package org.sakaiproject.content.entityproviders; import java.util.ArrayList; import java.util.List; import lombok.Getter; import lombok.Setter; import lombok.extern.apachecommons.CommonsLog; import org.apache.commons.lang.StringUtils; import org.sakaiproject.authz.api.SecurityService; import org.sakaiproject.content.api.ContentHostingService; import org.sakaiproject.content.api.ContentResource; import org.sakaiproject.entity.api.ResourceProperties; import org.sakaiproject.entitybroker.EntityView; import org.sakaiproject.entitybroker.entityprovider.EntityProvider; import org.sakaiproject.entitybroker.entityprovider.annotations.EntityCustomAction; import org.sakaiproject.entitybroker.entityprovider.annotations.EntityId; import org.sakaiproject.entitybroker.entityprovider.annotations.EntityOwner; import org.sakaiproject.entitybroker.entityprovider.annotations.EntityTitle; import org.sakaiproject.entitybroker.entityprovider.capabilities.ActionsExecutable; import org.sakaiproject.entitybroker.entityprovider.capabilities.AutoRegisterEntityProvider; import org.sakaiproject.entitybroker.entityprovider.capabilities.Describeable; import org.sakaiproject.entitybroker.entityprovider.capabilities.Outputable; import org.sakaiproject.entitybroker.entityprovider.extension.Formats; import org.sakaiproject.entitybroker.exception.EntityNotFoundException; import org.sakaiproject.entitybroker.util.AbstractEntityProvider; import org.sakaiproject.exception.IdUnusedException; import org.sakaiproject.exception.PermissionException; import org.sakaiproject.site.api.Site; import org.sakaiproject.site.api.SiteService; import org.sakaiproject.site.api.ToolConfiguration; import org.sakaiproject.tool.api.ToolManager; import org.sakaiproject.tool.cover.SessionManager; import org.sakaiproject.user.api.User; import org.sakaiproject.user.api.UserDirectoryService; import org.sakaiproject.user.api.UserNotDefinedException; /** * Entity provider for the Content / Resources tool */ @CommonsLog public class ContentEntityProvider extends AbstractEntityProvider implements EntityProvider, AutoRegisterEntityProvider, ActionsExecutable, Outputable, Describeable { public final static String ENTITY_PREFIX = "content"; @Override public String getEntityPrefix() { return ENTITY_PREFIX; } /** * * Get a list of resources in a site * * site/siteId */ @EntityCustomAction(action = "site", viewKey = EntityView.VIEW_LIST) public List<ContentItem> getContentCollectionForSite(EntityView view) { // get siteId String siteId = view.getPathSegment(2); if(log.isDebugEnabled()) { log.debug("Content for site: " + siteId); } // check siteId supplied if (StringUtils.isBlank(siteId)) { throw new IllegalArgumentException("siteId a must be set in order to get the resources for a site, via the URL /content/site/siteId"); } return getResources(siteId); } /** * * Get a list of resources in a user's workspace * * user/eid */ @EntityCustomAction(action = "user", viewKey = EntityView.VIEW_LIST) public List<ContentItem> getContentCollectionForUserWorkspace(EntityView view) { // get userEid String userEid = view.getPathSegment(2); if(log.isDebugEnabled()) { log.debug("Content for user workspace: " + userEid); } // check siteId supplied if (StringUtils.isBlank(userEid)) { throw new IllegalArgumentException("eid must be set in order to get the resources for a user's workspace, via the URL /content/user/eid"); } //get Id for user based on supplied eid String userId = null; try { User u = userDirectoryService.getUserByEid(userEid); if(u != null){ userId = u.getId(); } } catch (UserNotDefinedException e) { throw new EntityNotFoundException("Invalid user: " + userEid, userEid); } //get user siteId String siteId = siteService.getUserSiteId(userId); //check user can access this site - specifically check here so we dont expose the site uuid in the main check Site site; try { site = siteService.getSiteVisit(siteId); } catch (IdUnusedException e) { throw new EntityNotFoundException("Invalid user workspace: " + userEid, userEid); } catch (PermissionException e) { throw new EntityNotFoundException("No access to user workspace: " + userEid, userEid); } return getResources(siteId); } /** * * Get a list of resources in the current user's my workspace * * user/eid */ @EntityCustomAction(action = "my", viewKey = EntityView.VIEW_LIST) public List<ContentItem> getContentCollectionForMyWorkspace(EntityView view) { if(log.isDebugEnabled()) { log.debug("Content for my workspace"); } //get user String userId = userDirectoryService.getCurrentUser().getId(); if(StringUtils.isBlank(userId)) { throw new SecurityException("You need to be logged in in order to access your workspace content items."); } //get user siteId String siteId = siteService.getUserSiteId(userId); return getResources(siteId); } /** * Get the list of resources for a site. The API handles visibility checks automatically. * * @param siteId could be normal worksite siteid or my workspace siteid * @return */ private List<ContentItem> getResources(String siteId) { //check user can access this site Site site; try { site = siteService.getSiteVisit(siteId); } catch (IdUnusedException e) { throw new EntityNotFoundException("Invalid siteId: " + siteId, siteId); } catch (PermissionException e) { throw new EntityNotFoundException("No access to site: " + siteId, siteId); } //check user can access the tool, it might be hidden ToolConfiguration toolConfig = site.getToolForCommonId("sakai.resources"); if(toolConfig == null || !toolManager.isVisible(site, toolConfig)) { throw new EntityNotFoundException("No access to tool in site: " + siteId, siteId); } //get the items List<ContentItem> items = new ArrayList<ContentItem>(); String currentSiteCollectionId = contentHostingService.getSiteCollection(siteId); log.debug("currentSiteCollectionId: " + currentSiteCollectionId); List<ContentResource> resources = contentHostingService.getAllResources(currentSiteCollectionId); for(ContentResource resource: resources) { //convert to our simplified object ContentItem item = new ContentItem(); ResourceProperties props = resource.getProperties(); item.setTitle(props.getProperty(ResourceProperties.PROP_DISPLAY_NAME)); item.setDescription(props.getProperty(ResourceProperties.PROP_DESCRIPTION)); item.setType(props.getProperty(ResourceProperties.PROP_CONTENT_TYPE)); item.setSize(Long.parseLong(props.getProperty(ResourceProperties.PROP_CONTENT_LENGTH))); item.setUrl(resource.getUrl()); item.setAuthor(getDisplayName(props.getProperty(ResourceProperties.PROP_CREATOR))); item.setModifiedDate(props.getProperty(ResourceProperties.PROP_MODIFIED_DATE)); item.setContainer(resource.getContainingCollection().getReference()); items.add(item); } return items; } @Override public String[] getHandledOutputFormats() { return new String[] { Formats.XML, Formats.JSON}; } @Setter private ContentHostingService contentHostingService; @Setter private SiteService siteService; @Setter private ToolManager toolManager; @Setter private SecurityService securityService; @Setter private UserDirectoryService userDirectoryService; /** * Simplified helper class to represent an individual content item */ public static class ContentItem { @Getter @Setter private String title; @Getter @Setter private String description; @Getter @Setter private String url; @Getter @Setter private String type; @Getter @Setter private long size; @Getter @Setter private String author; @Getter @Setter private String modifiedDate; @Getter @Setter private String container; } /** * Helper to get the displayname for a user. * @param uuid uuid of the user * @return displayname or null. We dont want to expose the uuid. */ private String getDisplayName(String uuid) { try { return userDirectoryService.getUser(uuid).getDisplayName(); } catch (UserNotDefinedException e) { //dont throw, return null return null; } } }