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.Entity;
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.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.user.api.User;
import org.sakaiproject.user.api.UserDirectoryService;
import org.sakaiproject.user.api.UserNotDefinedException;
/**
* Entity provider for the Dropbox tool
*/
@CommonsLog
public class DropboxEntityProvider extends AbstractEntityProvider implements EntityProvider, AutoRegisterEntityProvider, ActionsExecutable, Outputable, Describeable {
public final static String ENTITY_PREFIX = "dropbox";
@Override
public String getEntityPrefix() {
return ENTITY_PREFIX;
}
/**
* site/siteId/user/userEid
*/
@EntityCustomAction(action = "site", viewKey = EntityView.VIEW_LIST)
public List<DropboxItem> getDropboxCollectionForSiteAndUser(EntityView view) {
// get siteId
String siteId = view.getPathSegment(2);
// get userId
String userEid = view.getPathSegment(4);
if(log.isDebugEnabled()) {
log.debug("Dropbox for site: " + siteId + " and user: " + userEid);
}
// check siteId and userEid supplied
if (StringUtils.isBlank(siteId) || StringUtils.isBlank(userEid)) {
throw new IllegalArgumentException(
"siteId and userEid must be set in order to get the dropbox for a site, via the URL /dropbox/site/siteId/user/userId");
}
//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.dropbox");
if(toolConfig == null || !toolManager.isVisible(site, toolConfig)) {
throw new EntityNotFoundException("No access to tool in site: " + siteId, siteId);
}
//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);
}
//check user has permission to this dropbox in this site
boolean isAllowed = canAccessDropbox(siteId, userId);
if(!isAllowed) {
throw new SecurityException("No access to site: " + siteId + " and dropbox: " + userEid);
}
//get collectionId for the dropbox
String collectionId = getDropBoxCollectionId(siteId, userId);
//get list of resources in dropbox
List<ContentResource> resources = contentHostingService.getAllResources(collectionId);
List<DropboxItem> dropboxItems = new ArrayList<DropboxItem>();
for(ContentResource resource: resources) {
//convert to our simplified object
DropboxItem item = new DropboxItem();
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());
dropboxItems.add(item);
}
return dropboxItems;
}
@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 item in a user's dropbox
*/
public static class DropboxItem {
@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;
}
/**
* Can the current user actually access the requested dropbox?
* Admin, dropbox.maintain and dropbox.own are allowed
*
* @param siteId - siteId specified
* @param dropboxUserId - userId of the dropbox
* @return
*/
private boolean canAccessDropbox(String siteId, String dropboxUserId) {
String currentUserId = userDirectoryService.getCurrentUser().getId();
//admin
if (securityService.isSuperUser(currentUserId)) {
return true;
}
String siteRef = "";
if(siteId != null && !siteId.startsWith(SiteService.REFERENCE_ROOT)) {
siteRef = SiteService.REFERENCE_ROOT + Entity.SEPARATOR + siteId;
}
//owner - current user must match dropboxid, and have permission in the site
if(StringUtils.equals(currentUserId, dropboxUserId) && securityService.unlock(currentUserId, ContentHostingService.AUTH_DROPBOX_OWN, siteRef)) {
return true;
}
//maintainer, must have permission in the site
if(securityService.unlock(currentUserId, ContentHostingService.AUTH_DROPBOX_MAINTAIN, siteRef)) {
return true;
}
return false;
}
/**
* Get the collection Id for the dropbox
* @param siteId
* @param userId
* @return
*/
private String getDropBoxCollectionId(String siteId, String userId) {
return ContentHostingService.COLLECTION_DROPBOX + siteId + "/" + userId + "/";
}
}