/**
* This Source Code Form is subject to the terms of the Mozilla Public License,
* v. 2.0. If a copy of the MPL was not distributed with this file, You can
* obtain one at http://mozilla.org/MPL/2.0/. OpenMRS is also distributed under
* the terms of the Healthcare Disclaimer located at http://openmrs.org/license.
*
* Copyright (C) OpenMRS Inc. OpenMRS is a registered trademark and the OpenMRS
* graphic logo is a trademark of OpenMRS Inc.
*/
package org.openmrs.module.webservices.rest.web.v1_0.resource.openmrs1_8;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import org.apache.commons.beanutils.PropertyUtils;
import org.apache.commons.lang.StringUtils;
import org.openmrs.Role;
import org.openmrs.User;
import org.openmrs.api.context.Context;
import org.openmrs.module.webservices.rest.SimpleObject;
import org.openmrs.module.webservices.rest.util.ReflectionUtil;
import org.openmrs.module.webservices.rest.web.RequestContext;
import org.openmrs.module.webservices.rest.web.RestConstants;
import org.openmrs.module.webservices.rest.web.RestUtil;
import org.openmrs.module.webservices.rest.web.annotation.PropertyGetter;
import org.openmrs.module.webservices.rest.web.annotation.RepHandler;
import org.openmrs.module.webservices.rest.web.annotation.Resource;
import org.openmrs.module.webservices.rest.web.representation.DefaultRepresentation;
import org.openmrs.module.webservices.rest.web.representation.FullRepresentation;
import org.openmrs.module.webservices.rest.web.representation.RefRepresentation;
import org.openmrs.module.webservices.rest.web.representation.Representation;
import org.openmrs.module.webservices.rest.web.resource.impl.DelegatingResourceDescription;
import org.openmrs.module.webservices.rest.web.resource.impl.MetadataDelegatingCrudResource;
import org.openmrs.module.webservices.rest.web.resource.impl.NeedsPaging;
import org.openmrs.module.webservices.rest.web.response.ConversionException;
import org.openmrs.module.webservices.rest.web.response.ResponseException;
import org.openmrs.module.webservices.rest.web.v1_0.wrapper.openmrs1_8.UserAndPassword1_8;
/**
* {@link Resource} for User, supporting standard CRUD operations
*/
@Resource(name = RestConstants.VERSION_1 + "/user", supportedClass = UserAndPassword1_8.class, supportedOpenmrsVersions = {
"1.8.*", "1.9.*", "1.10.*", "1.11.*", "1.12.*" })
public class UserResource1_8 extends MetadataDelegatingCrudResource<UserAndPassword1_8> {
/**
* The name of the parameter that can be used to restrict a search to roles.
*/
public static final String PARAMETER_ROLES = "roles";
public UserResource1_8() {
}
@RepHandler(RefRepresentation.class)
public SimpleObject asRef(UserAndPassword1_8 delegate) throws ConversionException {
DelegatingResourceDescription description = new DelegatingResourceDescription();
description.addProperty("uuid");
description.addProperty("display");
if (delegate.isRetired()) {
description.addProperty("retired");
}
description.addSelfLink();
return convertDelegateToRepresentation(delegate, description);
}
/**
* @see org.openmrs.module.webservices.rest.web.resource.impl.DelegatingCrudResource#getRepresentationDescription(org.openmrs.module.webservices.rest.web.representation.Representation)
*/
@Override
public DelegatingResourceDescription getRepresentationDescription(Representation rep) {
if (rep instanceof DefaultRepresentation) {
DelegatingResourceDescription description = new DelegatingResourceDescription();
description.addProperty("uuid");
description.addProperty("display");
description.addProperty("username");
description.addProperty("systemId");
description.addProperty("userProperties");
description.addProperty("person", Representation.REF);
description.addProperty("privileges", Representation.REF);
description.addProperty("roles", Representation.REF);
description.addProperty("retired");
description.addSelfLink();
description.addLink("full", ".?v=" + RestConstants.REPRESENTATION_FULL);
return description;
} else if (rep instanceof FullRepresentation) {
DelegatingResourceDescription description = new DelegatingResourceDescription();
description.addProperty("uuid");
description.addProperty("display");
description.addProperty("username");
description.addProperty("systemId");
description.addProperty("userProperties");
description.addProperty("person", Representation.DEFAULT);
description.addProperty("privileges", Representation.DEFAULT);
description.addProperty("roles", Representation.DEFAULT);
description.addProperty("allRoles", Representation.DEFAULT);
description.addProperty("proficientLocales");
description.addProperty("secretQuestion");
description.addProperty("retired");
description.addProperty("auditInfo");
description.addSelfLink();
return description;
}
return null;
}
/**
* @see org.openmrs.module.webservices.rest.web.resource.impl.BaseDelegatingResource#getCreatableProperties()
*/
@Override
public DelegatingResourceDescription getCreatableProperties() {
DelegatingResourceDescription description = new DelegatingResourceDescription();
description.addRequiredProperty("username");
description.addRequiredProperty("password");
description.addRequiredProperty("person");
description.addProperty("systemId");
description.addProperty("userProperties");
description.addProperty("roles");
description.addProperty("proficientLocales");
description.addProperty("secretQuestion");
return description;
}
/**
* @see org.openmrs.module.webservices.rest.web.resource.impl.DelegatingCrudResource#newDelegate()
*/
@Override
public UserAndPassword1_8 newDelegate() {
return new UserAndPassword1_8();
}
/**
* @see org.openmrs.module.webservices.rest.web.resource.impl.DelegatingCrudResource#save(java.lang.Object)
*/
@Override
public UserAndPassword1_8 save(UserAndPassword1_8 user) {
User openmrsUser = new User();
String password = user.getPassword();
openmrsUser = Context.getUserService().saveUser(user.getUser(), password);
Context.refreshAuthenticatedUser();
if (openmrsUser.getId() != null && StringUtils.isNotBlank(password)) {
Context.getUserService().changePassword(openmrsUser, password);
}
return new UserAndPassword1_8(openmrsUser);
}
/**
* @see org.openmrs.module.webservices.rest.web.resource.impl.DelegatingCrudResource#getByUniqueId(java.lang.String)
*/
@Override
public UserAndPassword1_8 getByUniqueId(String uuid) {
return new UserAndPassword1_8(Context.getUserService().getUserByUuid(uuid));
}
/**
* @see org.openmrs.module.webservices.rest.web.resource.impl.DelegatingCrudResource#delete(java.lang.Object,
* java.lang.String, org.openmrs.module.webservices.rest.web.RequestContext)
*/
@Override
public void delete(UserAndPassword1_8 user, String reason, RequestContext context) throws ResponseException {
if (user.isRetired()) {
// DELETE is idempotent, so we return success here
return;
}
Context.getUserService().retireUser(Context.getUserService().getUser(user.getId()), reason);
}
/**
* @see org.openmrs.module.webservices.rest.web.resource.impl.DelegatingCrudResource#purge(java.lang.Object,
* org.openmrs.module.webservices.rest.web.RequestContext)
*/
@Override
public void purge(UserAndPassword1_8 user, RequestContext context) throws ResponseException {
if (user == null) {
// DELETE is idempotent, so we return success here
return;
}
Context.getUserService().purgeUser(user.getUser());
}
/**
* @param context A {@link RequestContext} that can contain two parameter values: 'q' for the
* user name and 'roles' for the role restriction. If a user name is given, users
* with a user name beginning with this string will be returned (prefix search). If
* no user name is given, the search will not be restricted to specific user names.
* The roles have to be given as a comma separated string. If multiple roles are
* given, the users having at least one of the roles will be returned. A role may be
* specified either by its UUID or by its display name. If no role parameter is
* given, the search will not be restricted to roles.
* @see org.openmrs.module.webservices.rest.web.resource.impl.DelegatingCrudResource#doSearch(org.openmrs.module.webservices.rest.web.RequestContext)
*/
@Override
protected NeedsPaging<UserAndPassword1_8> doSearch(RequestContext context) {
// determine roles
List<Role> foundRoles = null;
final String requestedRolesParameter = context.getParameter(PARAMETER_ROLES);
if (requestedRolesParameter != null) {
foundRoles = getRequestedRoles(requestedRolesParameter);
}
// forward query
final List<User> users;
if (isNoRequestedRoleFound(foundRoles)) {
// for an empty role list there shall be no results
users = Collections.emptyList();
} else {
// Note: a null value for roles is interpreted as 'no restriction to roles'
users = Context.getUserService().getUsers(context.getParameter("q"), foundRoles, context.getIncludeAll());
}
// convert to UserAndPassword class
final List<UserAndPassword1_8> usersResult = new ArrayList<UserAndPassword1_8>();
for (User user : users) {
usersResult.add(new UserAndPassword1_8(user));
}
return new NeedsPaging<UserAndPassword1_8>(usersResult, context);
}
private boolean isNoRequestedRoleFound(List<Role> roles) {
return roles != null && roles.isEmpty();
}
/**
* @param rolesParameter A comma separated list of role names or role UUIDs. May not be null.
* @return A non-null list of existing {@link Role}s that may be empty, if no valid roles are
* found.
*/
private List<Role> getRequestedRoles(final String rolesParameter) {
final List<Role> result = new ArrayList<Role>();
final List<String> roleStrings = Arrays.asList(StringUtils.split(rolesParameter, ","));
for (String roleString : roleStrings) {
// try with uuid
Role role = Context.getUserService().getRoleByUuid(roleString);
// try with display name
if (role == null) {
role = Context.getUserService().getRole(roleString);
}
// add if found
if (role != null) {
result.add(role);
}
}
return result;
}
/**
* Overrides BaseDelegatingResource getProperty method to get properties from User property of
* UserAndPassword instead of UserAndPassword itself
*
* @see org.openmrs.module.webservices.rest.web.resource.impl.BaseDelegatingResource#setProperty(T,
* java.lang.String, java.lang.Object)
* @param instance
* @param propertyName
* @throws ConversionException
*/
@Override
public Object getProperty(UserAndPassword1_8 instance, String propertyName) throws ConversionException {
try {
if (propertyName.equals("password")) {
return instance.getPassword();
} else {
// try to find a @PropertyGetter-annotated method
Method annotatedGetter = ReflectionUtil.findPropertyGetterMethod(this, propertyName);
if (annotatedGetter != null) {
return annotatedGetter.invoke(this, instance);
}
return PropertyUtils.getProperty(instance.getUser(), propertyName);
}
}
catch (Exception ex) {
throw new ConversionException(propertyName, ex);
}
}
/**
* Overrides BaseDelegatingResource setProperty method to allow properties to be set on User
* property of UserAndPassword instead of UserAndPassword itself
*
* @see org.openmrs.module.webservices.rest.web.resource.impl.BaseDelegatingResource#setProperty(T,
* java.lang.String, java.lang.Object)
* @param instance
* @param propertyName
* @param value
* @throws ConversionException
*/
@Override
public void setProperty(Object instance, String propertyName, Object value) throws ConversionException {
try {
UserAndPassword1_8 userAndPassword = (UserAndPassword1_8) instance;
if (propertyName.equals("password")) {
userAndPassword.setPassword(value != null ? value.toString() : null);
} else {
// just treat every other property like a we're on the User object
super.setProperty(userAndPassword.getUser(), propertyName, value);
}
}
catch (Exception ex) {
throw new ConversionException(propertyName, ex);
}
}
/**
* @param user
* @return roles for user
* @see User#getRoles()
*/
public Set<Role> getRoles(UserAndPassword1_8 user) {
if (user.getUser().getRoles() == null)
return null;
return RestUtil.removeRetiredData(user.getUser().getRoles());
}
/**
* @param user
* @return all roles for user
* @see User#getAllRoles()
*/
public Set<Role> getAllRoles(UserAndPassword1_8 user) {
if (user.getUser().getRoles() == null)
return null;
return RestUtil.removeRetiredData(user.getUser().getAllRoles()); //Get all active roles, including inherited roles
}
/**
* @param user
* @return username or systemId (for concise display purposes)
*/
@Override
@PropertyGetter("display")
public String getDisplayString(UserAndPassword1_8 user) {
StringBuilder ret = new StringBuilder();
User u = user.getUser();
ret.append(StringUtils.isNotEmpty(u.getUsername()) ? u.getUsername() : u.getSystemId());
return ret.toString();
}
/**
* Overridden here since the unique id is not on UserAndPassword directly
*
* @see org.openmrs.module.webservices.rest.web.resource.impl.BaseDelegatingResource#getUniqueId(java.lang.Object)
*/
@Override
protected String getUniqueId(UserAndPassword1_8 delegate) {
return delegate.getUser().getUuid();
}
/**
* Overridden here since the auditInfo is not on UserAndPassword directly, but on the User
*
* @see org.openmrs.module.webservices.rest.web.resource.impl.MetadataDelegatingCrudResource#getAuditInfo(java.lang.Object)
*/
@PropertyGetter("auditInfo")
public SimpleObject getAuditInfo(UserAndPassword1_8 delegate) throws Exception {
SimpleObject ret = super.getAuditInfo(delegate.getUser());
return ret;
}
/**
* @see org.openmrs.module.webservices.rest.web.resource.impl.DelegatingCrudResource#doGetAll(org.openmrs.module.webservices.rest.web.RequestContext)
*/
@Override
protected NeedsPaging<UserAndPassword1_8> doGetAll(RequestContext context) {
List<UserAndPassword1_8> users = new ArrayList<UserAndPassword1_8>();
for (User user : Context.getUserService().getAllUsers()) {
users.add(new UserAndPassword1_8(user));
}
return new NeedsPaging<UserAndPassword1_8>(users, context);
}
}