package org.gcube.gcat.persistence.ckan; import java.util.HashMap; import java.util.List; import java.util.Map; import javax.ws.rs.InternalServerErrorException; import javax.ws.rs.WebApplicationException; import javax.ws.rs.core.Response.Status; import org.gcube.gcat.social.PortalUser; import org.gcube.gcat.utils.ContextUtility; import org.gcube.gcat.utils.RandomString; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.fasterxml.jackson.databind.node.ObjectNode; /** * @author Luca Frosini (ISTI - CNR) */ public class CKANUser extends CKAN { private static final Logger logger = LoggerFactory.getLogger(CKANUser.class); /* User Paths */ // see https://docs.ckan.org/en/latest/api/#ckan.logic.action.get.user_list public static final String USER_LIST = CKAN.CKAN_API_PATH + "user_list"; // see http://docs.ckan.org/en/latest/api/#ckan.logic.action.create.user_create public static final String USER_CREATE = CKAN.CKAN_API_PATH + "user_create"; // see http://docs.ckan.org/en/latest/api/#ckan.logic.action.get.user_show public static final String USER_SHOW = CKAN.CKAN_API_PATH + "user_show"; // see http://docs.ckan.org/en/latest/api/#ckan.logic.action.update.user_update public static final String USER_UPDATE = CKAN.CKAN_API_PATH + "user_update"; // see http://docs.ckan.org/en/latest/api/#ckan.logic.action.delete.user_delete public static final String USER_DELETE = CKAN.CKAN_API_PATH + "user_delete"; public static final String ADD_USER_TO_GROUP = CKAN.CKAN_API_PATH + "member_create"; public static final String NAME = "name"; public static final String DISPLAY_NAME = "display_name"; public static final String FULL_NAME = "fullname"; public static final String ABOUT = "about"; public static final String EMAIL = "email"; public static final String PASSWORD = "password"; private static final String API_KEY = "apikey"; public enum Role { MEMBER("Catalogue-Member", "member"), EDITOR("Catalogue-Editor", "editor"), ADMIN("Catalogue-Admin", "admin"); private final String portalRole; private final String ckanRole; Role(String portalRole, String ckanRole) { this.portalRole = portalRole; this.ckanRole = ckanRole; } public String getPortalRole() { return portalRole; } public String getCkanRole() { return ckanRole; } protected static final Map ROLE_BY_PORTAL_ROLE; protected static final Map ROLE_BY_CKAN_ROLE; static { ROLE_BY_PORTAL_ROLE = new HashMap(); // null or empty string identify a member ROLE_BY_PORTAL_ROLE.put(null, MEMBER); ROLE_BY_PORTAL_ROLE.put("", MEMBER); ROLE_BY_CKAN_ROLE = new HashMap(); for(Role role : Role.values()) { ROLE_BY_PORTAL_ROLE.put(role.getPortalRole(), role); ROLE_BY_CKAN_ROLE.put(role.getCkanRole(), role); } } public static Role getRoleFromPortalRole(String portalRole) { return ROLE_BY_PORTAL_ROLE.get(portalRole); } public static String getCkanRoleFromPortalRole(String portalRole) { return getRoleFromPortalRole(portalRole).getCkanRole(); } public static Role getRoleFromCkanRole(String ckanRole) { return ROLE_BY_CKAN_ROLE.get(ckanRole); } public static String getPortalRoleFromCkanRole(String ckanRole) { return getRoleFromCkanRole(ckanRole).getPortalRole(); } } private static final InheritableThreadLocal currentCkanUser = new InheritableThreadLocal() { @Override protected CKANUser initialValue() { CKANUser ckanUser = new CKANUser(); ckanUser.retrieve(); return ckanUser; } }; public static CKANUser getCurrentCKANUser() { return currentCkanUser.get(); } protected PortalUser portalUser; protected Role role; public CKANUser() { super(); LIST = USER_LIST; CREATE = USER_CREATE; READ = USER_SHOW; UPDATE = USER_UPDATE; PATCH = null; DELETE = USER_DELETE; PURGE = null; } public String create() { RandomString randomString = new RandomString(12); ObjectNode objectNode = mapper.createObjectNode(); objectNode.put(NAME, name); objectNode.put(PASSWORD, randomString.nextString()); checkAndSetEMail(objectNode); checkAndSetFullName(objectNode); checkAndSetJobTitle(objectNode); return create(getAsString(objectNode)); } @Override public void delete(boolean purge) { this.delete(); } /** * * @param objectNode * @return true if the display name and the full name has been updated in objectNode */ private boolean checkAndSetJobTitle(ObjectNode objectNode) { String portalJobTitle = getPortalUser().getJobTitle(); String ckanJobTitle = ""; if(objectNode.has(ABOUT)) { ckanJobTitle = objectNode.get(ABOUT).asText(); } if(portalJobTitle.compareTo(ckanJobTitle)!=0){ objectNode = (ObjectNode) result; objectNode.put(ABOUT, portalJobTitle); return true; } return false; } /** * * @param objectNode * @return true if the display name and the full name has been updated in objectNode */ private boolean checkAndSetFullName(ObjectNode objectNode) { String portalFullname = getPortalUser().getFullName(); String ckanFullname = ""; if(objectNode.has(FULL_NAME)) { ckanFullname = objectNode.get(FULL_NAME).asText(); } if(portalFullname.compareTo(ckanFullname)!=0){ objectNode = (ObjectNode) result; objectNode.put(FULL_NAME, portalFullname); objectNode.put(DISPLAY_NAME, portalFullname); return true; } return false; } /** * * @param objectNode * @return true if the display name and the full name has been updated */ private boolean checkAndSetEMail(ObjectNode objectNode) { String portalEmail = getPortalUser().getEMail(); String ckanEmail = ""; if(objectNode.has(EMAIL)) { ckanEmail = objectNode.get(EMAIL).asText(); } if(portalEmail.compareTo(ckanEmail)!=0){ objectNode = (ObjectNode) result; objectNode.put(EMAIL, portalEmail); return true; } return false; } /** * Update the user profile on CKAN if the got got informations differs from the portal information * @return true if the profile information has been updated */ protected boolean updateProfileIfNeeded() { ObjectNode objectNode = (ObjectNode) result; boolean toBeUpdated = false; toBeUpdated = checkAndSetEMail(objectNode) || toBeUpdated; toBeUpdated = checkAndSetFullName(objectNode) || toBeUpdated; toBeUpdated = checkAndSetJobTitle(objectNode) || toBeUpdated; if(toBeUpdated) { update(getAsString(objectNode)); } return toBeUpdated; } private void retrieve() { setApiKey(CKANUtility.getSysAdminAPI()); try { if(name==null || name.compareTo("")==0) { setName(getCKANUsername()); } read(); updateProfileIfNeeded(); } catch(WebApplicationException e) { if(e.getResponse().getStatusInfo() == Status.NOT_FOUND) { create(); }else { throw e; } } addUserToOrganization(); } protected void parseResult() { name = result.get(NAME).asText(); apiKey = result.get(API_KEY).asText(); } protected static String getCKANUsername(String username){ if(username == null) return null; return username.trim().replaceAll("\\.", "_"); } public static String getCKANUsername() { return getCKANUsername(ContextUtility.getUsername()); } public String read() { String ret = super.read(); parseResult(); return ret; } protected void addUserToOrganization(String organizationName, String ckanUsername, String role) { logger.trace("Going to add user {} to organization {} with role {}", ckanUsername, organizationName, role); CKANOrganization ckanOrganization = new CKANOrganization(); ckanOrganization.setApiKey(CKANUtility.getSysAdminAPI()); ckanOrganization.setName(organizationName); ckanOrganization.addUserToOrganisation(ckanUsername, role); } private Role getRole() { if(role==null) { role = Role.MEMBER; List roles = getPortalUser().getRoles(); for(String portalRole : roles){ Role gotRole = Role.getRoleFromPortalRole(portalRole); if(gotRole!=null && gotRole.ordinal()>role.ordinal()){ role = gotRole; } } } return role; } public void addUserToOrganization(String organizationName) { addUserToOrganization(organizationName, name, getRole().getCkanRole()); } public void addUserToOrganization() { String organizationName = CKANOrganization.getCKANOrganizationName(); addUserToOrganization(organizationName); } public void addToGroup(String groupName) throws WebApplicationException { try { ObjectNode objectNode = mapper.createObjectNode(); objectNode.put(ID_KEY, CKANGroup.getCKANGroupName(groupName)); objectNode.put("object", name); objectNode.put("object_type", "user"); objectNode.put("capacity", "member"); sendPostRequest(ADD_USER_TO_GROUP, getAsString(objectNode)); }catch (WebApplicationException e) { throw e; }catch (Exception e) { throw new InternalServerErrorException(e); } } public PortalUser getPortalUser() { if(portalUser==null) { portalUser = new PortalUser(); } return portalUser; } }