• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

openmrs / openmrs-core / 30399801741

28 Jul 2026 09:13PM UTC coverage: 64.333% (+0.2%) from 64.136%
30399801741

push

github

web-flow
Fix Mockito inline mocks on JDK 8 and 11 (#6403)

24619 of 38268 relevant lines covered (64.33%)

0.64 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

86.85
/api/src/main/java/org/openmrs/api/impl/UserServiceImpl.java
1
/**
2
 * This Source Code Form is subject to the terms of the Mozilla Public License,
3
 * v. 2.0. If a copy of the MPL was not distributed with this file, You can
4
 * obtain one at http://mozilla.org/MPL/2.0/. OpenMRS is also distributed under
5
 * the terms of the Healthcare Disclaimer located at http://openmrs.org/license.
6
 *
7
 * Copyright (C) OpenMRS Inc. OpenMRS is a registered trademark and the OpenMRS
8
 * graphic logo is a trademark of OpenMRS Inc.
9
 */
10
package org.openmrs.api.impl;
11

12
import java.util.ArrayList;
13
import java.util.Collection;
14
import java.util.Date;
15
import java.util.HashSet;
16
import java.util.List;
17
import java.util.Locale;
18
import java.util.Map;
19
import java.util.Objects;
20
import java.util.Optional;
21
import java.util.Properties;
22
import java.util.Set;
23
import java.util.stream.Collectors;
24

25
import org.apache.commons.lang.RandomStringUtils;
26
import org.apache.commons.lang3.StringUtils;
27
import org.openmrs.Person;
28
import org.openmrs.Privilege;
29
import org.openmrs.Role;
30
import org.openmrs.User;
31
import org.openmrs.annotation.Authorized;
32
import org.openmrs.annotation.Logging;
33
import org.openmrs.api.APIException;
34
import org.openmrs.api.AdministrationService;
35
import org.openmrs.api.CannotDeleteRoleWithChildrenException;
36
import org.openmrs.api.InvalidActivationKeyException;
37
import org.openmrs.api.UserService;
38
import org.openmrs.api.context.Context;
39
import org.openmrs.api.db.DAOException;
40
import org.openmrs.api.db.LoginCredential;
41
import org.openmrs.api.db.UserDAO;
42
import org.openmrs.messagesource.MessageSourceService;
43
import org.openmrs.notification.MessageException;
44
import org.openmrs.patient.impl.LuhnIdentifierValidator;
45
import org.openmrs.util.LocaleUtility;
46
import org.openmrs.util.OpenmrsConstants;
47
import org.openmrs.util.OpenmrsUtil;
48
import org.openmrs.util.PrivilegeConstants;
49
import org.openmrs.util.RoleConstants;
50
import org.openmrs.util.Security;
51
import org.slf4j.Logger;
52
import org.slf4j.LoggerFactory;
53
import org.springframework.cache.annotation.CacheEvict;
54
import org.springframework.transaction.annotation.Transactional;
55

56
/**
57
 * Default implementation of the user service. This class should not be used on its own. The current
58
 * OpenMRS implementation should be fetched from the Context
59
 *
60
 * @see org.openmrs.api.UserService
61
 * @see org.openmrs.api.context.Context
62
 */
63
@Transactional
64
public class UserServiceImpl extends BaseOpenmrsService implements UserService {
65
        
66
        private static final Logger log = LoggerFactory.getLogger(UserServiceImpl.class);
1✔
67
        
68
        protected UserDAO dao;
69
        
70
        private static final int MAX_VALID_TIME = 12 * 60 * 60 * 1000; //Period of 12 hours
71
        
72
        private static final int MIN_VALID_TIME = 60 * 1000; //Period of 1 minute
73
        
74
        private static final int DEFAULT_VALID_TIME = 10 * 60 * 1000; //Default time of 10 minute
75
        
76
        public UserServiceImpl() {
1✔
77
        }
1✔
78
        
79
        public void setUserDAO(UserDAO dao) {
80
                this.dao = dao;
1✔
81
        }
1✔
82
        
83
        /**
84
         * @return the validTime for which the password reset activation key will be valid
85
         */
86
        private int getValidTime() {
87
                String validTimeGp = Context.getAdministrationService()
1✔
88
                        .getGlobalProperty(OpenmrsConstants.GP_PASSWORD_RESET_VALIDTIME);
1✔
89
                final int validTime = StringUtils.isBlank(validTimeGp) ? DEFAULT_VALID_TIME : Integer.parseInt(validTimeGp);
1✔
90
                //if valid time is less that a minute or greater than 12hrs reset valid time to 1 minutes else set it to the required time.
91
                return (validTime < MIN_VALID_TIME) || (validTime > MAX_VALID_TIME) ? DEFAULT_VALID_TIME : validTime;
1✔
92
        }
93
        
94
        /**
95
         * @see org.openmrs.api.UserService#createUser(org.openmrs.User, java.lang.String)
96
         */
97
        @Override
98
        public User createUser(User user, String password) throws APIException {
99
                if (user.getUserId() != null) {
1✔
100
                        throw new APIException("This method can be used for only creating new users");
1✔
101
                }
102
                
103
                Context.requirePrivilege(PrivilegeConstants.ADD_USERS);
1✔
104
                
105
                checkPrivileges(user);
1✔
106
                
107
                // if a password wasn't supplied, throw an error
108
                if (password == null || password.isEmpty()) {
1✔
109
                        throw new APIException("User.creating.password.required", (Object[]) null);
×
110
                }
111
                
112
                if (hasDuplicateUsername(user)) {
1✔
113
                        throw new DAOException("Username " + user.getUsername() + " or system id " + user.getSystemId()
1✔
114
                                + " is already in use.");
115
                }
116
                
117
                // TODO Check required fields for user!!
118
                OpenmrsUtil.validatePassword(user.getUsername(), password, user.getSystemId());
1✔
119
                
120
                return dao.saveUser(user, password);
1✔
121
        }
122
        
123
        /**
124
         * @see org.openmrs.api.UserService#getUser(java.lang.Integer)
125
         */
126
        @Override
127
        @Transactional(readOnly = true)
128
        public User getUser(Integer userId) throws APIException {
129
                return dao.getUser(userId);
1✔
130
        }
131
        
132
        /**
133
         * @see org.openmrs.api.UserService#getUserByUsername(java.lang.String)
134
         */
135
        @Override
136
        @Transactional(readOnly = true)
137
        public User getUserByUsername(String username) throws APIException {
138
                return dao.getUserByUsername(username);
1✔
139
        }
140
        
141
        /**
142
         * @see org.openmrs.api.UserService#hasDuplicateUsername(org.openmrs.User)
143
         */
144
        @Override
145
        @Transactional(readOnly = true)
146
        public boolean hasDuplicateUsername(User user) throws APIException {
147
                return dao.hasDuplicateUsername(user.getUsername(), user.getSystemId(), user.getUserId());
1✔
148
        }
149
        
150
        /**
151
         * @see org.openmrs.api.UserService#getUsersByRole(org.openmrs.Role)
152
         */
153
        @Override
154
        @Transactional(readOnly = true)
155
        public List<User> getUsersByRole(Role role) throws APIException {
156
                List<Role> roles = new ArrayList<>();
1✔
157
                roles.add(role);
1✔
158
                
159
                return Context.getUserService().getUsers(null, roles, false);
1✔
160
        }
161
        
162
        /**
163
         * @see org.openmrs.api.UserService#saveUser(org.openmrs.User)
164
         */
165
        @Override
166
        @CacheEvict(value = "userSearchLocales", allEntries = true)
167
        public User saveUser(User user) throws APIException {
168
                if (user.getUserId() == null) {
1✔
169
                        throw new APIException("This method can be called only to update existing users");
×
170
                }
171
                
172
                Context.requirePrivilege(PrivilegeConstants.EDIT_USERS);
1✔
173
                
174
                checkPrivileges(user);
1✔
175
                
176
                if (hasDuplicateUsername(user)) {
1✔
177
                        throw new DAOException("Username " + user.getUsername() + " or system id " + user.getSystemId()
×
178
                                + " is already in use.");
179
                }
180
                
181
                return dao.saveUser(user, null);
1✔
182
        }
183
        
184
        public User voidUser(User user, String reason) throws APIException {
185
                return Context.getUserService().retireUser(user, reason);
×
186
        }
187
        
188
        /**
189
         * @see org.openmrs.api.UserService#retireUser(org.openmrs.User, java.lang.String)
190
         */
191
        @Override
192
        public User retireUser(User user, String reason) throws APIException {
193
                user.setRetired(true);
1✔
194
                user.setRetireReason(reason);
1✔
195
                user.setRetiredBy(Context.getAuthenticatedUser());
1✔
196
                user.setDateRetired(new Date());
1✔
197
                
198
                return saveUser(user);
1✔
199
        }
200
        
201
        public User unvoidUser(User user) throws APIException {
202
                return Context.getUserService().unretireUser(user);
×
203
        }
204
        
205
        /**
206
         * @see org.openmrs.api.UserService#unretireUser(org.openmrs.User)
207
         */
208
        @Override
209
        public User unretireUser(User user) throws APIException {
210
                user.setRetired(false);
1✔
211
                user.setRetireReason(null);
1✔
212
                user.setRetiredBy(null);
1✔
213
                user.setDateRetired(null);
1✔
214
                
215
                return saveUser(user);
1✔
216
        }
217
        
218
        /**
219
         * @see org.openmrs.api.UserService#getAllUsers()
220
         */
221
        @Override
222
        @Transactional(readOnly = true)
223
        public List<User> getAllUsers() throws APIException {
224
                return dao.getAllUsers();
1✔
225
        }
226
        
227
        /**
228
         * @see org.openmrs.api.UserService#getAllPrivileges()
229
         */
230
        @Override
231
        @Transactional(readOnly = true)
232
        public List<Privilege> getAllPrivileges() throws APIException {
233
                return dao.getAllPrivileges();
1✔
234
        }
235
        
236
        /**
237
         * @see org.openmrs.api.UserService#getPrivilege(java.lang.String)
238
         */
239
        @Override
240
        @Transactional(readOnly = true)
241
        public Privilege getPrivilege(String p) throws APIException {
242
                return dao.getPrivilege(p);
1✔
243
        }
244
        
245
        /**
246
         * @see org.openmrs.api.UserService#purgePrivilege(org.openmrs.Privilege)
247
         */
248
        @Override
249
        @CacheEvict(value = "rolePrivileges", allEntries = true)
250
        public void purgePrivilege(Privilege privilege) throws APIException {
251
                if (OpenmrsUtil.getCorePrivileges().keySet().contains(privilege.getPrivilege())) {
1✔
252
                        throw new APIException("Privilege.cannot.delete.core", (Object[]) null);
1✔
253
                }
254
                
255
                dao.deletePrivilege(privilege);
1✔
256
        }
1✔
257
        
258
        /**
259
         * @see org.openmrs.api.UserService#savePrivilege(org.openmrs.Privilege)
260
         */
261
        @Override
262
        @CacheEvict(value = "rolePrivileges", allEntries = true)
263
        public Privilege savePrivilege(Privilege privilege) throws APIException {
264
                return dao.savePrivilege(privilege);
1✔
265
        }
266
        
267
        /**
268
         * @see org.openmrs.api.UserService#getAllRoles()
269
         */
270
        @Override
271
        @Transactional(readOnly = true)
272
        public List<Role> getAllRoles() throws APIException {
273
                return dao.getAllRoles();
1✔
274
        }
275
        
276
        /**
277
         * @see org.openmrs.api.UserService#getRole(java.lang.String)
278
         */
279
        @Override
280
        @Transactional(readOnly = true)
281
        public Role getRole(String r) throws APIException {
282
                return dao.getRole(r);
1✔
283
        }
284
        
285
        /**
286
         * @see org.openmrs.api.UserService#purgeRole(org.openmrs.Role)
287
         */
288
        @Override
289
        @CacheEvict(value = "rolePrivileges", allEntries = true)
290
        public void purgeRole(Role role) throws APIException {
291
                if (role == null || role.getRole() == null) {
1✔
292
                        return;
1✔
293
                }
294
                
295
                if (OpenmrsUtil.getCoreRoles().keySet().contains(role.getRole())) {
1✔
296
                        throw new APIException("Role.cannot.delete.core", (Object[]) null);
1✔
297
                }
298
                
299
                if (role.hasChildRoles()) {
1✔
300
                        throw new CannotDeleteRoleWithChildrenException();
1✔
301
                }
302
                
303
                dao.deleteRole(role);
1✔
304
        }
1✔
305
        
306
        /**
307
         * @see org.openmrs.api.UserService#saveRole(org.openmrs.Role)
308
         */
309
        @Override
310
        @CacheEvict(value = "rolePrivileges", allEntries = true)
311
        public Role saveRole(Role role) throws APIException {
312
                // make sure one of the parents of this role isn't itself...this would
313
                // cause an infinite loop
314
                if (role.getAllParentRoles().contains(role)) {
1✔
315
                        throw new APIException("Role.cannot.inherit.descendant", (Object[]) null);
1✔
316
                }
317
                
318
                checkPrivileges(role);
1✔
319
                
320
                return dao.saveRole(role);
1✔
321
        }
322
        
323
        /**
324
         * @see org.openmrs.api.UserService#changePassword(java.lang.String, java.lang.String)
325
         */
326
        @Override
327
        public void changePassword(String oldPassword, String newPassword) throws APIException {
328
                User user = Context.getAuthenticatedUser();
1✔
329
                changePassword(user, oldPassword, newPassword);
1✔
330
        }
1✔
331
        
332
        /**
333
         * @see org.openmrs.api.UserService#changeHashedPassword(User, String, String)
334
         */
335
        @Override
336
        public void changeHashedPassword(User user, String hashedPassword, String salt) throws APIException {
337
                dao.changeHashedPassword(user, hashedPassword, salt);
1✔
338
        }
1✔
339
        
340
        /**
341
         * @see org.openmrs.api.UserService#changeQuestionAnswer(User, String, String)
342
         */
343
        @Override
344
        public void changeQuestionAnswer(User u, String question, String answer) throws APIException {
345
                dao.changeQuestionAnswer(u, question, answer);
1✔
346
        }
1✔
347
        
348
        /**
349
         * @see org.openmrs.api.UserService#changeQuestionAnswer(java.lang.String, java.lang.String,
350
         * java.lang.String)
351
         */
352
        @Override
353
        public void changeQuestionAnswer(String pw, String q, String a) {
354
                dao.changeQuestionAnswer(pw, q, a);
1✔
355
        }
1✔
356
        
357
        /**
358
         * @see org.openmrs.api.UserService#isSecretAnswer(org.openmrs.User, java.lang.String)
359
         */
360
        @Override
361
        @Transactional(readOnly = true)
362
        public boolean isSecretAnswer(User u, String answer) {
363
                return dao.isSecretAnswer(u, answer);
1✔
364
        }
365
        
366
        /**
367
         * @see org.openmrs.api.UserService#getUsersByName(java.lang.String, java.lang.String, boolean)
368
         */
369
        @Override
370
        @Transactional(readOnly = true)
371
        public List<User> getUsersByName(String givenName, String familyName, boolean includeVoided) throws APIException {
372
                return dao.getUsersByName(givenName, familyName, includeVoided);
1✔
373
        }
374
        
375
        /**
376
         * @see org.openmrs.api.UserService#getUsersByPerson(org.openmrs.Person, boolean)
377
         */
378
        @Override
379
        @Transactional(readOnly = true)
380
        public List<User> getUsersByPerson(Person person, boolean includeRetired) throws APIException {
381
                return dao.getUsersByPerson(person, includeRetired);
1✔
382
        }
383
        
384
        /**
385
         * @see org.openmrs.api.UserService#getUsers(java.lang.String, java.util.List, boolean)
386
         */
387
        @Override
388
        @Transactional(readOnly = true)
389
        public List<User> getUsers(String nameSearch, List<Role> roles, boolean includeVoided) throws APIException {
390
                return Context.getUserService().getUsers(nameSearch, roles, includeVoided, null, null);
1✔
391
        }
392
        
393
        /**
394
         * Convenience method to check if the authenticated user has all privileges they are giving out
395
         *
396
         * @param user user that has privileges
397
         */
398
        private void checkPrivileges(User user) {
399
                List<String> requiredPrivs = user.getAllRoles().stream().peek(this::checkSuperUserPrivilege)
1✔
400
                        .map(Role::getPrivileges).filter(Objects::nonNull).flatMap(Collection::stream)
1✔
401
                        .map(Privilege::getPrivilege).filter(p -> !Context.hasPrivilege(p)).sorted().collect(Collectors.toList());
1✔
402
                if (requiredPrivs.size() == 1) {
1✔
403
                        throw new APIException("User.you.must.have.privilege", new Object[] { requiredPrivs.get(0) });
1✔
404
                } else if (requiredPrivs.size() > 1) {
1✔
405
                        throw new APIException("User.you.must.have.privileges", new Object[] { String.join(", ", requiredPrivs) });
1✔
406
                }
407
        }
1✔
408
        
409
        private void checkSuperUserPrivilege(Role r) {
410
                if (r.getRole().equals(RoleConstants.SUPERUSER)
1✔
411
                        && !Context.hasPrivilege(PrivilegeConstants.ASSIGN_SYSTEM_DEVELOPER_ROLE)) {
1✔
412
                        throw new APIException("User.you.must.have.role", new Object[] { RoleConstants.SUPERUSER });
1✔
413
                }
414
        }
1✔
415
        
416
        /**
417
         * @see org.openmrs.api.UserService#setUserProperty(User, String, String)
418
         */
419
        @Override
420
        public User setUserProperty(User user, String key, String value) {
421
                if (user != null) {
1✔
422
                        if (!Context.hasPrivilege(PrivilegeConstants.EDIT_USERS) && !user.equals(Context.getAuthenticatedUser())) {
1✔
423
                                throw new APIException("you.are.not.authorized.change.properties", new Object[] { user.getUserId() });
×
424
                        }
425
                        
426
                        user.setUserProperty(key, value);
1✔
427
                        try {
428
                                Context.addProxyPrivilege(PrivilegeConstants.EDIT_USERS);
1✔
429
                                Context.getUserService().saveUser(user);
1✔
430
                        }
431
                        finally {
432
                                Context.removeProxyPrivilege(PrivilegeConstants.EDIT_USERS);
1✔
433
                        }
434
                }
435
                
436
                return user;
1✔
437
        }
438
        
439
        /**
440
         * @see org.openmrs.api.UserService#removeUserProperty(org.openmrs.User, java.lang.String)
441
         */
442
        @Override
443
        public User removeUserProperty(User user, String key) {
444
                if (user != null) {
1✔
445
                        
446
                        // if the current user isn't allowed to edit users and
447
                        // the user being edited is not the current user, throw an
448
                        // exception
449
                        if (!Context.hasPrivilege(PrivilegeConstants.EDIT_USERS) && !user.equals(Context.getAuthenticatedUser())) {
1✔
450
                                throw new APIException("you.are.not.authorized.change.properties", new Object[] { user.getUserId() });
×
451
                        }
452
                        
453
                        user.removeUserProperty(key);
1✔
454
                        
455
                        try {
456
                                Context.addProxyPrivilege(PrivilegeConstants.EDIT_USERS);
1✔
457
                                Context.getUserService().saveUser(user);
1✔
458
                        }
459
                        finally {
460
                                Context.removeProxyPrivilege(PrivilegeConstants.EDIT_USERS);
1✔
461
                        }
462
                }
463
                
464
                return user;
1✔
465
        }
466
        
467
        /**
468
         * Generates system ids based on the following algorithm scheme: user_id-check digit
469
         *
470
         * @see org.openmrs.api.UserService#generateSystemId()
471
         */
472
        @Override
473
        @Transactional(readOnly = true)
474
        public String generateSystemId() {
475
                // Hardcoding Luhn algorithm since all existing openmrs user ids have
476
                // had check digits generated this way.
477
                LuhnIdentifierValidator liv = new LuhnIdentifierValidator();
1✔
478
                
479
                String systemId;
480
                Integer offset = 0;
1✔
481
                do {
482
                        // generate and increment the system id if necessary
483
                        Integer generatedId = dao.generateSystemId() + offset++;
1✔
484
                        
485
                        systemId = generatedId.toString();
1✔
486
                        
487
                        try {
488
                                systemId = liv.getValidIdentifier(systemId);
1✔
489
                        }
490
                        catch (Exception e) {
×
491
                                log.error("error getting check digit", e);
×
492
                                return systemId;
×
493
                        }
1✔
494
                        
495
                        // loop until we find a system id that no one has 
496
                } while (dao.hasDuplicateUsername(null, systemId, null));
1✔
497
                
498
                return systemId;
1✔
499
        }
500
        
501
        /**
502
         * @see org.openmrs.api.UserService#purgeUser(org.openmrs.User)
503
         */
504
        @Override
505
        public void purgeUser(User user) throws APIException {
506
                dao.deleteUser(user);
1✔
507
        }
1✔
508
        
509
        /**
510
         * @see org.openmrs.api.UserService#purgeUser(org.openmrs.User, boolean)
511
         */
512
        @Override
513
        public void purgeUser(User user, boolean cascade) throws APIException {
514
                if (cascade) {
1✔
515
                        throw new APIException("cascade.do.not.think", (Object[]) null);
1✔
516
                }
517
                
518
                dao.deleteUser(user);
1✔
519
        }
1✔
520
        
521
        /**
522
         * Convenience method to check if the authenticated user has all privileges they are giving out
523
         * to the new role
524
         *
525
         * @param role
526
         */
527
        private void checkPrivileges(Role role) {
528
                Optional.ofNullable(role.getPrivileges())
1✔
529
                        .map(p -> p.stream().filter(pr -> !Context.hasPrivilege(pr.getPrivilege())).map(Privilege::getPrivilege)
1✔
530
                                .distinct().collect(Collectors.joining(", ")))
1✔
531
                        .ifPresent(missing -> {
1✔
532
                                if (StringUtils.isNotBlank(missing)) {
1✔
533
                                        throw new APIException("Role.you.must.have.privileges", new Object[] { missing });
1✔
534
                                }
535
                        });
1✔
536
        }
1✔
537
        
538
        /**
539
         * @see org.openmrs.api.UserService#getPrivilegeByUuid(java.lang.String)
540
         */
541
        @Override
542
        @Transactional(readOnly = true)
543
        public Privilege getPrivilegeByUuid(String uuid) throws APIException {
544
                return dao.getPrivilegeByUuid(uuid);
1✔
545
        }
546
        
547
        /**
548
         * @see org.openmrs.api.UserService#getRoleByUuid(java.lang.String)
549
         */
550
        @Override
551
        @Transactional(readOnly = true)
552
        public Role getRoleByUuid(String uuid) throws APIException {
553
                return dao.getRoleByUuid(uuid);
1✔
554
        }
555
        
556
        /**
557
         * @see org.openmrs.api.UserService#getUserByUuid(java.lang.String)
558
         */
559
        @Override
560
        @Transactional(readOnly = true)
561
        public User getUserByUuid(String uuid) throws APIException {
562
                return dao.getUserByUuid(uuid);
1✔
563
        }
564
        
565
        /**
566
         * @see UserService#getCountOfUsers(String, List, boolean)
567
         */
568
        @Override
569
        @Transactional(readOnly = true)
570
        public Integer getCountOfUsers(String name, List<Role> roles, boolean includeRetired) {
571
                if (name != null) {
×
572
                        name = StringUtils.replace(name, ", ", " ");
×
573
                }
574
                
575
                // if the authenticated role is in the list of searched roles, then all
576
                // persons should be searched
577
                Role authRole = getRole(RoleConstants.AUTHENTICATED);
×
578
                if (roles.contains(authRole)) {
×
579
                        return dao.getCountOfUsers(name, new ArrayList<>(), includeRetired);
×
580
                }
581
                
582
                return dao.getCountOfUsers(name, roles, includeRetired);
×
583
        }
584
        
585
        /**
586
         * @see UserService#getUsers(String, List, boolean, Integer, Integer)
587
         */
588
        @Override
589
        @Transactional(readOnly = true)
590
        public List<User> getUsers(String name, List<Role> roles, boolean includeRetired, Integer start, Integer length)
591
                throws APIException {
592
                if (name != null) {
1✔
593
                        name = StringUtils.replace(name, ", ", " ");
1✔
594
                }
595
                
596
                if (roles == null) {
1✔
597
                        roles = new ArrayList<>();
1✔
598
                }
599
                
600
                // if the authenticated role is in the list of searched roles, then all
601
                // persons should be searched
602
                Role authRole = getRole(RoleConstants.AUTHENTICATED);
1✔
603
                if (roles.contains(authRole)) {
1✔
604
                        return dao.getUsers(name, new ArrayList<>(), includeRetired, start, length);
×
605
                }
606
                
607
                // add the requested roles and all child roles for consideration
608
                Set<Role> allRoles = new HashSet<>();
1✔
609
                for (Role r : roles) {
1✔
610
                        allRoles.add(r);
1✔
611
                        allRoles.addAll(r.getAllChildRoles());
1✔
612
                }
1✔
613
                
614
                return dao.getUsers(name, new ArrayList<>(allRoles), includeRetired, start, length);
1✔
615
        }
616
        
617
        @Override
618
        public User saveUserProperty(String key, String value) {
619
                User user = Context.getAuthenticatedUser();
1✔
620
                if (user == null) {
1✔
621
                        throw new APIException("no.authenticated.user.found", (Object[]) null);
×
622
                }
623
                user.setUserProperty(key, value);
1✔
624
                return dao.saveUser(user, null);
1✔
625
        }
626
        
627
        @Override
628
        public User saveUserProperties(Map<String, String> properties) {
629
                User user = Context.getAuthenticatedUser();
1✔
630
                if (user == null) {
1✔
631
                        throw new APIException("no.authenticated.user.found", (Object[]) null);
×
632
                }
633
                user.getUserProperties().clear();
1✔
634
                for (Map.Entry<String, String> entry : properties.entrySet()) {
1✔
635
                        user.setUserProperty(entry.getKey(), entry.getValue());
1✔
636
                }
1✔
637
                return dao.saveUser(user, null);
1✔
638
        }
639
        
640
        /**
641
         * @see UserService#changePassword(User, String, String)
642
         */
643
        @Override
644
        @Authorized(PrivilegeConstants.EDIT_USER_PASSWORDS)
645
        @Logging(ignoredArgumentIndexes = { 1, 2 })
646
        public void changePassword(User user, String oldPassword, String newPassword) throws APIException {
647
                if (user.getUserId() == null) {
1✔
648
                        throw new APIException("user.must.exist", (Object[]) null);
1✔
649
                }
650
                
651
                if (oldPassword == null) {
1✔
652
                        if (!Context.hasPrivilege(PrivilegeConstants.EDIT_USER_PASSWORDS)) {
1✔
653
                                throw new APIException("null.old.password.privilege.required", (Object[]) null);
×
654
                        }
655
                } else if (!dao.getLoginCredential(user).checkPassword(oldPassword)) {
1✔
656
                        throw new APIException("old.password.not.correct", (Object[]) null);
×
657
                        
658
                } else if (oldPassword.equals(newPassword)) {
1✔
659
                        throw new APIException("new.password.equal.to.old", (Object[]) null);
×
660
                }
661
                
662
                if (("admin".equals(user.getSystemId()) || "admin".equals(user.getUsername())) && Boolean.parseBoolean(
1✔
663
                        Context.getRuntimeProperties().getProperty(ADMIN_PASSWORD_LOCKED_PROPERTY, "false"))) {
1✔
664
                        throw new APIException("admin.password.is.locked");
1✔
665
                }
666
                
667
                updatePassword(user, newPassword);
1✔
668
        }
1✔
669
        
670
        @Override
671
        @Logging(ignoredArgumentIndexes = { 1 })
672
        public void changePassword(User user, String newPassword) {
673
                Context.getUserService().changePassword(user, null, newPassword);
×
674
        }
×
675
        
676
        @Override
677
        @Logging(ignoredArgumentIndexes = { 1, 2 })
678
        public void changePasswordUsingSecretAnswer(String secretAnswer, String pw) throws APIException {
679
                User user = Context.getAuthenticatedUser();
1✔
680
                
681
                if (!isSecretAnswer(user, secretAnswer)) {
1✔
682
                        throw new APIException("secret.answer.not.correct", (Object[]) null);
1✔
683
                }
684
                
685
                updatePassword(user, pw);
1✔
686
        }
1✔
687

688
        private void updatePassword(User user, String newPassword) {
689
                OpenmrsUtil.validatePassword(user.getUsername(), newPassword, user.getSystemId());
1✔
690
                dao.changePassword(user, newPassword);
1✔
691
        }
1✔
692
        
693
        @Override
694
        public String getSecretQuestion(User user) throws APIException {
695
                if (user.getUserId() != null) {
×
696
                        LoginCredential loginCredential = dao.getLoginCredential(user);
×
697
                        return loginCredential.getSecretQuestion();
×
698
                } else {
699
                        return null;
×
700
                }
701
        }
702
        
703
        /**
704
         * @see org.openmrs.api.UserService#getUserByUsernameOrEmail(java.lang.String)
705
         */
706
        @Override
707
        @Transactional(readOnly = true)
708
        public User getUserByUsernameOrEmail(String usernameOrEmail) {
709
                if (StringUtils.isNotBlank(usernameOrEmail)) {
1✔
710
                        User user = dao.getUserByEmail(usernameOrEmail);
1✔
711
                        if (user == null) {
1✔
712
                                return getUserByUsername(usernameOrEmail);
1✔
713
                        }
714
                        return user;
1✔
715
                }
716
                throw new APIException("error.usernameOrEmail.notNullOrBlank", (Object[]) null);
1✔
717
        }
718
        
719
        /**
720
         * @see org.openmrs.api.UserService#getUserByActivationKey(java.lang.String)
721
         */
722
        @Override
723
        @Transactional(readOnly = true)
724
        public User getUserByActivationKey(String activationKey) {
725
                LoginCredential loginCred = dao.getLoginCredentialByActivationKey(activationKey);
1✔
726
                if (loginCred != null) {
1✔
727
                        String[] credTokens = loginCred.getActivationKey().split(":");
1✔
728
                        if (System.currentTimeMillis() <= Long.parseLong(credTokens[1])) {
1✔
729
                                return getUser(loginCred.getUserId());
1✔
730
                        }
731
                }
732
                return null;
1✔
733
        }
734
        
735
        /**
736
         * @throws APIException
737
         * @throws MessageException
738
         * @see org.openmrs.api.UserService#setUserActivationKey(org.openmrs.User)
739
         */
740
        @Override
741
        public User setUserActivationKey(User user) throws MessageException {
742
                String token = RandomStringUtils.randomAlphanumeric(20);
1✔
743
                long time = System.currentTimeMillis() + getValidTime();
1✔
744
                String hashedKey = Security.encodeString(token);
1✔
745
                String activationKey = hashedKey + ":" + time;
1✔
746
                LoginCredential credentials = dao.getLoginCredential(user);
1✔
747
                credentials.setActivationKey(activationKey);
1✔
748
                dao.setUserActivationKey(credentials);
1✔
749
                
750
                MessageSourceService messages = Context.getMessageSourceService();
1✔
751
                AdministrationService adminService = Context.getAdministrationService();
1✔
752
                Locale locale = getDefaultLocaleForUser(user);
1✔
753
                
754
                //                Delete this method call when removing {@link OpenmrsConstants#GP_HOST_URL}
755
                copyHostURLGlobalPropertyToPasswordResetGlobalProperty(adminService);
1✔
756
                
757
                String link = adminService.getGlobalProperty(OpenmrsConstants.GP_PASSWORD_RESET_URL)
1✔
758
                        .replace("{activationKey}", token);
1✔
759
                
760
                Properties mailProperties = Context.getMailProperties();
1✔
761
                
762
                String sender = mailProperties.getProperty("mail.from");
1✔
763
                
764
                String subject = messages.getMessage("mail.passwordreset.subject", null, locale);
1✔
765
                
766
                String msg = messages.getMessage("mail.passwordreset.content", null, locale)
1✔
767
                        .replace("{name}", user.getUsername())
1✔
768
                        .replace("{link}", link)
1✔
769
                        .replace("{time}", String.valueOf(getValidTime() / 60000));
1✔
770
                
771
                Context.getMessageService().sendMessage(user.getEmail(), sender, subject, msg);
×
772
                
773
                return user;
×
774
        }
775
        
776
        /**
777
         * Delete this method when deleting {@link OpenmrsConstants#GP_HOST_URL}
778
         */
779
        private void copyHostURLGlobalPropertyToPasswordResetGlobalProperty(AdministrationService adminService) {
780
                String hostURLGP = adminService.getGlobalProperty(OpenmrsConstants.GP_HOST_URL);
1✔
781
                String passwordResetGP = adminService.getGlobalProperty(OpenmrsConstants.GP_PASSWORD_RESET_URL);
1✔
782
                if (StringUtils.isNotBlank(hostURLGP) && StringUtils.isBlank(passwordResetGP)) {
1✔
783
                        adminService.setGlobalProperty(OpenmrsConstants.GP_PASSWORD_RESET_URL, hostURLGP);
×
784
                }
785
        }
1✔
786
        
787
        /**
788
         * @see UserService#getDefaultLocaleForUser(User)
789
         */
790
        @Override
791
        public Locale getDefaultLocaleForUser(User user) {
792
                Locale locale = null;
1✔
793
                if (user != null) {
1✔
794
                        try {
795
                                String preferredLocale = user.getUserProperty(OpenmrsConstants.USER_PROPERTY_DEFAULT_LOCALE);
1✔
796
                                if (StringUtils.isNotBlank(preferredLocale)) {
1✔
797
                                        locale = LocaleUtility.fromSpecification(preferredLocale);
1✔
798
                                }
799
                        }
800
                        catch (Exception e) {
×
801
                                log.warn("Unable to parse user locale into a Locale", e);
×
802
                        }
1✔
803
                }
804
                if (locale == null) {
1✔
805
                        locale = Context.getLocale();
1✔
806
                }
807
                return locale;
1✔
808
        }
809
        
810
        /**
811
         * @see org.openmrs.api.UserService#changePasswordUsingActivationKey(String, String);
812
         */
813
        @Override
814
        public void changePasswordUsingActivationKey(String activationKey, String newPassword) {
815
                User user = getUserByActivationKey(activationKey);
1✔
816
                if (user == null) {
1✔
817
                        throw new InvalidActivationKeyException("activation.key.not.correct");
1✔
818
                }
819
                
820
                updatePassword(user, newPassword);
1✔
821
        }
1✔
822

823
        /**
824
         * @see org.openmrs.api.UserService#getLastLoginTime(User)
825
         */
826
        public String getLastLoginTime(User user) {
827
                return dao.getLastLoginTime(user);
1✔
828
        }
829
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE TRIAL · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc