diff --git a/src/emc-metalnx-shared/src/main/java/com/emc/metalnx/controller/BrowseController.java b/src/emc-metalnx-shared/src/main/java/com/emc/metalnx/controller/BrowseController.java new file mode 100644 index 000000000..20b9b93ef --- /dev/null +++ b/src/emc-metalnx-shared/src/main/java/com/emc/metalnx/controller/BrowseController.java @@ -0,0 +1,1059 @@ +/* + * Copyright (c) 2015-2017, Dell EMC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.emc.metalnx.controller; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Date; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.Stack; + +import javax.annotation.PostConstruct; +import javax.servlet.http.HttpServletRequest; + +import org.irods.jargon.core.exception.FileNotFoundException; +import org.irods.jargon.core.exception.JargonException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Scope; +import org.springframework.http.HttpStatus; +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.ModelAttribute; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.ResponseBody; +import org.springframework.web.bind.annotation.ResponseStatus; +import org.springframework.web.bind.annotation.SessionAttributes; +import org.springframework.web.context.WebApplicationContext; +import org.springframework.web.servlet.mvc.support.RedirectAttributes; +import org.thymeleaf.util.StringUtils; + +import com.emc.metalnx.controller.utils.LoggedUserUtils; +import com.emc.metalnx.core.domain.entity.DataGridCollectionAndDataObject; +import com.emc.metalnx.core.domain.entity.DataGridGroup; +import com.emc.metalnx.core.domain.entity.DataGridPageContext; +import com.emc.metalnx.core.domain.entity.DataGridResource; +import com.emc.metalnx.core.domain.entity.DataGridUser; +import com.emc.metalnx.core.domain.exceptions.DataGridConnectionRefusedException; +import com.emc.metalnx.core.domain.exceptions.DataGridException; +import com.emc.metalnx.modelattribute.breadcrumb.DataGridBreadcrumb; +import com.emc.metalnx.modelattribute.collection.CollectionOrDataObjectForm; +import com.emc.metalnx.modelattribute.metadatatemplate.MetadataTemplateForm; +import com.emc.metalnx.services.interfaces.CollectionService; +import com.emc.metalnx.services.interfaces.FavoritesService; +import com.emc.metalnx.services.interfaces.GroupBookmarkService; +import com.emc.metalnx.services.interfaces.GroupService; +import com.emc.metalnx.services.interfaces.IRODSServices; +import com.emc.metalnx.services.interfaces.MetadataService; +import com.emc.metalnx.services.interfaces.PermissionsService; +import com.emc.metalnx.services.interfaces.ResourceService; +import com.emc.metalnx.services.interfaces.RuleDeploymentService; +import com.emc.metalnx.services.interfaces.UserBookmarkService; +import com.emc.metalnx.services.interfaces.UserService; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; + +/** + * Transitional controller factors out all sub functions of the + * {@link CollectionController} so that this controller can respond to 'deep + * linkable' paths, including from breadcrumbs in the info pages + * + * @author Mike Conway - NIEHS + * + */ +@Controller +@Scope(WebApplicationContext.SCOPE_SESSION) +@SessionAttributes({ "sourcePaths" }) +@RequestMapping(value = "/browse") +public class BrowseController { + + @Autowired + CollectionService cs; + + @Autowired + ResourceService resourceService; + + @Autowired + UserService userService; + + @Autowired + GroupService groupService; + + @Autowired + GroupBookmarkService groupBookmarkService; + + @Autowired + UserBookmarkService userBookmarkService; + + @Autowired + MetadataService metadataService; + + @Autowired + GroupBookmarkController groupBookmarkController; + + @Autowired + PermissionsService permissionsService; + + @Autowired + IRODSServices irodsServices; + + @Autowired + FavoritesService favoritesService; + + @Autowired + LoggedUserUtils loggedUserUtils; + + @Autowired + RuleDeploymentService ruleDeploymentService; + + // parent path of the current directory in the tree view + private String parentPath; + + // path to the current directory in the tree view + private String currentPath; + + // number of pages for current path + private int totalObjsForCurrentPath; + + // number of pages for current search + private int totalObjsForCurrentSearch; + + // Auxiliary structure to manage download, upload, copy and move operations + private List sourcePaths; + + // ui mode that will be shown when the rods user switches mode from admin to + // user and vice-versa + public static final String UI_USER_MODE = "user"; + public static final String UI_ADMIN_MODE = "admin"; + + public static final int MAX_HISTORY_SIZE = 10; + + private boolean cameFromMetadataSearch; + private boolean cameFromFilePropertiesSearch; + private boolean cameFromBookmarks; + + private Stack collectionHistoryBack; + private Stack collectionHistoryForward; + + // variable to save trash path for the logged user + private String userTrashPath = ""; + // saves the trash under the zone + private String zoneTrashPath = ""; + + private static final Logger logger = LoggerFactory.getLogger(BrowseController.class); + + @PostConstruct + public void init() throws DataGridException { + collectionHistoryBack = new Stack(); + collectionHistoryForward = new Stack(); + + cameFromMetadataSearch = false; + cameFromFilePropertiesSearch = false; + cameFromBookmarks = false; + + sourcePaths = new ArrayList<>(); + parentPath = ""; + currentPath = ""; + } + + /** + * Get a list of resources in which an object doesn't have replicas + * + * @param model + * @return list of resources in which an object can be replicated + * @throws DataGridConnectionRefusedException + */ + @RequestMapping(value = "getAvailableRescForPath/") + public String getAvailableRescForPath(final Model model, @RequestParam("isUpload") final boolean isUpload) + throws DataGridConnectionRefusedException { + + Map replicasMap = null; + List resources = resourceService.findFirstLevelResources(); + + if (!isUpload) { + for (String path : sourcePaths) { + replicasMap = cs.listReplicasByResource(path); + for (DataGridResource resc : replicasMap.values()) { + if (resources.contains(resc)) { + resources.remove(resc); + } + } + } + } + model.addAttribute("resources", resources); + return "collections/collectionsResourcesForReplica"; + } + + /** + * Switches an admin from the Rods_Admin UI to the Rods_User UI and vice-versa. + * + * @param model + * @return redirects an admin user from to the new UI view mode (admin view or + * user view) + */ + @RequestMapping(value = "/switchMode/") + @ResponseStatus(value = HttpStatus.OK) + public void switchMode(final Model model, final HttpServletRequest request, + @RequestParam("currentMode") final String currentMode, final RedirectAttributes redirectAttributes) { + + // if the admin is currently seeing the Admin UI, we need to switch it + // over to the USER UI + if (currentMode.equalsIgnoreCase(UI_ADMIN_MODE)) { + request.getSession().setAttribute("uiMode", UI_USER_MODE); + } + // if the admin is currently seeing the User UI, we need to switch it + // over to the ADMIN UI + else if (currentMode.equalsIgnoreCase(UI_USER_MODE)) { + request.getSession().setAttribute("uiMode", UI_ADMIN_MODE); + } + } + + /** + * Responds the getSubdirectories request finding collections and data objects + * that exist underneath a certain path + * + * @param model + * @param path + * path to find all subdirectories and objects + * @return treeView template that renders all nodes of certain path (parent) + * @throws DataGridException + * if Metalnx cannot find collections and objects inside the path + */ + @RequestMapping(value = "/getSubDirectories/", method = RequestMethod.POST) + public String getSubDirectories(final Model model, @RequestParam("path") String path) throws DataGridException { + + logger.info("getSubDirectories()"); + logger.info("model:{}", model); + logger.info("path:{}", path); + + // removes all ocurrences of "/" at the end of the path string + while (path.endsWith("/") && !"/".equals(path)) { + path = path.substring(0, path.lastIndexOf("/")); + } + + logger.info("Get subdirectories of {}", path); + + System.out.println("In GetSubdirectories!!"); + System.out.println("path :: " + path); + + return getCollBrowserView(model, path); + } + + /** + * Goes back in collection historic stack + * + * @param model + * @param steps + * @return treeView template that renders all nodes of certain path (parent) + * @throws DataGridConnectionRefusedException + */ + @RequestMapping(value = "/goBackHistory/", method = RequestMethod.POST) + public String goBackHistory(final Model model, @RequestParam("steps") final int steps) + throws DataGridException, JargonException { + if (collectionHistoryBack.size() < steps || steps < 1) { + model.addAttribute("invalidStepsBackwards", steps); + logger.info("It is not possible to go back {} steps, current stack size is {}", steps, + collectionHistoryBack.size()); + return getCollBrowserView(model, currentPath); + } + + logger.info("Going back {} steps in collection history", steps); + + // pop paths from collectionHistoryBack and push them to + // collectionHistoryForward + while (collectionHistoryForward.size() >= MAX_HISTORY_SIZE) { + collectionHistoryForward.remove(0); + } + collectionHistoryForward.push(currentPath); + for (int i = 0; i < steps - 1; i++) { + String elementHistory = collectionHistoryBack.pop(); + while (collectionHistoryForward.size() >= MAX_HISTORY_SIZE) { + collectionHistoryForward.remove(0); + } + collectionHistoryForward.push(elementHistory); + } + + return getCollBrowserView(model, collectionHistoryBack.pop()); + } + + /** + * Goes forward in collection historic stack + * + * @param model + * @param steps + * @return treeView template that renders all nodes of certain path (parent) + * @throws DataGridConnectionRefusedException + */ + @RequestMapping(value = "/goForwardHistory/", method = RequestMethod.POST) + public String goForwardHistory(final Model model, @RequestParam("steps") final int steps) + throws DataGridException, JargonException { + if (collectionHistoryForward.size() < steps || steps < 1) { + model.addAttribute("invalidStepsForward", steps); + return getCollBrowserView(model, currentPath); + } + + logger.info("Going {} steps forward in collection history", steps); + + // pop paths from collectionHistoryBack and push them to + // collectionHistoryForward + while (collectionHistoryBack.size() >= MAX_HISTORY_SIZE) { + collectionHistoryBack.remove(0); + } + collectionHistoryBack.push(currentPath); + for (int i = 0; i < steps - 1; i++) { + String elementHistory = collectionHistoryForward.pop(); + while (collectionHistoryBack.size() >= MAX_HISTORY_SIZE) { + collectionHistoryBack.remove(0); + } + collectionHistoryBack.push(elementHistory); + } + + return getCollBrowserView(model, collectionHistoryForward.pop()); + } + + /** + * Responds the getSubdirectories request finding collections and data objects + * that exist underneath a certain path + * + * @param model + * @param path + * @return treeView template that renders all nodes of certain path (parent) + * @throws DataGridConnectionRefusedException + */ + @RequestMapping(value = "/getSubDirectoriesOldTree/") + public String getSubDirectoriesOldTree(final Model model, @RequestParam("path") String path) + throws DataGridConnectionRefusedException { + + if (path.isEmpty()) { + path = "/"; + } else { + if (path.endsWith("/") && path.compareTo("/") != 0) { + path = path.substring(0, path.length() - 1); + } + } + + // The line below was modified so that only collection would be retrieved + model.addAttribute("dataGridCollectionAndDataObjectList", cs.getSubCollectionsUnderPath(path)); + + return "collections/oldTreeView :: oldTreeView"; + } + + /** + * Gets checksum, total number of replicas and where each replica lives in the + * data grid for a specific data object + * + * @param model + * @param path + * path to the data object to get checksum and replica information + * @return the template that shows the data object information + * @throws DataGridConnectionRefusedException + */ + @RequestMapping(value = "/info/", method = RequestMethod.POST) + public String getFileInfo(final Model model, final String path) throws DataGridConnectionRefusedException { + + System.out.println("CollectionController getInfoFile() starts !!"); + DataGridCollectionAndDataObject dataGridObj = null; + Map replicasMap = null; + + try { + System.out.println("Path = " + path); + + dataGridObj = cs.findByName(path); + + if (dataGridObj != null && !dataGridObj.isCollection()) { + replicasMap = cs.listReplicasByResource(path); + dataGridObj.setChecksum(cs.getChecksum(path)); + dataGridObj.setNumberOfReplicas(cs.getTotalNumberOfReplsForDataObject(path)); + dataGridObj.setReplicaNumber(String.valueOf(cs.getReplicationNumber(path))); + permissionsService.resolveMostPermissiveAccessForUser(dataGridObj, + loggedUserUtils.getLoggedDataGridUser()); + + } + + } catch (DataGridConnectionRefusedException e) { + logger.error("Could not connect to the data grid", e); + throw e; + } catch (DataGridException e) { + logger.error("Could not get file info for {}", path, e); + } + + model.addAttribute("collectionAndDataObject", dataGridObj); + model.addAttribute("currentCollection", dataGridObj); + model.addAttribute("replicasMap", replicasMap); + model.addAttribute("infoFlag", true); + + System.out.println("permissionOnCurrentPath =======" + cs.getPermissionsForPath(path)); + System.out.println("currentCollection.getName() == " + dataGridObj.getName()); + + System.out.println("CollectionController getInfoFile() ends !!"); + return "collections/info :: infoView"; + // return "collections/info"; + } + + /** + * Finds all collections and files existing under a certain path for a given + * group name. + * + * @param model + * @param path + * start point to get collections and files + * @param groupName + * group that all collections and files permissions will be listed + * @return + * @throws DataGridConnectionRefusedException + * @throws JargonException + * @throws FileNotFoundException + */ + @RequestMapping(value = "/getDirectoriesAndFilesForGroupForm") + public String getDirectoriesAndFilesForGroupForm(final Model model, @RequestParam("path") String path, + @RequestParam("groupName") final String groupName, + @RequestParam("retrievePermissions") final boolean retrievePermissions) + throws DataGridConnectionRefusedException, FileNotFoundException, JargonException { + if (path == null || path == "") { + path = "/"; + } + + List list = null; + list = cs.getSubCollectionsAndDataObjectsUnderPath(path); + + Set readPermissions = null; + Set writePermissions = null; + Set ownershipPermissions = null; + Set inheritPermissions = null; + + if (retrievePermissions) { + readPermissions = cs.listReadPermissionsForPathAndGroup(path, groupName); + writePermissions = cs.listWritePermissionsForPathAndGroup(path, groupName); + ownershipPermissions = cs.listOwnershipForPathAndGroup(path, groupName); + inheritPermissions = cs.listInheritanceForPath(path); + } else { + readPermissions = new HashSet(); + writePermissions = new HashSet(); + ownershipPermissions = new HashSet(); + inheritPermissions = new HashSet(); + } + + List groupBookmarks = new ArrayList(); + if (groupName.length() > 0) { + DataGridGroup group = groupService.findByGroupname(groupName).get(0); + groupBookmarks = groupBookmarkService.findBookmarksForGroupAsString(group); + } + + model.addAttribute("dataGridCollectionAndDataObjectList", list); + model.addAttribute("currentPath", path); + model.addAttribute("readPermissions", readPermissions); + model.addAttribute("writePermissions", writePermissions); + model.addAttribute("ownershipPermissions", ownershipPermissions); + model.addAttribute("inheritPermissions", inheritPermissions); + model.addAttribute("addBookmark", groupBookmarkController.getAddBookmark()); + model.addAttribute("removeBookmark", groupBookmarkController.getRemoveBookmark()); + model.addAttribute("groupBookmarks", groupBookmarks); + + return "collections/treeViewForGroupForm :: treeView"; + } + + /** + * Finds all collections existing under a certain path. + * + * @param model + * @param path + * start point to get collections and files + * @param username + * user who all collections and files permissions will be listed + * @return the template that will render the tree + * @throws DataGridConnectionRefusedException + * @throws JargonException + * @throws FileNotFoundException + */ + @RequestMapping(value = "/getDirectoriesAndFilesForUser") + public String getDirectoriesAndFilesForUser(final Model model, @RequestParam("path") final String path, + @RequestParam("username") final String username, + @RequestParam("retrievePermissions") final boolean retrievePermissions) + throws DataGridConnectionRefusedException, FileNotFoundException, JargonException { + + List list = new ArrayList(); + Set readPermissions = new HashSet(); + Set writePermissions = new HashSet(); + Set ownershipPermissions = new HashSet(); + Set inheritPermissions = new HashSet(); + List userBookmarks = new ArrayList(); + + // If a string is null, empty or contains only white spaces, StringUtils + // returns true + boolean isPathEmpty = StringUtils.isEmptyOrWhitespace(path); + boolean isUsernameEmpty = StringUtils.isEmptyOrWhitespace(username); + + if (!isPathEmpty) { + // When adding a user (there is no username), we still need to be + // able to walk through the iRODS tree + list = cs.getSubCollectionsAndDataObjectsUnderPath(path); + + if (!isUsernameEmpty) { + if (retrievePermissions) { + readPermissions = cs.listReadPermissionsForPathAndUser(path, username); + writePermissions = cs.listWritePermissionsForPathAndUser(path, username); + ownershipPermissions = cs.listOwnershipForPathAndUser(path, username); + inheritPermissions = cs.listInheritanceForPath(path); + } + + List users = userService.findByUsername(username); + if (users != null && !users.isEmpty()) { + userBookmarks = userBookmarkService.findBookmarksForUserAsString(users.get(0)); + } + } + } + + model.addAttribute("dataGridCollectionAndDataObjectList", list); + model.addAttribute("currentPath", path); + model.addAttribute("readPermissions", readPermissions); + model.addAttribute("writePermissions", writePermissions); + model.addAttribute("ownershipPermissions", ownershipPermissions); + model.addAttribute("inheritPermissions", inheritPermissions); + model.addAttribute("addBookmark", new ArrayList()); + model.addAttribute("removeBookmark", new ArrayList()); + model.addAttribute("userBookmarks", userBookmarks); + + return "collections/treeViewForUserForm :: treeView"; + } + + /** + * Looks for collections or data objects that match the parameter string + * + * @param model + * @param name + * collection name that will be searched in the data grid + * @return the template that renders all collections and data objects matching + * the parameter string + * @throws DataGridConnectionRefusedException + */ + @RequestMapping(value = "/find/{name}") + public String listCollectionsAndDataObjects(final Model model, @PathVariable final String name) + throws DataGridConnectionRefusedException { + logger.info("Finding collections or data objects that match " + name); + + // Find collections and data objects + List dataGridCollectionAndDataObjects = cs + .searchCollectionAndDataObjectsByName(name + "%"); + model.addAttribute("dataGridCollectionAndDataObjects", dataGridCollectionAndDataObjects); + return "collections/collectionsBrowser :: treeView"; + } + + /** + * Performs the action of actually creating a collection in iRODS + * + * @param model + * @param collection + * @return if the creation of collection was successful, it returns the + * collection management template, and returns the add collection + * template, otherwise. + * @throws DataGridConnectionRefusedException + */ + @RequestMapping(value = "add/action", method = RequestMethod.POST) + public String addCollection(final Model model, @ModelAttribute final CollectionOrDataObjectForm collection, + final RedirectAttributes redirectAttributes) throws DataGridConnectionRefusedException { + + logger.info("addCollection()"); + logger.info("collection:{}", collection); + logger.info("redirectAttributes:{}", redirectAttributes); + + DataGridCollectionAndDataObject newCollection = new DataGridCollectionAndDataObject( + currentPath + '/' + collection.getCollectionName(), collection.getCollectionName(), currentPath, true); + + logger.info("newCollection:{}", newCollection); + + newCollection.setParentPath(currentPath); + newCollection.setCreatedAt(new Date()); + newCollection.setModifiedAt(newCollection.getCreatedAt()); + newCollection.setInheritanceOption(collection.getInheritOption()); + + boolean creationSucessful; + try { + creationSucessful = cs.createCollection(newCollection); + logger.info("creationSuccessful?:{}", creationSucessful); + + if (creationSucessful) { + redirectAttributes.addFlashAttribute("collectionAddedSuccessfully", collection.getCollectionName()); + } + } catch (DataGridConnectionRefusedException e) { + throw e; + } catch (DataGridException e) { + logger.error("Could not create collection/data object (lack of permission): ", e.getMessage()); + redirectAttributes.addFlashAttribute("missingPermissionError", true); + } + + return "redirect:/collections" + currentPath; + } + + /** + * Performs the action of modifying a collection + * + * @throws DataGridConnectionRefusedException + */ + @RequestMapping(value = "modify/action", method = RequestMethod.POST) + public String modifyAction(@ModelAttribute final CollectionOrDataObjectForm collForm, + final RedirectAttributes redirectAttributes) throws DataGridException { + String previousPath = collForm.getPath(); + String parentPath = previousPath.substring(0, previousPath.lastIndexOf("/")); + String newPath = String.format("%s/%s", parentPath, collForm.getCollectionName()); + + logger.info("Modify action for " + previousPath + "/" + newPath); + boolean modificationSuccessful = cs.modifyCollectionAndDataObject(previousPath, newPath, + collForm.getInheritOption()); + + if (modificationSuccessful) { + logger.debug("Collection/Data Object {} modified to {}", previousPath, newPath); + + userBookmarkService.updateBookmark(previousPath, newPath); + groupBookmarkService.updateBookmark(previousPath, newPath); + + redirectAttributes.addFlashAttribute("collectionModifiedSuccessfully", collForm.getCollectionName()); + } + + return "redirect:/collections" + parentPath; + } + + @RequestMapping(value = "applyTemplatesToCollections/", method = RequestMethod.POST) + public String applyTemplatesToCollections(final RedirectAttributes redirectAttributes, + @ModelAttribute final MetadataTemplateForm template) throws DataGridConnectionRefusedException { + boolean templatesAppliedSuccessfully = applyTemplatesToPath(template); + redirectAttributes.addFlashAttribute("templatesAppliedSuccessfully", templatesAppliedSuccessfully); + return "redirect:/collections/"; + } + + private boolean applyTemplatesToPath(final MetadataTemplateForm template) + throws DataGridConnectionRefusedException { + boolean allMetadataAdded = true; + List attributes = template.getAvuAttributes(); + List values = template.getAvuValues(); + List units = template.getAvuUnits(); + + if (attributes == null || values == null || units == null) { + return false; + } + + for (int i = 0; i < attributes.size(); i++) { + String attr = attributes.isEmpty() ? "" : attributes.get(i); + String val = values.isEmpty() ? "" : values.get(i); + String unit = units.isEmpty() ? "" : units.get(i); + for (String path : template.getPaths()) { + boolean isMetadadaAdded = metadataService.addMetadataToPath(path, attr, val, unit); + if (!isMetadadaAdded) { + allMetadataAdded = false; + } + } + } + + return allMetadataAdded; + } + + /* + * **************************************************************************** + * ************************ USER COLLECTION CONTROLLER ************************ + * **************************************************************************** + */ + + /** + * Responds the collections/home request + * + * @param model + * @return the collection management template + * @throws DataGridConnectionRefusedException + */ + @RequestMapping(value = "/home") + public String homeCollection(final Model model) throws DataGridException { + // cleaning session variables + logger.info("homeCollection()"); + sourcePaths.clear(); + currentPath = cs.getHomeDirectyForCurrentUser(); + parentPath = currentPath; + return "redirect:/collections" + currentPath; + } + + /** + * Responds the collections/public request + * + * @param model + * @return the collection management template + */ + @RequestMapping(value = "/public") + public String publicCollection(final Model model) throws DataGridException { + // cleaning session variables + sourcePaths.clear(); + + currentPath = cs.getHomeDirectyForPublic(); + parentPath = currentPath; + + model.addAttribute("publicPath", currentPath); + model.addAttribute("currentPath", currentPath); + model.addAttribute("parentPath", parentPath); + model.addAttribute("homePath", cs.getHomeDirectyForCurrentUser()); + model.addAttribute("resources", resourceService.findAll()); + + return "redirect:/collections" + currentPath; + } + + /** + * Responds the collections/trash request + * + * @param model + * @return the collection management template + * @throws DataGridException + */ + @RequestMapping(value = "/trash") + public String trashCollection(final Model model) throws DataGridException { + // cleaning session variables + sourcePaths.clear(); + + if (userTrashPath == null || userTrashPath.equals("")) { + userTrashPath = String.format("/%s/trash/home/%s", irodsServices.getCurrentUserZone(), + irodsServices.getCurrentUser()); + } + currentPath = userTrashPath; + parentPath = currentPath; + + model.addAttribute("currentPath", currentPath); + model.addAttribute("parentPath", parentPath); + model.addAttribute("publicPath", cs.getHomeDirectyForPublic()); + model.addAttribute("homePath", cs.getHomeDirectyForCurrentUser()); + model.addAttribute("resources", resourceService.findAll()); + + return "redirect:/collections" + currentPath; + } + + @RequestMapping(value = "/getBreadCrumbForObject/") + public String getBreadCrumbForObject(final Model model, @RequestParam("path") String path) + throws DataGridConnectionRefusedException { + if (path.isEmpty()) { + path = currentPath; + } else { + if (path.endsWith("/") && path.compareTo("/") != 0) { + path = path.substring(0, path.length() - 1); + } + if (!path.equals(currentPath) + && (collectionHistoryBack.isEmpty() || !currentPath.equals(collectionHistoryBack.peek()))) { + while (collectionHistoryBack.size() >= MAX_HISTORY_SIZE) { + collectionHistoryBack.remove(0); + } + collectionHistoryBack.push(currentPath); + if (!collectionHistoryForward.isEmpty()) { + collectionHistoryForward.clear(); + } + } + currentPath = path; + } + + setBreadcrumbToModel(model, path); + return "collections/collectionsBreadCrumb"; + } + + /* + * ***************************************************************************** + * ******************************** VALIDATION ********************************* + * ***************************************************************************** + */ + + /** + * Validates a collection name in iRODS + * + * @return True, if the collection name can be used. False, otherwise. + * @throws DataGridConnectionRefusedException + */ + @ResponseBody + @RequestMapping(value = "isValidCollectionName/{newObjectName}/", method = RequestMethod.GET, produces = { + "text/plain" }) + public String isValidCollectionName(@PathVariable final String newObjectName) throws DataGridException { + String rc = "true"; + String newPath = String.format("%s/%s", currentPath, newObjectName); + + try { + cs.findByName(newPath); + rc = "false"; + } catch (DataGridException e) { + logger.debug("Path {} does not exist. Executing modification", newPath, e); + } + return rc; + } + + /* + * ************************************************************************* + * ******************************** UTILS ********************************** + * ************************************************************************* + */ + + /** + * Finds all collections and data objects existing under a certain path + * + * @param request + * contains all parameters in a map, we can use it to get all + * parameters passed in request + * @return json with collections and data objects + * @throws DataGridConnectionRefusedException + */ + @RequestMapping(value = "getPaginatedJSONObjs/") + @ResponseBody + public String getPaginatedJSONObjs(final HttpServletRequest request) throws DataGridConnectionRefusedException { + List dataGridCollectionAndDataObjects; + + int draw = Integer.parseInt(request.getParameter("draw")); + int start = Integer.parseInt(request.getParameter("start")); + int length = Integer.parseInt(request.getParameter("length")); + String searchString = request.getParameter("search[value]"); + int orderColumn = Integer.parseInt(request.getParameter("order[0][column]")); + String orderDir = request.getParameter("order[0][dir]"); + boolean deployRule = request.getParameter("rulesdeployment") != null; + + // Pagination context to get the sequence number for the listed items + DataGridPageContext pageContext = new DataGridPageContext(); + + ObjectMapper mapper = new ObjectMapper(); + Map jsonResponse = new HashMap(); + jsonResponse.put("draw", String.valueOf(draw)); + jsonResponse.put("recordsTotal", String.valueOf(1)); + jsonResponse.put("recordsFiltered", String.valueOf(0)); + jsonResponse.put("data", new ArrayList()); + String jsonString = ""; + + try { + String path = currentPath; + if (deployRule) { + path = ruleDeploymentService.getRuleCachePath(); + } + + Double startPage = Math.floor(start / length) + 1; + dataGridCollectionAndDataObjects = cs.getSubCollectionsAndDataObjectsUnderPathThatMatchSearchTextPaginated( + path, searchString, startPage.intValue(), length, orderColumn, orderDir, pageContext); + totalObjsForCurrentSearch = pageContext.getTotalNumberOfItems(); + totalObjsForCurrentPath = pageContext.getTotalNumberOfItems(); + + jsonResponse.put("recordsTotal", String.valueOf(totalObjsForCurrentPath)); + jsonResponse.put("recordsFiltered", String.valueOf(totalObjsForCurrentSearch)); + jsonResponse.put("data", dataGridCollectionAndDataObjects); + } catch (DataGridConnectionRefusedException e) { + throw e; + } catch (Exception e) { + logger.error("Could not get collections/data objs under path {}: {}", currentPath, e.getMessage()); + } + + try { + jsonString = mapper.writeValueAsString(jsonResponse); + } catch (JsonProcessingException e) { + logger.error("Could not parse hashmap in collections to json: {}", e.getMessage()); + } + + return jsonString; + } + + /** + * @return the sourcePaths + */ + public List getSourcePaths() { + return sourcePaths; + } + + /** + * @return the currentPath + */ + public String getCurrentPath() { + return currentPath; + } + + public String getParentPath() { + return parentPath; + } + + /** + * Removes a path from the user's navigation history + * + * @param path + * path to be removed + */ + public void removePathFromHistory(final String path) { + if (path == null || path.isEmpty()) { + return; + } + + collectionHistoryBack.remove(path); + collectionHistoryForward.remove(path); + } + + /* + * ************************************************************************** + * **************************** PRIVATE METHODS ***************************** + * ************************************************************************** + */ + + /** + * Sets the current path and parent path based on a given path. + * + * @param path + * new path to update current path and parent path + */ + private void assignNewValuesToCurrentAndParentPath(final String path) { + if (path == null || path.isEmpty()) { + return; + } + + currentPath = path; + parentPath = currentPath.substring(0, currentPath.lastIndexOf("/") + 1); + } + + /** + * Creates the breadcrumb based on a given path. + * + * @param model + * Model attribute to set variables to be used in the view + * @param path + * path that will be displayed in the breadcrumb + */ + private void setBreadcrumbToModel(final Model model, final String path) { + DataGridCollectionAndDataObject obj; + try { + obj = cs.findByName(path); + } catch (DataGridException e) { + obj = new DataGridCollectionAndDataObject(); + obj.setPath(path); + obj.setCollection(false); + obj.setParentPath(path.substring(0, path.lastIndexOf("/") + 1)); + obj.setName(path.substring(path.lastIndexOf("/") + 1, path.length())); + logger.error("Could not find DataGridCollectionAndDataObject by path: {}", e.getMessage()); + } + + setBreadcrumbToModel(model, obj); + } + + /** + * Creates the breadcrumb based on a given path. + * + * @param model + * Model attribute to set variables to be used in the view + * @param obj + * {@code DataGridCollectionAndDataObject} object + */ + private void setBreadcrumbToModel(final Model model, final DataGridCollectionAndDataObject obj) { + ArrayList listHistoryBack = new ArrayList(collectionHistoryBack); + Collections.reverse(listHistoryBack); + + DataGridUser user = loggedUserUtils.getLoggedDataGridUser(); + boolean isPathFavorite = favoritesService.isPathFavoriteForUser(user, obj.getPath()); + + model.addAttribute("starredPath", isPathFavorite); + model.addAttribute("collectionPastHistory", listHistoryBack); + model.addAttribute("collectionPastHistoryEmpty", collectionHistoryBack.isEmpty()); + model.addAttribute("collectionForwardHistory", collectionHistoryForward); + model.addAttribute("collectionForwardHistoryEmpty", collectionHistoryForward.isEmpty()); + model.addAttribute("collectionForwardHistory", collectionHistoryForward); + model.addAttribute("collectionAndDataObject", obj); + model.addAttribute("breadcrumb", new DataGridBreadcrumb(obj.getPath())); + model.addAttribute("homeCollectionName", irodsServices.getCurrentUser()); + } + + /** + * Finds all collections and data objects existing under a certain path + * + * @param model + * @param path + * path to get all directories and data objects from + * @return collections browser template that renders all items of certain path + * (parent) + * @throws DataGridConnectionRefusedException + * if Metalnx cannot connect to the grid. + */ + private String getCollBrowserView(final Model model, String path) throws DataGridException { + logger.info("getCollBrowserView()"); + + logger.info("model:{}", model); + logger.info("path:{}", path); + if (cs.isPathValid(path)) { + if (path.endsWith("/") && path.compareTo("/") != 0) { + path = path.substring(0, path.length() - 1); + } + currentPath = path; + } else { + model.addAttribute("invalidPath", path); + path = currentPath; + } + + DataGridUser user = loggedUserUtils.getLoggedDataGridUser(); + logger.info("find collection by name:{}", path); + DataGridCollectionAndDataObject dataGridObj = cs.findByName(path); + + if (dataGridObj.isDataObject()) { + dataGridObj.setChecksum(cs.getChecksum(path)); + dataGridObj.setNumberOfReplicas(cs.getTotalNumberOfReplsForDataObject(path)); + dataGridObj.setReplicaNumber(String.valueOf(cs.getReplicationNumber(path))); + } + + permissionsService.resolveMostPermissiveAccessForUser(dataGridObj, user); + + if (zoneTrashPath == null || zoneTrashPath.isEmpty()) { + zoneTrashPath = String.format("/%s/trash", irodsServices.getCurrentUserZone()); + } + + CollectionOrDataObjectForm collectionForm = new CollectionOrDataObjectForm(); + collectionForm.setInheritOption(cs.getInheritanceOptionForCollection(currentPath)); + + String permissionType = cs.getPermissionsForPath(path); + boolean isPermissionOwn = "own".equals(permissionType); + boolean isTrash = path.contains(zoneTrashPath) && (isPermissionOwn || user.isAdmin()); + boolean inheritanceDisabled = !isPermissionOwn && collectionForm.getInheritOption(); + + model.addAttribute("collectionAndDataObject", dataGridObj); + model.addAttribute("isTrash", isTrash); + model.addAttribute("permissionType", permissionType); + model.addAttribute("currentPath", currentPath); + model.addAttribute("isCurrentPathCollection", cs.isCollection(path)); + model.addAttribute("user", user); + model.addAttribute("trashColl", cs.getTrashForPath(currentPath)); + model.addAttribute("collection", collectionForm); + model.addAttribute("inheritanceDisabled", inheritanceDisabled); + model.addAttribute("requestMapping", "/collections/add/action/"); + model.addAttribute("parentPath", parentPath); + setBreadcrumbToModel(model, dataGridObj); + return "collections/collectionsBrowser"; + // return "collections/info"; + } + + /** + * Adds a given path to the list of paths visited by the user + * + * @param path + * path to a collection or data object to be added to history + */ + private void addPathToHistory(final String path) { + if (path.equals(currentPath)) { + return; + } + + while (collectionHistoryBack.size() >= MAX_HISTORY_SIZE) { + collectionHistoryBack.remove(0); + } + + collectionHistoryBack.push(currentPath); + + if (!collectionHistoryForward.isEmpty()) { + collectionHistoryForward.clear(); + } + } +} diff --git a/src/emc-metalnx-shared/src/main/java/com/emc/metalnx/controller/CollectionController.java b/src/emc-metalnx-shared/src/main/java/com/emc/metalnx/controller/CollectionController.java index 21f166b0e..ba55a59cc 100755 --- a/src/emc-metalnx-shared/src/main/java/com/emc/metalnx/controller/CollectionController.java +++ b/src/emc-metalnx-shared/src/main/java/com/emc/metalnx/controller/CollectionController.java @@ -178,9 +178,7 @@ public void init() throws DataGridException { * @throws DataGridException */ @RequestMapping(value = "/") - public String index(final Model model, final HttpServletRequest request, - @RequestParam(value = "uploadNewTab", required = false) final boolean uploadNewTab) - throws DataGridConnectionRefusedException { + public String index(final Model model, final HttpServletRequest request) throws DataGridConnectionRefusedException { logger.info("index()"); try { sourcePaths.clear(); @@ -204,9 +202,6 @@ public String index(final Model model, final HttpServletRequest request, model.addAttribute("homePath", cs.getHomeDirectyForCurrentUser()); model.addAttribute("publicPath", cs.getHomeDirectyForPublic()); } - if (uploadNewTab) { - model.addAttribute("uploadNewTab", uploadNewTab); - } model.addAttribute("cameFromFilePropertiesSearch", cameFromFilePropertiesSearch); model.addAttribute("cameFromMetadataSearch", cameFromMetadataSearch); @@ -332,18 +327,17 @@ public String getSubDirectories(final Model model, @RequestParam("path") String while (path.endsWith("/") && !"/".equals(path)) { path = path.substring(0, path.lastIndexOf("/")); } - + logger.info("Get subdirectories of {}", path); - + System.out.println("In GetSubdirectories!!"); - System.out.println("path :: " +path); - + System.out.println("path :: " + path); + // put old path in collection history stack addPathToHistory(path); return getCollBrowserView(model, path); } - /** * Goes back in collection historic stack @@ -454,17 +448,16 @@ public String getSubDirectoriesOldTree(final Model model, @RequestParam("path") * @return the template that shows the data object information * @throws DataGridConnectionRefusedException */ - @RequestMapping(value = "/info/" , method = RequestMethod.POST) - public String getFileInfo(final Model model, final String path) + @RequestMapping(value = "/info/", method = RequestMethod.POST) + public String getFileInfo(final Model model, @RequestParam("path") final String path) throws DataGridConnectionRefusedException { - System.out.println("CollectionController getInfoFile() starts !!"); DataGridCollectionAndDataObject dataGridObj = null; Map replicasMap = null; try { - System.out.println("Path = " +path); - + System.out.println("Path = " + path); + dataGridObj = cs.findByName(path); if (dataGridObj != null && !dataGridObj.isCollection()) { @@ -473,9 +466,8 @@ public String getFileInfo(final Model model, final String path) dataGridObj.setNumberOfReplicas(cs.getTotalNumberOfReplsForDataObject(path)); dataGridObj.setReplicaNumber(String.valueOf(cs.getReplicationNumber(path))); permissionsService.resolveMostPermissiveAccessForUser(dataGridObj, - loggedUserUtils.getLoggedDataGridUser()); - - + loggedUserUtils.getLoggedDataGridUser()); + } } catch (DataGridConnectionRefusedException e) { @@ -487,16 +479,14 @@ public String getFileInfo(final Model model, final String path) model.addAttribute("collectionAndDataObject", dataGridObj); model.addAttribute("currentCollection", dataGridObj); - model.addAttribute("replicasMap", replicasMap); + model.addAttribute("replicasMap", replicasMap); model.addAttribute("infoFlag", true); - - + System.out.println("permissionOnCurrentPath =======" + cs.getPermissionsForPath(path)); - System.out.println("currentCollection.getName() == "+ dataGridObj.getName()); - - System.out.println("CollectionController getInfoFile() ends !!"); - return "collections/info :: infoView"; - //return "collections/info"; + System.out.println("currentCollection.getName() == " + dataGridObj.getName()); + + // return "collections/collectionInfo"; + return "collections/info"; } /** @@ -579,7 +569,7 @@ public String getDirectoriesAndFilesForUser(final Model model, @RequestParam("pa @RequestParam("username") final String username, @RequestParam("retrievePermissions") final boolean retrievePermissions) throws DataGridConnectionRefusedException, FileNotFoundException, JargonException { - + List list = new ArrayList(); Set readPermissions = new HashSet(); Set writePermissions = new HashSet(); @@ -1107,10 +1097,10 @@ private String getCollBrowserView(final Model model, String path) throws DataGri model.addAttribute("collection", collectionForm); model.addAttribute("inheritanceDisabled", inheritanceDisabled); model.addAttribute("requestMapping", "/collections/add/action/"); - model.addAttribute("parentPath", parentPath); + model.addAttribute("parentPath", parentPath); setBreadcrumbToModel(model, dataGridObj); - return "collections/collectionsBrowser"; - //return "collections/info"; + return "collections/collectionsBrowser"; + // return "collections/info"; } /** diff --git a/src/emc-metalnx-shared/src/main/java/com/emc/metalnx/controller/CollectionInfoController.java b/src/emc-metalnx-shared/src/main/java/com/emc/metalnx/controller/CollectionInfoController.java index 72a899149..2b7574782 100644 --- a/src/emc-metalnx-shared/src/main/java/com/emc/metalnx/controller/CollectionInfoController.java +++ b/src/emc-metalnx-shared/src/main/java/com/emc/metalnx/controller/CollectionInfoController.java @@ -2,10 +2,9 @@ import java.io.IOException; import java.io.InputStream; -import java.util.List; - +import java.io.UnsupportedEncodingException; +import java.net.URLDecoder; import javax.servlet.http.HttpServletRequest; - import org.apache.commons.io.IOUtils; import org.irods.jargon.core.connection.IRODSAccount; import org.irods.jargon.core.exception.JargonException; @@ -22,7 +21,6 @@ import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.util.AntPathMatcher; -import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RequestParam; @@ -31,7 +29,6 @@ import org.springframework.web.context.WebApplicationContext; import org.springframework.web.servlet.HandlerMapping; -import com.emc.metalnx.controller.utils.LoggedUserUtils; import com.emc.metalnx.core.domain.exceptions.DataGridConnectionRefusedException; import com.emc.metalnx.core.domain.exceptions.DataGridException; import com.emc.metalnx.modelattribute.breadcrumb.DataGridBreadcrumb; @@ -58,7 +55,7 @@ public class CollectionInfoController { @Autowired IRODSServices irodsServices; - + @Autowired IconService iconService; @@ -69,7 +66,7 @@ public class CollectionInfoController { @RequestMapping(value = "/**", method = RequestMethod.GET) public String getTestCollectionInfo(final Model model, HttpServletRequest request) - throws DataGridException, DataGridConnectionRefusedException { + throws DataGridException, DataGridConnectionRefusedException, JargonException { logger.info("CollectionInfoController getTestCollectionInfo() starts !!"); final String path = "/" + extractFilePath(request); @@ -78,36 +75,35 @@ public String getTestCollectionInfo(final Model model, HttpServletRequest reques @SuppressWarnings("rawtypes") DataProfile dataProfile = getCollectionDataProfile(path); - + String iconToDisplay = ""; - - if(dataProfile!= null && dataProfile.isFile()) + + if (dataProfile != null && dataProfile.isFile()) iconToDisplay = iconService.getIconToDisplayFile(dataProfile.getDataType().getMimeType()); - if(dataProfile!= null && !dataProfile.isFile()) + if (dataProfile != null && !dataProfile.isFile()) iconToDisplay = iconService.getIconToDisplayCollection(); - - model.addAttribute("iconToDisplay", iconToDisplay); + + model.addAttribute("iconToDisplay", iconToDisplay); model.addAttribute("dataProfile", dataProfile); model.addAttribute("breadcrumb", new DataGridBreadcrumb(dataProfile.getAbsolutePath())); DataGridBreadcrumb bc = new DataGridBreadcrumb(dataProfile.getAbsolutePath()); System.out.println("Absolute Path :: " +dataProfile.getAbsolutePath()); String template = ""; - - if(!dataProfile.isFile()) + + if (!dataProfile.isFile()) template = "collections/collectionInfo"; - if(dataProfile.isFile()) + if (dataProfile.isFile()) template = "collections/fileInfo"; - - return template; - - //:: mainPage(page='collections/collectionInfo', fragment='collectionInfo')"; - //"main :: mainPage(page='some-page', fragment='somePage')"; + + return template; + + // :: mainPage(page='collections/collectionInfo', fragment='collectionInfo')"; + // "main :: mainPage(page='some-page', fragment='somePage')"; } - + @SuppressWarnings("unchecked") public DataProfile getCollectionDataProfile(String path) throws DataGridException { - IRODSAccount irodsAccount = irodsServices.getUserAO().getIRODSAccount(); logger.debug("got irodsAccount:{}", irodsAccount); @@ -123,47 +119,45 @@ public DataProfile getCollectionDataProfile(String path) thro DataProfile dataProfile = dataProfilerService.retrieveDataProfile(path); logger.info("------CollectionInfoController getTestCollectionInfo() ends !!"); logger.info("data profile retrieved:{}", dataProfile); - + /* * TODO: after this do an if test and send to right view with the DataProfile in * the model */ return dataProfile; - + } catch (JargonException e) { logger.error("Could not retrieve collection/dataobject from path: {}", path, e); throw new DataGridException(e.getMessage()); } } - - - + @RequestMapping(value = "/collectionFileInfo/", method = RequestMethod.POST) - public String getCollectionFileInfo(final Model model, @RequestParam("path") - final String path) throws DataGridException { + public String getCollectionFileInfo(final Model model, @RequestParam("path") final String path) + throws DataGridException { + + logger.info("CollectionInfoController getCollectionFileInfo() starts :: " + path); - logger.info("CollectionInfoController getCollectionFileInfo() starts :: " +path); - @SuppressWarnings("rawtypes") DataProfile dataProfile = getCollectionDataProfile(path); - + String iconToDisplay = ""; - - if(dataProfile!= null && dataProfile.isFile()) + + if (dataProfile != null && dataProfile.isFile()) iconToDisplay = iconService.getIconToDisplayFile(dataProfile.getDataType().getMimeType()); - if(dataProfile!= null && !dataProfile.isFile()) + if (dataProfile != null && !dataProfile.isFile()) iconToDisplay = iconService.getIconToDisplayCollection(); - - model.addAttribute("iconToDisplay", iconToDisplay); + + model.addAttribute("iconToDisplay", iconToDisplay); model.addAttribute("dataProfile", dataProfile); - + logger.info("getCollectionFileInfo() ends !!"); return "collections/info :: infoView"; - //return "collections/info"; + // return "collections/info"; } - - @RequestMapping(value = "/getFile/",produces = MediaType.APPLICATION_OCTET_STREAM_VALUE) + + @RequestMapping(value = "/getFile/", produces = MediaType.APPLICATION_OCTET_STREAM_VALUE) public @ResponseBody byte[] getFile() throws IOException { logger.info("getFile() starts!!"); InputStream in = getClass() @@ -206,8 +200,15 @@ public String getCollectionFileInfo(final Model model, @RequestParam("path") * * } */ - private static String extractFilePath(HttpServletRequest request) { + private String extractFilePath(HttpServletRequest request) throws JargonException { String path = (String) request.getAttribute(HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE); + try { + path = URLDecoder.decode(path, + this.getIrodsServices().getIrodsAccessObjectFactory().getJargonProperties().getEncoding()); + } catch (UnsupportedEncodingException | JargonException e) { + logger.error("unable to decode path", e); + throw new JargonException(e); + } String bestMatchPattern = (String) request.getAttribute(HandlerMapping.BEST_MATCHING_PATTERN_ATTRIBUTE); AntPathMatcher apm = new AntPathMatcher(); return apm.extractPathWithinPattern(bestMatchPattern, path); diff --git a/src/emc-metalnx-shared/src/main/java/com/emc/metalnx/controller/FileOperationsController.java b/src/emc-metalnx-shared/src/main/java/com/emc/metalnx/controller/FileOperationsController.java index 981fdfce6..969ada471 100755 --- a/src/emc-metalnx-shared/src/main/java/com/emc/metalnx/controller/FileOperationsController.java +++ b/src/emc-metalnx-shared/src/main/java/com/emc/metalnx/controller/FileOperationsController.java @@ -60,6 +60,9 @@ public class FileOperationsController { private static final Logger logger = LoggerFactory.getLogger(FileOperationsController.class); private static String TRASH_PATH; + @Autowired + private BrowseController browseController; + @Autowired private CollectionController collectionController; @@ -115,7 +118,7 @@ public String move(final Model model, @RequestParam("targetPath") final String t model.addAttribute("failedMoves", failedMoves); - return collectionController.getSubDirectories(model, targetPath); + return browseController.getSubDirectories(model, targetPath); } @RequestMapping(value = "/copy", method = RequestMethod.POST) @@ -124,14 +127,26 @@ public String copy(final Model model, @RequestParam("targetPath") final String t @RequestParam("copyWithMetadata") final boolean copyWithMetadata, @RequestParam("paths[]") final String[] paths) throws DataGridException, JargonException { + logger.info("copy()"); + logger.info("model:{}", model); + logger.info("copyWithMetadata:{}", copyWithMetadata); + logger.info("targetPath:{}", targetPath); + for (String path : paths) { + logger.info("path:{}", path); + } + List failedCopies = new ArrayList<>(); String fileCopied = ""; for (String p : paths) { String item = p.substring(p.lastIndexOf("/") + 1, p.length()); + logger.info("copying p:{}", p); + logger.info("to target path:{}", targetPath); if (!fileOperationService.copy(p, targetPath, copyWithMetadata)) { + logger.warn("failed on copy of item:{}", item); failedCopies.add(item); } else if (paths.length == 1) { + logger.info("success on item:{}", item); fileCopied = item; } } @@ -142,7 +157,7 @@ public String copy(final Model model, @RequestParam("targetPath") final String t model.addAttribute("failedCopies", failedCopies); - return collectionController.getSubDirectories(model, targetPath); + return browseController.getSubDirectories(model, targetPath); } /** @@ -173,14 +188,14 @@ public String deleteReplica(final Model model, @RequestParam("path") final Strin } else { model.addAttribute("delReplReturn", "failure"); } - return collectionController.getFileInfo(model, path); + return browseController.getFileInfo(model, path); } @RequestMapping(value = "/replicate", method = RequestMethod.POST) public String replicate(final Model model, final HttpServletRequest request) throws DataGridConnectionRefusedException { - List sourcePaths = collectionController.getSourcePaths(); + List sourcePaths = browseController.getSourcePaths(); String[] resources = request.getParameterMap().get("resourcesForReplication"); List failedReplicas = new ArrayList<>(); @@ -203,7 +218,7 @@ public String replicate(final Model model, final HttpServletRequest request) sourcePaths.clear(); } - return collectionController.index(model, request, false); + return collectionController.index(model, request); } @RequestMapping(value = "/prepareFilesForDownload/", method = RequestMethod.GET) @@ -262,7 +277,7 @@ public String deleteCollectionAndDataObject(final Model model, @RequestParam("pa fileDeleted = path.substring(path.lastIndexOf("/") + 1, path.length()); } - collectionController.removePathFromHistory(path); + browseController.removePathFromHistory(path); } if (fileDeleted != null) { @@ -270,15 +285,15 @@ public String deleteCollectionAndDataObject(final Model model, @RequestParam("pa } model.addAttribute("failedDeletions", failedDeletions); - model.addAttribute("currentPath", collectionController.getCurrentPath()); - model.addAttribute("parentPath", collectionController.getParentPath()); + model.addAttribute("currentPath", browseController.getCurrentPath()); + model.addAttribute("parentPath", browseController.getParentPath()); - return collectionController.getSubDirectories(model, collectionController.getCurrentPath()); + return browseController.getSubDirectories(model, browseController.getCurrentPath()); } @RequestMapping(value = "emptyTrash/", method = RequestMethod.POST) public ResponseEntity emptyTrash() throws DataGridConnectionRefusedException, JargonException { - String trashForCurrentPath = collectionService.getTrashForPath(collectionController.getCurrentPath()); + String trashForCurrentPath = collectionService.getTrashForPath(browseController.getCurrentPath()); DataGridUser loggedUser = loggedUserUtils.getLoggedDataGridUser(); if (fileOperationService.emptyTrash(loggedUser, trashForCurrentPath)) { return new ResponseEntity<>(HttpStatus.OK); @@ -298,8 +313,8 @@ public ResponseEntity emptyTrash() throws DataGridConnectionRefusedExcep */ @RequestMapping(value = "modify/", method = RequestMethod.GET) public String showModifyForm(final Model model, @RequestParam("path") final String path) throws DataGridException { - String currentPath = collectionController.getCurrentPath(); - String parentPath = collectionController.getParentPath(); + String currentPath = browseController.getCurrentPath(); + String parentPath = browseController.getParentPath(); String formType = "editDataObjectForm"; CollectionOrDataObjectForm targetForm = new CollectionOrDataObjectForm(); diff --git a/src/emc-metalnx-shared/src/main/java/com/emc/metalnx/modelattribute/enums/URLMap.java b/src/emc-metalnx-shared/src/main/java/com/emc/metalnx/modelattribute/enums/URLMap.java index 352fbd75c..6c45afe47 100755 --- a/src/emc-metalnx-shared/src/main/java/com/emc/metalnx/modelattribute/enums/URLMap.java +++ b/src/emc-metalnx-shared/src/main/java/com/emc/metalnx/modelattribute/enums/URLMap.java @@ -51,10 +51,10 @@ public class URLMap { public static final String URL_COLLECTIONS_INFO = "/info/"; public static final String URL_COLLECTIONS_MANAGEMENT = "/collections/"; - public static final String URL_ADD_COLLECTION = "/emc-metalnx-web/collections/add/"; + public static final String URL_ADD_COLLECTION = "/emc-metalnx-web/browse/add/"; public static final String URL_MODIFY_COLLECTION = "/emc-metalnx-web/fileOperation/modify/"; public static final String URL_DELETE_COLLECTION = "/emc-metalnx-web/fileOperation/delete/"; - public static final String URL_COLLECTION_VALIDATE_NAME = "/emc-metalnx-web/collections/isValidCollectionName/"; + public static final String URL_COLLECTION_VALIDATE_NAME = "/emc-metalnx-web/browse/isValidCollectionName/"; public static final String URL_METADATA_SEARCH = "/metadata/"; @@ -85,13 +85,13 @@ public class URLMap { public static final String URL_DELETE_SPECIFIC_QUERY = "/emc-metalnx-web/specificqueries/remove/"; public static final String URL_SPECIFIC_QUERY_VALIDATE = "/emc-metalnx-web/specificqueries/validate/"; - public static final String URL_HOME_COLLECTION_USER = "/collections/home/"; - public static final String URL_PUBLIC_COLLECTION_USER = "/collections/public/"; - public static final String URL_TRASH_COLLECTION_USER = "/collections/trash/"; - public static final String URL_ADD_COLLECTION_USER = "/emc-metalnx-web/collections/add/"; + public static final String URL_HOME_COLLECTION_USER = "/browse/home"; + public static final String URL_PUBLIC_COLLECTION_USER = "/browse/public/"; + public static final String URL_TRASH_COLLECTION_USER = "/browse/trash/"; + public static final String URL_ADD_COLLECTION_USER = "/emc-metalnx-web/browse/add/"; public static final String URL_MODIFY_COLLECTION_USER = "/emc-metalnx-web/fileOperation/modify/"; public static final String URL_DELETE_COLLECTION_USER = "/fileOperation/delete/"; - public static final String URL_COLLECTION_VALIDATE_NAME_USER = "/emc-metalnx-web/collections/isValidCollectionName/"; + public static final String URL_COLLECTION_VALIDATE_NAME_USER = "/emc-metalnx-web/browse/isValidCollectionName/"; public static final String URL_LOGOUT = "/logout/"; public static final String URL_TICKETS = "/tickets/"; diff --git a/src/emc-metalnx-shared/src/main/resources/i18n/messages_en.properties b/src/emc-metalnx-shared/src/main/resources/i18n/messages_en.properties index 5e939d937..9d19999de 100644 --- a/src/emc-metalnx-shared/src/main/resources/i18n/messages_en.properties +++ b/src/emc-metalnx-shared/src/main/resources/i18n/messages_en.properties @@ -18,6 +18,8 @@ text.back=Back text.creation.date=Creation Date text.contains=Contains +text.collections=Collections +text.close=Close text.file.name=File Name text.info=Info text.delete=Delete diff --git a/src/emc-metalnx-shared/src/main/resources/static/js/switchTemplate.js b/src/emc-metalnx-shared/src/main/resources/static/js/switchTemplate.js index 16cd3efbf..dbbdd318b 100644 --- a/src/emc-metalnx-shared/src/main/resources/static/js/switchTemplate.js +++ b/src/emc-metalnx-shared/src/main/resources/static/js/switchTemplate.js @@ -17,12 +17,12 @@ $("#adminModeBtn").click(function(){ $("#adminModeBtn").removeClass("btn-default"); - $("#userModeBtn").removeClass("btn-primary"); - + $("#userModeBtn").removeClass("btn-primary"); + $("#adminModeBtn").addClass("btn-primary"); - $("#userModeBtn").addClass("btn-default"); - - $.post("/emc-metalnx-web/collections/switchMode/", {currentMode: "user"}, + $("#userModeBtn").addClass("btn-default"); + + $.post("/emc-metalnx-web/browse/switchMode/", {currentMode: "user"}, function(response){ window.location = "/emc-metalnx-web/dashboard/"; } @@ -32,13 +32,13 @@ $("#adminModeBtn").click(function(){ $("#userModeBtn").click(function(){ $("#adminModeBtn").removeClass("btn-primary"); $("#userModeBtn").removeClass("btn-default"); - + $("#userModeBtn").addClass("btn-primary"); $("#adminModeBtn").addClass("btn-default"); - - $.post("/emc-metalnx-web/collections/switchMode/", {currentMode: "admin"}, + + $.post("/emc-metalnx-web/collections/switchMode/", {currentMode: "admin"}, function(response){ window.location = "/emc-metalnx-web/collections/"; } ); -}); \ No newline at end of file +}); diff --git a/src/emc-metalnx-shared/src/main/resources/views/bookmarks/userBookmarks.html b/src/emc-metalnx-shared/src/main/resources/views/bookmarks/userBookmarks.html index 0ce5964d6..adbe20eca 100755 --- a/src/emc-metalnx-shared/src/main/resources/views/bookmarks/userBookmarks.html +++ b/src/emc-metalnx-shared/src/main/resources/views/bookmarks/userBookmarks.html @@ -134,7 +134,7 @@

} ); function redirectToCollections(path){ - var url = "/emc-metalnx-web/collections/redirectFromUserBookmarksToCollections/"; + var url = "/emc-metalnx-web/browse/redirectFromUserBookmarksToCollections/"; ajaxEncapsulation(url, "POST", {path: path}, showCollections, null, null, null); } diff --git a/src/emc-metalnx-shared/src/main/resources/views/collections/collectionManagement.html b/src/emc-metalnx-shared/src/main/resources/views/collections/collectionManagement.html index bc4829fb1..49386d057 100755 --- a/src/emc-metalnx-shared/src/main/resources/views/collections/collectionManagement.html +++ b/src/emc-metalnx-shared/src/main/resources/views/collections/collectionManagement.html @@ -37,17 +37,18 @@

  • -
  • Collections
  • +
  • Collections
  • @@ -222,7 +223,7 @@

    - @@ -232,7 +233,7 @@

    - Public @@ -323,7 +324,7 @@

    - iRods @@ -332,7 +333,7 @@

    - @@ -342,7 +343,7 @@

    - Public @@ -660,13 +661,14 @@

    function getSubDirectories(path) { - alert("getSubDirectories") - console.log("Collection managemnet - getSubDirectories()"); + + //alert("getSubDirectories") + console.log("Collection management - getSubDirectories()"); $("#table-loader").show(); $("#tree-view-panel-body").hide(); setTimeout(function () { - ajaxEncapsulation("/emc-metalnx-web/collections/getSubDirectories/", "POST", {path: path}, displaySubDirectories, null, null, null); + ajaxEncapsulation("/emc-metalnx-web/browse/getSubDirectories/", "POST", {path: path}, displaySubDirectories, null, null, null); currentPath = path; console.log("currentpath " +currentPath); console.log("path " +path) @@ -686,7 +688,7 @@ var groupName = $("#collectionInfoGroupName").text(); ajaxEncapsulation( - "/emc-metalnx-web/collections/getSubDirectoriesOldTree/", + "/emc-metalnx-web/browse/getSubDirectoriesOldTree/", "POST", {path : directoryPath, groupName : groupName}, function (data){ @@ -722,13 +724,13 @@ } function showModifyForm() { - var cbChecked = $('input[name="collectionPathCheckboxes"]:checked').length; - - if (cbChecked > 1) return; - - var url = [[ ${ urlMap.URL_MODIFY_COLLECTION_USER } ]]; - var path = $('input[name="collectionPathCheckboxes"]:checked').val(); - ajaxEncapsulation(url, "GET", {path: path}, displayModifyForm, null, null, null); + var cbChecked = $('input[name="collectionPathCheckboxes"]:checked').length; + + if (cbChecked > 1) return; + + var url = [[ ${ urlMap.URL_MODIFY_COLLECTION_USER } ]]; + var path = $('input[name="collectionPathCheckboxes"]:checked').val(); + ajaxEncapsulation(url, "GET", {path: path}, displayModifyForm, null, null, null); } function submitForm() { @@ -736,29 +738,46 @@ $(".registerForm").submit(); } } + + function callbackMoveAndCopyError(path){ + $("#moveModal").modal("hide"); + + //reset the modal + cleanModals(); + + //updating the list of files and collections + currentPath = path; + + positionBrowserToPath(path); + + //xs$("#tree-view-panel-body").html(data); + } + function callbackMoveAndCopy(data){ $("#moveModal").modal("hide"); //reset the modal - cleanModals(); + cleanModals(); //updating the list of files and collections currentPath = targetPath; totalCheckboxesChecked = 0; - resetDataTablesStart(); + //resetDataTablesStart(); + + positionBrowserToPath(targetPath); $("#tree-view-panel-body").html(data); } function updateResourceForReplicationOptions() { - $("#selectResource > option").remove(); - $("#selectResourceToUpload > option").each(function() { - if(!$(this).is(":selected")) { - $("#selectResource").append($(this).clone()); - } - }); + $("#selectResource > option").remove(); + $("#selectResourceToUpload > option").each(function() { + if(!$(this).is(":selected")) { + $("#selectResource").append($(this).clone()); + } + }); } $("#moveBtn").click(function() { @@ -838,34 +857,41 @@ return paths; } + + /** + * position the collection browser to the new path + */ + function positionBrowserToPath(path) { + window.location.href = '/emc-metalnx-web/collections' + path; //relative to domain + } function deleteAction(){ - setOperationInProgress(); - $("#actions button").prop("disabled", true); - $('#actionsWait').show(); - $('#actionLabel').html([[#{collections.empty.trash.status}]]); - $("#uploadIcon").prop("disabled", true); - $("#uploadIcon").addClass("disabled"); - $("#showCollectionFormBtn").prop("disabled", true); - $("#showCollectionFormBtn").addClass("disabled"); - - var paths = findPathsSelected(); - var url = "/emc-metalnx-web/fileOperation/delete/"; - - ajaxEncapsulation( - url, - "POST", - {paths: paths}, - function (data) { - unsetOperationInProgress(); - resetDataTablesStart(); - $("#tree-view-panel-body").html(data); - - } - ); - - $("#deleteModal").modal("hide"); - cleanModals(); + setOperationInProgress(); + $("#actions button").prop("disabled", true); + $('#actionsWait').show(); + $('#actionLabel').html([[#{collections.empty.trash.status}]]); + $("#uploadIcon").prop("disabled", true); + $("#uploadIcon").addClass("disabled"); + $("#showCollectionFormBtn").prop("disabled", true); + $("#showCollectionFormBtn").addClass("disabled"); + + var paths = findPathsSelected(); + var url = "/emc-metalnx-web/fileOperation/delete/"; + + ajaxEncapsulation( + url, + "POST", + {paths: paths}, + function (data) { + unsetOperationInProgress(); + resetDataTablesStart(); + $("#tree-view-panel-body").html(data); + + } + ); + + $("#deleteModal").modal("hide"); + cleanModals(); } $('.modal').on('hidden.bs.modal', function(e){ @@ -946,10 +972,10 @@ $("#table-loader").show(); $("#table-loader").nextAll().remove(); - url = "/emc-metalnx-web/collections/info/"; + url = "/emc-metalnx-web/browse/info/"; ajaxEncapsulation(url, "POST", {path: path}, displayInfoDetails, null, null, null); ajaxEncapsulation( - '/emc-metalnx-web/collections/getBreadCrumbForObject/', + '/emc-metalnx-web/browse/getBreadCrumbForObject/', "POST", {path: path}, function(data){ @@ -964,7 +990,7 @@ } */ function goBackHistory(steps){ ajaxEncapsulation( - '/emc-metalnx-web/collections/goBackHistory/', + '/emc-metalnx-web/browse/goBackHistory/', "POST", {steps: steps}, displaySubDirectories, @@ -973,7 +999,7 @@ } function goForwardHistory(steps){ ajaxEncapsulation( - '/emc-metalnx-web/collections/goForwardHistory/', + '/emc-metalnx-web/browse/goForwardHistory/', "POST", {steps: steps}, displaySubDirectories, @@ -986,7 +1012,7 @@ $('.targetPathInfoSpan').html(targetPath); } - //this function below only wqorks with favorites and user bookmarks table because they have the same number of columns + //this function below only works with favorites and user bookmarks table because they have the same number of columns function modalMoveCopyFavAndUserbookmarkDatatable(datatableId, datatableVar, urlService){ datatableVar = $('#'+datatableId).DataTable( { "serverSide": true, diff --git a/src/emc-metalnx-shared/src/main/resources/views/collections/collectionsBreadCrumb.html b/src/emc-metalnx-shared/src/main/resources/views/collections/collectionsBreadCrumb.html index 8e1b84e8c..ccfc885b7 100755 --- a/src/emc-metalnx-shared/src/main/resources/views/collections/collectionsBreadCrumb.html +++ b/src/emc-metalnx-shared/src/main/resources/views/collections/collectionsBreadCrumb.html @@ -21,20 +21,8 @@ Toggle Dropdown @@ -50,7 +38,7 @@ @@ -70,7 +58,7 @@ @@ -78,7 +66,7 @@ @@ -110,6 +98,7 @@
    +
    diff --git a/src/emc-metalnx-web/src/main/resources/log4j.properties b/src/emc-metalnx-web/src/main/resources/log4j.properties index 1661b6e45..9bb369ef1 100644 --- a/src/emc-metalnx-web/src/main/resources/log4j.properties +++ b/src/emc-metalnx-web/src/main/resources/log4j.properties @@ -26,7 +26,7 @@ log4j.appender.stdout.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1 # Third Party frameworks log4j.logger.org.springframework=WARN log4j.logger.org.thymeleaf=INFO -log4j.logger.org.irods=DEBUG +log4j.logger.org.irods=WARN # logs the SQL statements - set DEBUG for detailed info log4j.logger.org.hibernate.SQL=ERROR diff --git a/src/emc-metalnx-web/src/main/webapp/WEB-INF/applicationContext.xml b/src/emc-metalnx-web/src/main/webapp/WEB-INF/applicationContext.xml index ff6dfbc74..c55f014f0 100755 --- a/src/emc-metalnx-web/src/main/webapp/WEB-INF/applicationContext.xml +++ b/src/emc-metalnx-web/src/main/webapp/WEB-INF/applicationContext.xml @@ -31,8 +31,8 @@ - - file:///C:/Users/hetalben/opt/etc/irods-ext/metalnx.properties + file:/etc/irods-ext/metalnx.properties + @@ -41,8 +41,8 @@ - - + + @@ -82,6 +82,8 @@ It allows theming and custom messages --> + +