diff --git a/src/main/java/org/gcube/datacatalogue/ckanutillibrary/server/DataCatalogue.java b/src/main/java/org/gcube/datacatalogue/ckanutillibrary/server/DataCatalogue.java index 52925ff..7c91eb9 100644 --- a/src/main/java/org/gcube/datacatalogue/ckanutillibrary/server/DataCatalogue.java +++ b/src/main/java/org/gcube/datacatalogue/ckanutillibrary/server/DataCatalogue.java @@ -11,13 +11,10 @@ import org.gcube.datacatalogue.ckanutillibrary.shared.jackan.model.CkanGroup; import org.gcube.datacatalogue.ckanutillibrary.shared.jackan.model.CkanLicense; import org.gcube.datacatalogue.ckanutillibrary.shared.jackan.model.CkanOrganization; - - /** * The Interface DataCatalogue. * - * @author Francesco Mangiacrapa at ISTI-CNR Pisa (Italy) - * Jun 1, 2020 + * @author Francesco Mangiacrapa at ISTI-CNR Pisa (Italy) Jun 1, 2020 */ public interface DataCatalogue { @@ -98,7 +95,6 @@ public interface DataCatalogue { */ String getCatalogueUrl(); - /** * Returns the list of groups to whom the user belongs (with any role). * @@ -111,12 +107,11 @@ public interface DataCatalogue { * Retrieve a ckan dataset given its id. * * @param datasetId the dataset id - * @param apiKey the api key. If null uses gCat to get the Dataset + * @param apiKey the api key. If null uses gCat to get the Dataset * @return the dataset */ CkanDataset getDataset(String datasetId, String apiKey); - /** * Gets the user role by group. * @@ -124,16 +119,16 @@ public interface DataCatalogue { * @return the user role by group */ Map> getUserRoleByGroup(String username); - + /** - * The method returns the role the user has in the organizations he/she belongs to (it uses the db, so it is much faster). + * The method returns the role the user has in the organizations he/she belongs + * to (it uses the db, so it is much faster). * * @param username the username * @return the user role by organization */ Map> getUserRoleByOrganization(String username); - - + /** * Retrieve the list of organizations ids. * @@ -155,7 +150,7 @@ public interface DataCatalogue { * @return the organization by id or name */ CkanOrganization getOrganizationByIdOrName(String name); - + /** * Returns the list of organizations to whom the user belongs (with any role). * @@ -163,9 +158,10 @@ public interface DataCatalogue { * @return a list of organizations */ List getOrganizationsByUser(String username); - + /** - * Returns the list of organizations' names to whom the user belongs (with any role). + * Returns the list of organizations' names to whom the user belongs (with any + * role). * * @param username the username * @return a list of organizations @@ -173,14 +169,15 @@ public interface DataCatalogue { List getOrganizationsNamesByUser(String username); /** - * Given the username and the organization name the method retrieves the role of the user (i.e. his/her 'capacity') + * Given the username and the organization name the method retrieves the role of + * the user (i.e. his/her 'capacity') * * @param username the username - * @param orgName the org name + * @param orgName the org name * @return the capacity of the user into this organization or null */ String getRoleOfUserInOrganization(String username, String orgName); - + /** * Check if the user is valid by checking if its API_KEY is present into DB. * @@ -188,35 +185,59 @@ public interface DataCatalogue { * @return true, if successful */ boolean checkValidUser(String username); - + /** - * Check if this role is present for this user in the organization. If he/she is not present we need to add it with the given role. + * Check if this role is present for this user in the organization. If he/she is + * not present we need to add it with the given role. + * * @param username * @param organizationName * @param correspondentRoleToCheck * @return true if the role can be set, false if it cannot */ - boolean checkRoleIntoOrganization(String username, String organizationName, RolesCkanGroupOrOrg correspondentRoleToCheck); - + boolean checkRoleIntoOrganization(String username, String organizationName, + RolesCkanGroupOrOrg correspondentRoleToCheck); + /** - * Check if this role is present for this user in the group. If he/she is not present we need to add it with the given role. + * Check if this role is present for this user in the group. If he/she is not + * present we need to add it with the given role. + * * @param username * @param organizationName * @param correspondentRoleToCheck * @return true if the role can be set, false if it cannot */ boolean checkRoleIntoGroup(String username, String groupName, RolesCkanGroupOrOrg correspondentRoleToCheck); - + /** - * Returns the main landing pages for this catalogue (i.e. type, orgs, groups and items pages) + * Returns the main landing pages for this catalogue (i.e. type, orgs, groups + * and items pages) * * @return the landing pages * @throws Exception the exception */ LandingPages getLandingPages() throws Exception; + /** + * Returns a Map with key 'capacity' and as value a list of users with that + * capacity into the group groupNameOrTitle. + * + * @return + */ + Map> getRolesAndUsersGroup(String groupNameOrTitle); + /** + * Get the parent groups of this group + * + * @return the group parent, if any + */ + List getParentGroups(String groupName, String apiKey); + /** + * Retrieve the organization with this name + */ + CkanOrganization getOrganizationByName(String name); + /** ***************************************************************************** * @@ -227,39 +248,39 @@ public interface DataCatalogue { * * ***************************************************************************** - - - - /** - * Create a dataset with those information. The method allows to have multiple - * values for the same custom field key. NOTE: unfortunately java doesn't - * support overload in java interface methods (that's way I cannot use the same - * name for the method) + * + * + * + * /** Create a dataset with those information. The method allows to have + * multiple values for the same custom field key. NOTE: unfortunately java + * doesn't support overload in java interface methods (that's way I cannot use + * the same name for the method) * - * @param username the username - * @param title the title + * @param username the username + * @param title the title * @param name (unique identifier) - * @param organizationNameOrId the organization name or id - * @param author the author - * @param authorMail the author mail - * @param maintainer the maintainer - * @param maintainerMail the maintainer mail - * @param version the version - * @param description the description - * @param licenseId the license id - * @param tags the tags + * @param organizationName the organization name + * @param author the author + * @param authorMail the author mail + * @param maintainer the maintainer + * @param maintainerMail the maintainer mail + * @param version the version + * @param description the description + * @param licenseId the license id + * @param tags the tags * @param customFieldsMultiple the custom fields multiple - * @param resources the resources - * @param setPublic (manage visibility: Admin role is needed) - * @param setSearchable set the item as searchable or not - * @param socialPost send the social post or not + * @param resources the resources + * @param setPublic (manage visibility: Admin role is needed) + * @param setSearchable set the item as searchable or not + * @param socialPost send the social post or not * @return the id of the dataset on success, null otherwise * @throws Exception the exception */ - String createCkanDatasetMultipleCustomFields(String username, String title, String name, String organizationNameOrId, + String createCkanDatasetMultipleCustomFields(String username, String title, String name, String organizationName, String author, String authorMail, String maintainer, String maintainerMail, long version, String description, String licenseId, List tags, Map> customFieldsMultiple, - List resources, boolean setPublic, boolean setSearchable, boolean socialPost) throws Exception; + List resources, boolean setPublic, boolean setSearchable, boolean socialPost) + throws Exception; // /** // * Patch a product with product id productId by using the couples in @@ -295,30 +316,27 @@ public interface DataCatalogue { */ boolean deleteResourceFromDataset(String resourceId) throws Exception; - /** * Create a CkanGroup. * - * @param nameOrId a unique id for the group - * @param title a title for the group + * @param nameOrId a unique id for the group + * @param title a title for the group * @param description a description for the group * @return the created CkanGroup on success, null otherwise * @throws Exception the exception */ CkanGroup createGroup(String nameOrId, String title, String description) throws Exception; - /** * Sets the searchable field for dataset. * - * @param datasetId the dataset id + * @param datasetId the dataset id * @param searchable the searchable * @return true, if successful * @throws Exception the exception */ boolean setSearchableFieldForDataset(String datasetId, boolean searchable) throws Exception; - /** * Patch the fields for dataset passed * @@ -329,5 +347,13 @@ public interface DataCatalogue { */ boolean patchFieldsForDataset(String datasetId, Map mapFields) throws Exception; + /** + * Assign dataset to group. + * + * @param groupNameOrId the group name or id + * @param datasetNameOrId the dataset name or id + * @return true, if successful + */ + boolean assignDatasetToGroup(String groupNameOrId, String datasetNameOrId); } diff --git a/src/main/java/org/gcube/datacatalogue/ckanutillibrary/server/DataCatalogueImpl.java b/src/main/java/org/gcube/datacatalogue/ckanutillibrary/server/DataCatalogueImpl.java index 39e830d..affa573 100644 --- a/src/main/java/org/gcube/datacatalogue/ckanutillibrary/server/DataCatalogueImpl.java +++ b/src/main/java/org/gcube/datacatalogue/ckanutillibrary/server/DataCatalogueImpl.java @@ -5,13 +5,19 @@ import static com.google.common.base.Preconditions.checkNotNull; import java.net.URLEncoder; import java.util.ArrayList; +import java.util.Arrays; import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; import java.util.List; +import java.util.ListIterator; import java.util.Map; +import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import org.apache.http.HttpResponse; import org.apache.http.HttpStatus; +import org.apache.http.client.methods.HttpGet; import org.apache.http.client.methods.HttpPost; import org.apache.http.entity.ContentType; import org.apache.http.entity.StringEntity; @@ -44,7 +50,9 @@ import org.gcube.datacatalogue.ckanutillibrary.shared.jackan.model.CkanOrganizat import org.gcube.datacatalogue.ckanutillibrary.shared.jackan.model.CkanResource; import org.gcube.datacatalogue.ckanutillibrary.shared.jackan.model.CkanUser; import org.gcube.datacatalogue.ckanutillibrary.shared.jackan.model.exceptions.JackanException; +import org.json.simple.JSONArray; import org.json.simple.JSONObject; +import org.json.simple.parser.JSONParser; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -710,6 +718,39 @@ public class DataCatalogueImpl implements DataCatalogue { + @Override + public List getParentGroups(String groupName, String apiKey) { + // checks + checkNotNull(groupName); + checkNotNull(apiKey); + + try{ + ExtendCkanClient client = new ExtendCkanClient(CKAN_CATALOGUE_URL, apiKey); + return client.getGroup(groupName).getGroups(); + }catch(Exception e){ + LOG.error("Something went wrong, returning null", e); + } + + return null; + } + + @Override + public CkanOrganization getOrganizationByName(String name) { + + checkNotNull(name); + + String ckanName = name.toLowerCase(); + try{ + + return ckanCaller.getOrganization(ckanName); + + }catch(Exception e){ + LOG.warn("Failed to retrieve the organization with name " +name+ " on the ckan: "+ckanCaller.getCatalogUrl(), e); + } + return null; + } + + /* * * @@ -1060,5 +1101,182 @@ public class DataCatalogueImpl implements DataCatalogue { return toCreate; } + + + @Override + public Map> getRolesAndUsersGroup(String groupName) { + + // checks + checkNotNull(groupName); + checkArgument(!groupName.isEmpty()); + Map> capacityAndUsers = null; + String groupNameToCheck = CatalogueUtilMethods.fromGroupTitleToName(groupName); + + CkanGroup group = ckanCaller.getGroup(groupNameToCheck); + + if(group != null){ + capacityAndUsers = new HashMap>(); + List users = group.getUsers(); + for (CkanUser ckanUser : users) { + List listUsers; + if(capacityAndUsers.containsKey(RolesCkanGroupOrOrg.convertFromCapacity(ckanUser.getCapacity()))){ + listUsers = capacityAndUsers.get(RolesCkanGroupOrOrg.convertFromCapacity(ckanUser.getCapacity())); + }else + listUsers = new ArrayList(); + + listUsers.add(ckanUser.getName()); + capacityAndUsers.put(RolesCkanGroupOrOrg.convertFromCapacity(ckanUser.getCapacity()), listUsers); + + } + + LOG.info("Returning " + capacityAndUsers); + } + return capacityAndUsers; + } + + + //TODO HAS TO BE REVISITED by gCAT + @Override + public boolean assignDatasetToGroup(String groupNameOrId, String datasetNameOrId) { + return assignDatasetToGroupBody(groupNameOrId, datasetNameOrId, false); + + } + + /** + * The real body of the assignDatasetToGroup + * @param groupNameOrId + * @param datasetNameOrId + * @param apiKey + * @param addOnParents + * @return + */ + private boolean assignDatasetToGroupBody(String groupNameOrId, String datasetNameOrId, boolean addOnParents) { + + // checks + checkNotNull(groupNameOrId); + checkArgument(!groupNameOrId.isEmpty()); + checkNotNull(datasetNameOrId); + checkArgument(!datasetNameOrId.isEmpty()); + + String groupNameToCheck = CatalogueUtilMethods.fromGroupTitleToName(groupNameOrId); + + try(CloseableHttpClient httpClient = HttpClientBuilder.create().build();){ + + ExtendCkanClient client = new ExtendCkanClient(CKAN_CATALOGUE_URL, CKAN_TOKEN_SYS); + + // check the group exists + CkanGroup group = client.getGroup(groupNameToCheck); + + // move to a list + List groupNames = new ArrayList(); + groupNames.add(group.getName()); + if(group != null && addOnParents){ + findHierarchyGroups(groupNames, CKAN_TOKEN_SYS); + } + + // we need to use the apis to make it + String pathPackageShow = CKAN_CATALOGUE_URL + "/api/3/action/package_show?id=" + datasetNameOrId; + HttpGet getRequest = new HttpGet(pathPackageShow); + getRequest.addHeader("Authorization", CKAN_TOKEN_SYS); + HttpResponse response = httpClient.execute(getRequest); + + LOG.debug("Response is " + response.getStatusLine().getStatusCode() + " and message is " + response.getStatusLine().getReasonPhrase()); + + // read the json dataset and fetch the groups and fetch the groups' names, if any + if(response.getStatusLine().getStatusCode() == HttpStatus.SC_OK){ + + // parse the json and convert to java beans + String jsonAsString = EntityUtils.toString(response.getEntity()); + JSONParser parser = new JSONParser(); + JSONObject json = (JSONObject) parser.parse(jsonAsString); + JSONObject resultJson = (JSONObject) json.get("result"); + JSONArray groupsJson = (JSONArray)resultJson.get("groups"); + Iterator it = groupsJson.iterator(); + + while (it.hasNext()) { + JSONObject object = it.next(); + try{ + if(object.containsKey("name")) + groupNames.add((String)object.get("name")); + }catch(Exception e){ + LOG.error("Error", e); + } + } + + // remove duplicates + Set groupNamesSet = new HashSet(groupNames); + + LOG.debug("Groups to be added are " + groupNamesSet); + + // now we patch the dataset with the new group + String pathUpdatePatch = CKAN_CATALOGUE_URL + "/api/3/action/package_patch"; + + JSONObject req = new JSONObject(); + req.put("id", datasetNameOrId); + + JSONArray groups = new JSONArray(); + Iterator iteratorNameSet = groupNamesSet.iterator(); + while (iteratorNameSet.hasNext()) { + String groupName = iteratorNameSet.next(); + JSONObject groupJSON = new JSONObject(); + groupJSON.put("name", groupName); + groups.add(groupJSON); + } + req.put("groups", groups); + + LOG.debug("Request for patch is going to be " + req.toJSONString()); + + HttpPost request = new HttpPost(pathUpdatePatch); + request.addHeader("Authorization", CKAN_TOKEN_SYS); + StringEntity params = new StringEntity(req.toJSONString()); + request.setEntity(params); + HttpResponse responsePatch = httpClient.execute(request); + LOG.debug("Response code is " + responsePatch.getStatusLine().getStatusCode() + " and response message is " + responsePatch.getStatusLine().getReasonPhrase()); + + if(responsePatch.getStatusLine().getStatusCode() == HttpStatus.SC_OK){ + LOG.info("Dataset Added to the group!!"); + return true; + } + + } + + }catch(Exception e){ + LOG.error("Unable to make this association", e); + } + + return false; + } + + /** + * Find the hierarchy of trees + * @param uniqueGroups + * @param catalogue + * @param user's api key + */ + private void findHierarchyGroups( + List groupsTitles, + String apiKey) { + ListIterator iterator = groupsTitles.listIterator(); + while (iterator.hasNext()) { + String group = iterator.next(); + + List parents = getParentGroups(group, apiKey); + + if(parents == null || parents.isEmpty()) + return; + + for (CkanGroup ckanGroup : parents) { + List parentsList = new ArrayList(Arrays.asList(ckanGroup.getName())); + findHierarchyGroups(parentsList, apiKey); + for (String parent : parentsList) { + iterator.add(parent); + } + } + } + + } + + + }