Java tutorial
/********************************************************************************** * $URL: $ * $Id: $ *********************************************************************************** * * Copyright (c) 2006, 2007, 2008, 2009 The Sakai Foundation * * Licensed under the Educational Community 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.opensource.org/licenses/ECL-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 org.sakaiproject.content.tool; import java.io.IOException; import java.io.InputStream; import java.io.UnsupportedEncodingException; import java.io.File; import java.net.MalformedURLException; import java.net.URI; import java.net.URL; import java.net.URLDecoder; import java.text.Format; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Date; import java.util.Enumeration; import java.util.HashMap; import java.util.List; import java.util.Properties; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.PrintWriter; import org.apache.commons.fileupload.disk.DiskFileItem; import org.apache.commons.lang.StringUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.sakaiproject.cheftool.Context; import org.sakaiproject.cheftool.JetspeedRunData; import org.sakaiproject.cheftool.RunData; import org.sakaiproject.cheftool.VelocityPortlet; import org.sakaiproject.cheftool.VelocityPortletPaneledAction; import org.sakaiproject.component.cover.ComponentManager; import org.sakaiproject.component.cover.ServerConfigurationService; import org.sakaiproject.content.api.*; import org.sakaiproject.content.api.GroupAwareEntity.AccessMode; import org.sakaiproject.content.cover.ContentHostingService; import org.sakaiproject.entity.api.Entity; import org.sakaiproject.entity.api.ResourceProperties; import org.sakaiproject.entity.api.ResourcePropertiesEdit; import org.sakaiproject.event.api.SessionState; import org.sakaiproject.event.cover.NotificationService; import org.sakaiproject.exception.IdUnusedException; import org.sakaiproject.exception.IdUsedException; import org.sakaiproject.exception.InUseException; import org.sakaiproject.exception.OverQuotaException; import org.sakaiproject.exception.IdUniquenessException; import org.sakaiproject.exception.ServerOverloadException; import org.sakaiproject.site.api.Site; import org.sakaiproject.site.cover.SiteService; import org.sakaiproject.time.api.Time; import org.sakaiproject.time.cover.TimeService; import org.sakaiproject.tool.api.Placement; import org.sakaiproject.tool.api.Tool; import org.sakaiproject.tool.api.ToolException; import org.sakaiproject.tool.api.ToolSession; import org.sakaiproject.tool.cover.SessionManager; import org.sakaiproject.tool.cover.ToolManager; import org.sakaiproject.util.FileItem; import org.sakaiproject.util.FormattedText; import org.sakaiproject.util.ParameterParser; import org.sakaiproject.util.ResourceLoader; import org.sakaiproject.util.Validator; import org.sakaiproject.event.cover.EventTrackingService; import org.sakaiproject.event.api.NotificationEdit; public class ResourcesHelperAction extends VelocityPortletPaneledAction { /** the logger for this class */ private static final Log logger = LogFactory.getLog(ResourcesHelperAction.class); private static final ResourceConditionsHelper conditionsHelper = new ResourceConditionsHelper(); /** Resource bundle using current language locale */ private static ResourceLoader rb = new ResourceLoader("types"); private static ResourceLoader metaLang = new ResourceLoader("metadata"); private static ResourceLoader contentResourceBundle = new ResourceLoader("content"); protected static final String ACCESS_HTML_TEMPLATE = "resources/sakai_access_html"; protected static final String ACCESS_TEXT_TEMPLATE = "resources/sakai_access_text"; protected static final String ACCESS_UPLOAD_TEMPLATE = "resources/sakai_access_upload"; protected static final String ACCESS_URL_TEMPLATE = "resources/sakai_access_url"; /** copyright path -- MUST have same value as AccessServlet.COPYRIGHT_PATH */ public static final String COPYRIGHT_PATH = Entity.SEPARATOR + "copyright"; private static final String COPYRIGHT_ALERT_URL = ServerConfigurationService.getAccessUrl() + COPYRIGHT_PATH; protected static final String CREATE_FOLDERS_TEMPLATE = "resources/sakai_create_folders"; protected static final String CREATE_HTML_TEMPLATE = "resources/sakai_create_html"; protected static final String CREATE_TEXT_TEMPLATE = "resources/sakai_create_text"; protected static final String CREATE_UPLOAD_TEMPLATE = "resources/sakai_create_upload"; protected static final String CREATE_UPLOADS_TEMPLATE = "resources/sakai_create_uploads"; protected static final String CREATE_URL_TEMPLATE = "resources/sakai_create_url"; protected static final String CREATE_URLS_TEMPLATE = "resources/sakai_create_urls"; public static final String MODE_MAIN = "main"; protected static final String PREFIX = "ResourceTypeHelper."; protected static final String REVISE_HTML_TEMPLATE = "resources/sakai_revise_html"; protected static final String REVISE_TEXT_TEMPLATE = "resources/sakai_revise_text"; protected static final String REVISE_UPLOAD_TEMPLATE = "resources/sakai_revise_upload"; protected static final String REVISE_URL_TEMPLATE = "resources/sakai_revise_url"; protected static final String REPLACE_CONTENT_TEMPLATE = "resources/sakai_replace_file"; protected static final String MAKE_SITE_PAGE_TEMPLATE = "content/sakai_make_site_page"; protected static final String ERROR_PAGE_TEMPLATE = "resources/sakai_error_page"; /** The content type image lookup service in the State. */ private static final String STATE_CONTENT_TYPE_IMAGE_SERVICE = PREFIX + "content_type_image_service"; private static final String STATE_COPYRIGHT_FAIRUSE_URL = PREFIX + "copyright_fairuse_url"; private static final String STATE_COPYRIGHT_NEW_COPYRIGHT = PREFIX + "new_copyright"; /** copyright related info */ private static final String STATE_COPYRIGHT_TYPES = PREFIX + "copyright_types"; private static final String STATE_DEFAULT_COPYRIGHT = PREFIX + "default_copyright"; private static final String STATE_DEFAULT_COPYRIGHT_ALERT = PREFIX + "default_copyright_alert"; /** state attribute for the maximum size for file upload */ static final String STATE_FILE_UPLOAD_MAX_SIZE = PREFIX + "file_upload_max_size"; /** The user copyright string */ private static final String STATE_MY_COPYRIGHT = PREFIX + "mycopyright"; private static final String STATE_NEW_COPYRIGHT_INPUT = PREFIX + "new_copyright_input"; /** state attribute indicating whether users in current site should be denied option of making resources public */ private static final String STATE_PREVENT_PUBLIC_DISPLAY = PREFIX + "prevent_public_display"; /** state attribute indicating whether we're using the Creative Commons dialog instead of the "old" copyright dialog */ protected static final String STATE_USING_CREATIVE_COMMONS = PREFIX + "usingCreativeCommons"; /** name of state attribute for the default retract time */ protected static final String STATE_DEFAULT_RETRACT_TIME = PREFIX + "default_retract_time"; /** The title of the new page to be created in the site */ protected static final String STATE_PAGE_TITLE = PREFIX + "page_title"; /** Tool property to enable Drag and Drop uploads in a per-tool basis */ private static final String TOOL_PROP_DRAGNDROP_ENABLED = "content.upload.dragndrop"; /** We need to send a single email with every D&D upload reported in it */ private static final String DRAGNDROP_FILENAME_REFERENCE_LIST = "dragndrop_filename_reference_list"; private NotificationService notificationService = (NotificationService) ComponentManager .get(NotificationService.class); private EventTrackingService eventTrackingService = (EventTrackingService) ComponentManager .get(EventTrackingService.class); public String buildAccessContext(VelocityPortlet portlet, Context context, RunData data, SessionState state) { logger.debug(this + ".buildAccessContext()"); String template = ACCESS_TEXT_TEMPLATE; return template; } public String buildCreateContext(VelocityPortlet portlet, Context context, RunData data, SessionState state) { logger.debug(this + ".buildCreateContext()"); String template = CREATE_UPLOAD_TEMPLATE; ToolSession toolSession = SessionManager.getCurrentToolSession(); ResourceToolActionPipe pipe = (ResourceToolActionPipe) toolSession .getAttribute(ResourceToolAction.ACTION_PIPE); context.put(ResourcesAction.PIPE_INIT_ID, pipe.getInitializationId()); //Reference reference = (Reference) toolSession.getAttribute(ResourceToolAction.COLLECTION_REFERENCE); String typeId = pipe.getAction().getTypeId(); ListItem parent = new ListItem(pipe.getContentEntity()); if (parent.isDropbox) { String dropboxNotificationsProperty = getDropboxNotificationsProperty(); context.put("dropboxNotificationAllowed", Boolean .valueOf(ResourcesAction.DROPBOX_NOTIFICATIONS_ALLOW.equals(dropboxNotificationsProperty))); } if (ResourceType.TYPE_TEXT.equals(typeId)) { template = CREATE_TEXT_TEMPLATE; } else if (ResourceType.TYPE_HTML.equals(typeId)) { template = CREATE_HTML_TEMPLATE; } else if (ResourceType.TYPE_URL.equals(typeId)) { template = CREATE_URL_TEMPLATE; } else // assume ResourceType.TYPE_UPLOAD { template = CREATE_UPLOAD_TEMPLATE; } int requestStateId = ResourcesAction.preserveRequestState(state, new String[] { ResourcesAction.PREFIX + ResourcesAction.REQUEST }); context.put("requestStateId", requestStateId); return template; } public String buildMainPanelContext(VelocityPortlet portlet, Context context, RunData data, SessionState state) { logger.debug(this + ".buildMainPanelContext()"); // context.put("sysout", System.out); context.put("tlang", rb); context.put("metaLang", metaLang); context.put("validator", new Validator()); context.put("copyright_alert_url", COPYRIGHT_ALERT_URL); context.put("DOT", ListItem.DOT); context.put("calendarMap", new HashMap()); String ezproxy = ServerConfigurationService.getString("content.ezproxy.prefix", ""); if (ezproxy != null && ezproxy != "") { context.put("ezproxyPrefix", ezproxy); } else { context.put("ezproxyPrefix", false); } context.put("dateFormat", getDateFormatString()); String mode = (String) state.getAttribute(ResourceToolAction.STATE_MODE); if (mode == null) { initHelper(portlet, context, data, state); } if (state.getAttribute(ResourcesAction.STATE_MESSAGE) != null) { context.put("itemAlertMessage", state.getAttribute(ResourcesAction.STATE_MESSAGE)); state.removeAttribute(ResourcesAction.STATE_MESSAGE); } ContentTypeImageService contentTypeImageService = (ContentTypeImageService) state .getAttribute(STATE_CONTENT_TYPE_IMAGE_SERVICE); context.put("contentTypeImageService", contentTypeImageService); ToolSession toolSession = SessionManager.getCurrentToolSession(); ResourceToolActionPipe pipe = (ResourceToolActionPipe) toolSession .getAttribute(ResourceToolAction.ACTION_PIPE); if (pipe == null) { String attributes = "ResourcesHelperAction.buildMainPanelContext() SAK-8449 dump of state.attributes:\n"; List<String> attrNames = state.getAttributeNames(); for (String attrName : attrNames) { Object val = state.getAttribute(attrName); if (val instanceof Collection) { int i = 0; for (Object obj : (Collection) val) { attributes += "\t" + attrName + "[" + i + "] ==> " + obj + "\n"; i++; } } else { attributes += "\t" + attrName + " ==> " + val + "\n"; } } attributes += "ResourcesHelperAction.buildMainPanelContext() SAK-8449 dump of toolSession.attributes:\n"; Enumeration toolNames = toolSession.getAttributeNames(); while (toolNames.hasMoreElements()) { String name = (String) toolNames.nextElement(); Object val = toolSession.getAttribute(name); if (val instanceof Collection) { int i = 0; for (Object obj : (Collection) val) { attributes += "\t" + name + "[" + i + "] ==> " + obj + "\n"; i++; } } else { attributes += "\t" + name + " ==> " + val + "\n"; } } logger.debug(attributes, new Throwable()); return ERROR_PAGE_TEMPLATE; } if (pipe.isActionCompleted()) { return null; } context.put(ResourcesAction.PIPE_INIT_ID, pipe.getInitializationId()); String actionId = pipe.getAction().getId(); context.put("GROUP_ACCESS", AccessMode.GROUPED); context.put("SITE_ACCESS", AccessMode.SITE); context.put("INHERITED_ACCESS", AccessMode.INHERITED); context.put("TYPE_FOLDER", ResourceType.TYPE_FOLDER); context.put("TYPE_HTML", ResourceType.TYPE_HTML); context.put("TYPE_TEXT", ResourceType.TYPE_TEXT); context.put("TYPE_UPLOAD", ResourceType.TYPE_UPLOAD); context.put("TYPE_URL", ResourceType.TYPE_URL); String template = ""; switch (pipe.getAction().getActionType()) { case CREATE: template = buildCreateContext(portlet, context, data, state); break; case REVISE_CONTENT: template = buildReviseContext(portlet, context, data, state); break; case REPLACE_CONTENT: template = buildReplaceContext(portlet, context, data, state); break; case NEW_UPLOAD: template = buildUploadFilesContext(portlet, context, data, state); break; case NEW_FOLDER: template = buildNewFoldersContext(portlet, context, data, state); break; case NEW_URLS: template = buildNewUrlsContext(portlet, context, data, state); break; default: // hmmmm logger.info(this + "hmmm"); template = buildMakeSitePageContext(portlet, context, data, state); break; } return template; } public String buildMakeSitePageContext(VelocityPortlet portlet, Context context, RunData data, SessionState state) { logger.debug(this + ".buildMakeSitePage()"); int requestStateId = ResourcesAction.preserveRequestState(state, new String[] { ResourcesAction.PREFIX + ResourcesAction.REQUEST }); context.put("requestStateId", requestStateId); context.put("page", state.getAttribute(STATE_PAGE_TITLE)); return MAKE_SITE_PAGE_TEMPLATE; } protected String buildNewUrlsContext(VelocityPortlet portlet, Context context, RunData data, SessionState state) { logger.debug(this + ".buildNewUrlsContext()"); context.put("site_id", ToolManager.getCurrentPlacement().getContext()); ToolSession toolSession = SessionManager.getCurrentToolSession(); MultiFileUploadPipe pipe = (MultiFileUploadPipe) toolSession.getAttribute(ResourceToolAction.ACTION_PIPE); context.put(ResourcesAction.PIPE_INIT_ID, pipe.getInitializationId()); List<ResourceToolActionPipe> pipes = pipe.getPipes(); Time defaultRetractDate = (Time) state.getAttribute(STATE_DEFAULT_RETRACT_TIME); if (defaultRetractDate == null) { defaultRetractDate = TimeService.newTime(); state.setAttribute(STATE_DEFAULT_RETRACT_TIME, defaultRetractDate); } Boolean preventPublicDisplay = (Boolean) state.getAttribute(STATE_PREVENT_PUBLIC_DISPLAY); if (preventPublicDisplay == null) { preventPublicDisplay = Boolean.FALSE; state.setAttribute(STATE_PREVENT_PUBLIC_DISPLAY, preventPublicDisplay); } ListItem parent = new ListItem(pipe.getContentEntity()); parent.setPubviewPossible(!preventPublicDisplay); ListItem model = new ListItem(pipe, parent, defaultRetractDate); model.initMetadataGroups(); // model.setPubviewPossible(! preventPublicDisplay); context.put("model", model); context.put("type", model.getResourceTypeDef()); context.put("pipes", pipes); if (ContentHostingService.isAvailabilityEnabled()) { context.put("availability_is_enabled", Boolean.TRUE); } if (model.isDropbox) { String dropboxNotificationsProperty = getDropboxNotificationsProperty(); context.put("dropboxNotificationAllowed", Boolean .valueOf(ResourcesAction.DROPBOX_NOTIFICATIONS_ALLOW.equals(dropboxNotificationsProperty))); } String ezproxy = ServerConfigurationService.getString("content.ezproxy.prefix", ""); if (ezproxy != null && ezproxy != "") { context.put("ezproxyPrefix", ezproxy); } else { context.put("ezproxyPrefix", false); } ResourcesAction.copyrightChoicesIntoContext(state, context); ResourcesAction.publicDisplayChoicesIntoContext(state, context); ResourceConditionsHelper.buildConditionContext(context, state); int requestStateId = ResourcesAction.preserveRequestState(state, new String[] { ResourcesAction.PREFIX + ResourcesAction.REQUEST }); context.put("requestStateId", requestStateId); return CREATE_URLS_TEMPLATE; } /** * @param portlet * @param context * @param data * @param state * @return */ private String buildNewFoldersContext(VelocityPortlet portlet, Context context, RunData data, SessionState state) { logger.debug(this + ".buildNewFoldersContext()"); context.put("site_id", ToolManager.getCurrentPlacement().getContext()); ToolSession toolSession = SessionManager.getCurrentToolSession(); MultiFileUploadPipe pipe = (MultiFileUploadPipe) toolSession.getAttribute(ResourceToolAction.ACTION_PIPE); context.put(ResourcesAction.PIPE_INIT_ID, pipe.getInitializationId()); List<ResourceToolActionPipe> pipes = pipe.getPipes(); Time defaultRetractDate = (Time) state.getAttribute(STATE_DEFAULT_RETRACT_TIME); if (defaultRetractDate == null) { defaultRetractDate = TimeService.newTime(); state.setAttribute(STATE_DEFAULT_RETRACT_TIME, defaultRetractDate); } Boolean preventPublicDisplay = (Boolean) state.getAttribute(STATE_PREVENT_PUBLIC_DISPLAY); if (preventPublicDisplay == null) { preventPublicDisplay = Boolean.FALSE; state.setAttribute(STATE_PREVENT_PUBLIC_DISPLAY, preventPublicDisplay); } ListItem parent = new ListItem(pipe.getContentEntity()); parent.setPubviewPossible(!preventPublicDisplay); ListItem model = new ListItem(pipe, parent, defaultRetractDate); model.initMetadataGroups(); // model.setPubviewPossible(! preventPublicDisplay); context.put("model", model); context.put("type", model.getResourceTypeDef()); context.put("pipes", pipes); if (ContentHostingService.isAvailabilityEnabled()) { context.put("availability_is_enabled", Boolean.TRUE); } ResourcesAction.publicDisplayChoicesIntoContext(state, context); ResourceConditionsHelper.buildConditionContext(context, state); int requestStateId = ResourcesAction.preserveRequestState(state, new String[] { ResourcesAction.PREFIX + ResourcesAction.REQUEST }); context.put("requestStateId", requestStateId); return CREATE_FOLDERS_TEMPLATE; } /** * @param portlet * @param context * @param data * @param state * @return */ protected String buildReplaceContext(VelocityPortlet portlet, Context context, RunData data, SessionState state) { logger.debug(this + ".buildReplaceContext()"); ToolSession toolSession = SessionManager.getCurrentToolSession(); ResourceToolActionPipe pipe = (ResourceToolActionPipe) toolSession .getAttribute(ResourceToolAction.ACTION_PIPE); context.put(ResourcesAction.PIPE_INIT_ID, pipe.getInitializationId()); Boolean preventPublicDisplay = (Boolean) state.getAttribute(STATE_PREVENT_PUBLIC_DISPLAY); if (preventPublicDisplay == null) { preventPublicDisplay = Boolean.FALSE; state.setAttribute(STATE_PREVENT_PUBLIC_DISPLAY, preventPublicDisplay); } ListItem item = new ListItem(pipe.getContentEntity()); item.setPubviewPossible(!preventPublicDisplay); if (item.isDropbox) { String dropboxNotificationsProperty = getDropboxNotificationsProperty(); context.put("dropboxNotificationAllowed", Boolean .valueOf(ResourcesAction.DROPBOX_NOTIFICATIONS_ALLOW.equals(dropboxNotificationsProperty))); } context.put("item", item); int requestStateId = ResourcesAction.preserveRequestState(state, new String[] { ResourcesAction.PREFIX + ResourcesAction.REQUEST }); context.put("requestStateId", requestStateId); return REPLACE_CONTENT_TEMPLATE; } public String buildReviseContext(VelocityPortlet portlet, Context context, RunData data, SessionState state) { logger.debug(this + ".buildReviseContext()"); String template = REVISE_TEXT_TEMPLATE; ToolSession toolSession = SessionManager.getCurrentToolSession(); ResourceToolActionPipe pipe = (ResourceToolActionPipe) toolSession .getAttribute(ResourceToolAction.ACTION_PIPE); context.put(ResourcesAction.PIPE_INIT_ID, pipe.getInitializationId()); //Reference reference = (Reference) toolSession.getAttribute(ResourceToolAction.COLLECTION_REFERENCE); String typeId = pipe.getAction().getTypeId(); String mimetype = pipe.getMimeType(); ListItem item = new ListItem(pipe.getContentEntity()); context.put("item", item); // context.put("inDropbox", ContentHostingService.isInDropbox(pipe.getContentEntity().getId())); ResourceTypeRegistry registry = (ResourceTypeRegistry) ComponentManager.get(ResourceTypeRegistry.class); if (registry != null) { ResourceType typedef = registry.getType(typeId); if (typedef != null) { context.put("hasNotificationDialog", typedef.hasNotificationDialog()); } } if (item.isDropbox) { String dropboxNotificationsProperty = getDropboxNotificationsProperty(); context.put("dropboxNotificationAllowed", Boolean .valueOf(ResourcesAction.DROPBOX_NOTIFICATIONS_ALLOW.equals(dropboxNotificationsProperty))); } context.put("pipe", pipe); if (ResourceType.TYPE_TEXT.equals(typeId)) { template = REVISE_TEXT_TEMPLATE; } else if (ResourceType.TYPE_HTML.equals(typeId)) { template = REVISE_HTML_TEMPLATE; } else if (ResourceType.TYPE_URL.equals(typeId)) { String decodedUrl = pipe.getContentstring(); try { decodedUrl = URLDecoder.decode(pipe.getContentstring(), "UTF-8"); } catch (Exception e) { //cant decode, continue anyway with original string } context.put("decodedUrl", decodedUrl); template = REVISE_URL_TEMPLATE; } else if (ResourceType.TYPE_UPLOAD.equals(typeId) && mimetype != null && ResourceType.MIME_TYPE_HTML.equals(mimetype)) { template = REVISE_HTML_TEMPLATE; } else if (ResourceType.TYPE_UPLOAD.equals(typeId) && mimetype != null && ResourceType.MIME_TYPE_TEXT.equals(mimetype)) { template = REVISE_TEXT_TEMPLATE; } else // assume ResourceType.TYPE_UPLOAD { template = REVISE_UPLOAD_TEMPLATE; } int requestStateId = ResourcesAction.preserveRequestState(state, new String[] { ResourcesAction.PREFIX + ResourcesAction.REQUEST }); context.put("requestStateId", requestStateId); return template; } /** * @param portlet * @param context * @param data * @param state * @return */ protected String buildUploadFilesContext(VelocityPortlet portlet, Context context, RunData data, SessionState state) { logger.debug(this + ".buildUploadFilesContext()"); ToolSession toolSession = SessionManager.getCurrentToolSession(); context.put("site_id", ToolManager.getCurrentPlacement().getContext()); String max_file_size_mb = (String) state.getAttribute(STATE_FILE_UPLOAD_MAX_SIZE); if (max_file_size_mb == null) { max_file_size_mb = "20"; } context.put("uploadMaxSize", max_file_size_mb); String uploadMax = ServerConfigurationService.getString(ResourcesConstants.SAK_PROP_MAX_UPLOAD_FILE_SIZE); String instr_uploads = rb.getFormattedMessage("instr.uploads", new String[] { uploadMax }); context.put("instr_uploads", instr_uploads); String instr_dnd_uploads = rb.getFormattedMessage("instr.dnd.uploads", new String[] { uploadMax }); context.put("instr_dnd_uploads", instr_dnd_uploads); Boolean dragAndDrop = ServerConfigurationService.getBoolean("content.upload.dragndrop", true); String strDragAndDropEnabled = ToolManager.getCurrentPlacement().getConfig() .getProperty(TOOL_PROP_DRAGNDROP_ENABLED); if (StringUtils.isNotBlank(strDragAndDropEnabled)) { dragAndDrop = dragAndDrop || (new Boolean(strDragAndDropEnabled)); } context.put("dragAndDrop", dragAndDrop); // int max_bytes = 1024 * 1024; // try // { // max_bytes = Integer.parseInt(max_file_size_mb) * 1024 * 1024; // } // catch(Exception e) // { // // if unable to parse an integer from the value // // in the properties file, use 1 MB as a default // max_file_size_mb = "1"; // max_bytes = 1024 * 1024; // } MultiFileUploadPipe pipe = (MultiFileUploadPipe) toolSession.getAttribute(ResourceToolAction.ACTION_PIPE); context.put(ResourcesAction.PIPE_INIT_ID, pipe.getInitializationId()); List<ResourceToolActionPipe> pipes = pipe.getPipes(); Time defaultRetractDate = (Time) state.getAttribute(STATE_DEFAULT_RETRACT_TIME); if (defaultRetractDate == null) { defaultRetractDate = TimeService.newTime(); state.setAttribute(STATE_DEFAULT_RETRACT_TIME, defaultRetractDate); } Boolean preventPublicDisplay = (Boolean) state.getAttribute(STATE_PREVENT_PUBLIC_DISPLAY); if (preventPublicDisplay == null) { preventPublicDisplay = Boolean.FALSE; state.setAttribute(STATE_PREVENT_PUBLIC_DISPLAY, preventPublicDisplay); } ListItem parent = new ListItem(pipe.getContentEntity()); parent.setPubviewPossible(!preventPublicDisplay); ListItem model = new ListItem(pipe, parent, defaultRetractDate); model.initMetadataGroups(); // model.setPubviewPossible(! preventPublicDisplay); context.put("model", model); context.put("type", model.getResourceTypeDef()); context.put("pipes", pipes); if (ContentHostingService.isAvailabilityEnabled()) { context.put("availability_is_enabled", Boolean.TRUE); } if (model.isDropbox) { String dropboxNotificationsProperty = getDropboxNotificationsProperty(); context.put("dropboxNotificationAllowed", Boolean .valueOf(ResourcesAction.DROPBOX_NOTIFICATIONS_ALLOW.equals(dropboxNotificationsProperty))); } ResourcesAction.copyrightChoicesIntoContext(state, context); ResourcesAction.publicDisplayChoicesIntoContext(state, context); String defaultCopyrightStatus = (String) state.getAttribute(STATE_DEFAULT_COPYRIGHT); if (defaultCopyrightStatus == null || defaultCopyrightStatus.trim().equals("")) { defaultCopyrightStatus = ServerConfigurationService.getString("default.copyright"); state.setAttribute(STATE_DEFAULT_COPYRIGHT, defaultCopyrightStatus); } context.put("defaultCopyrightStatus", defaultCopyrightStatus); ResourceConditionsHelper.buildConditionContext(context, state); int requestStateId = ResourcesAction.preserveRequestState(state, new String[] { ResourcesAction.PREFIX + ResourcesAction.REQUEST }); context.put("requestStateId", requestStateId); return CREATE_UPLOADS_TEMPLATE; } public void doFinishUpload(RunData data) { ToolSession toolSession = SessionManager.getCurrentToolSession(); ResourceToolActionPipe pipe = (ResourceToolActionPipe) toolSession .getAttribute(ResourceToolAction.ACTION_PIPE); if (pipe != null) { pipe.setActionCanceled(false); pipe.setErrorEncountered(false); pipe.setActionCompleted(true); } logger.debug(this + ".doFinishUpload() finished action"); toolSession.setAttribute(ResourceToolAction.DONE, Boolean.TRUE); } public void doCancel(RunData data) { logger.debug(this + ".doCancel()"); SessionState state = ((JetspeedRunData) data).getPortletSessionState(((JetspeedRunData) data).getJs_peid()); ParameterParser params = data.getParameters(); ToolSession toolSession = SessionManager.getCurrentToolSession(); int requestStateId = params.getInt("requestStateId", 0); ResourcesAction.restoreRequestState(state, new String[] { ResourcesAction.PREFIX + ResourcesAction.REQUEST }, requestStateId); //Tool tool = ToolManager.getCurrentTool(); //String url = (String) toolSession.getAttribute(tool.getId() + Tool.HELPER_DONE_URL); //toolSession.removeAttribute(tool.getId() + Tool.HELPER_DONE_URL); ResourceToolActionPipe pipe = (ResourceToolActionPipe) toolSession .getAttribute(ResourceToolAction.ACTION_PIPE); if (pipe != null) { String pipe_init_id = pipe.getInitializationId(); String response_init_id = params.getString(ResourcesAction.PIPE_INIT_ID); if (pipe_init_id == null || response_init_id == null || !response_init_id.equalsIgnoreCase(pipe_init_id)) { pipe.setErrorEncountered(true); pipe.setActionCanceled(false); } else { pipe.setErrorEncountered(false); pipe.setActionCanceled(true); } pipe.setActionCompleted(false); toolSession.setAttribute(ResourceToolAction.DONE, Boolean.TRUE); } } public void doContinue(RunData data) { logger.debug(this + ".doContinue()"); SessionState state = ((JetspeedRunData) data).getPortletSessionState(((JetspeedRunData) data).getJs_peid()); ParameterParser params = data.getParameters(); int requestStateId = params.getInt("requestStateId", 0); ResourcesAction.restoreRequestState(state, new String[] { ResourcesAction.PREFIX + ResourcesAction.REQUEST }, requestStateId); String content = params.getString("content"); if (content == null) { addAlert(state, rb.getString("text.notext")); return; } ToolSession toolSession = SessionManager.getCurrentToolSession(); // Tool tool = ToolManager.getCurrentTool(); // String url = (String) toolSession.getAttribute(tool.getId() + Tool.HELPER_DONE_URL); // toolSession.removeAttribute(tool.getId() + Tool.HELPER_DONE_URL); ResourceToolActionPipe pipe = (ResourceToolActionPipe) toolSession .getAttribute(ResourceToolAction.ACTION_PIPE); if (pipe == null) { return; } if (pipe != null) { String pipe_init_id = pipe.getInitializationId(); String response_init_id = params.getString(ResourcesAction.PIPE_INIT_ID); if (pipe_init_id == null || response_init_id == null || !response_init_id.equalsIgnoreCase(pipe_init_id)) { // in this case, prevent upload to wrong folder pipe.setErrorMessage(rb.getString("alert.try-again")); pipe.setActionCanceled(false); pipe.setErrorEncountered(true); pipe.setActionCompleted(false); return; } toolSession.setAttribute(ResourceToolAction.ACTION_PIPE, pipe); } String resourceType = pipe.getAction().getTypeId(); String mimetype = pipe.getMimeType(); ListItem item = new ListItem(pipe.getContentEntity()); // notification int noti = determineNotificationPriority(params, item.isDropbox, item.userIsMaintainer()); pipe.setRevisedMimeType(pipe.getMimeType()); if (ResourceType.TYPE_TEXT.equals(resourceType) || ResourceType.MIME_TYPE_TEXT.equals(mimetype)) { pipe.setRevisedMimeType(ResourceType.MIME_TYPE_TEXT); pipe.setRevisedResourceProperty(ResourceProperties.PROP_CONTENT_ENCODING, ResourcesAction.UTF_8_ENCODING); pipe.setNotification(noti); } else if (ResourceType.TYPE_HTML.equals(resourceType) || ResourceType.MIME_TYPE_HTML.equals(mimetype)) { StringBuilder alertMsg = new StringBuilder(); content = FormattedText.processHtmlDocument(content, alertMsg); pipe.setRevisedMimeType(ResourceType.MIME_TYPE_HTML); pipe.setRevisedResourceProperty(ResourceProperties.PROP_CONTENT_ENCODING, ResourcesAction.UTF_8_ENCODING); pipe.setNotification(noti); if (alertMsg.length() > 0) { addAlert(state, alertMsg.toString()); return; } } else if (ResourceType.TYPE_URL.equals(resourceType)) { // SAK-23587 - properly escape the URL where required try { URL url = new URL(content); URI uri = new URI(url.getProtocol(), url.getUserInfo(), url.getHost(), url.getPort(), url.getPath(), url.getQuery(), url.getRef()); content = uri.toString(); } catch (Exception e) { //ok to ignore, just use the original url logger.debug("URL can not be encoded: " + e.getClass() + ":" + e.getCause()); } pipe.setRevisedMimeType(ResourceType.MIME_TYPE_URL); pipe.setNotification(noti); } else if (ResourceType.TYPE_FOLDER.equals(resourceType)) { MultiFileUploadPipe mfp = (MultiFileUploadPipe) pipe; int count = params.getInt("folderCount"); mfp.setFileCount(count); List<ResourceToolActionPipe> pipes = mfp.getPipes(); for (int i = 0; i < pipes.size(); i++) { ResourceToolActionPipe fp = pipes.get(i); String folderName = params.getString("folder" + (i + 1)); fp.setFileName(folderName); fp.setNotification(noti); } } try { pipe.setRevisedContent(content.getBytes(ResourcesAction.UTF_8_ENCODING)); pipe.setActionCanceled(false); pipe.setErrorEncountered(false); pipe.setActionCompleted(true); } catch (UnsupportedEncodingException e) { logger.warn(this + ": " + e.toString()); addAlert(state, rb.getString("alert.utf8encoding")); pipe.setActionCanceled(false); pipe.setErrorEncountered(true); pipe.setActionCompleted(false); } toolSession.setAttribute(ResourceToolAction.DONE, Boolean.TRUE); } public void doCreateFolders(RunData data) { logger.debug(this + ".doCreateFolders()"); SessionState state = ((JetspeedRunData) data).getPortletSessionState(((JetspeedRunData) data).getJs_peid()); ParameterParser params = data.getParameters(); ToolSession toolSession = SessionManager.getCurrentToolSession(); int requestStateId = params.getInt("requestStateId", 0); ResourcesAction.restoreRequestState(state, new String[] { ResourcesAction.PREFIX + ResourcesAction.REQUEST }, requestStateId); MultiFileUploadPipe pipe = (MultiFileUploadPipe) toolSession.getAttribute(ResourceToolAction.ACTION_PIPE); if (pipe == null) { return; } String pipe_init_id = pipe.getInitializationId(); String response_init_id = params.getString(ResourcesAction.PIPE_INIT_ID); if (pipe_init_id == null || response_init_id == null || !response_init_id.equalsIgnoreCase(pipe_init_id)) { // in this case, prevent upload to wrong folder pipe.setErrorMessage(rb.getString("alert.try-again")); pipe.setActionCanceled(false); pipe.setErrorEncountered(true); pipe.setActionCompleted(false); return; } String resourceType = pipe.getAction().getTypeId(); int count = params.getInt("fileCount"); pipe.setFileCount(count); int lastIndex = params.getInt("lastIndex"); ContentEntity entity = pipe.getContentEntity(); ListItem parent = null; if (entity != null && entity instanceof ContentCollection) { ContentCollection containingCollection = (ContentCollection) entity; Boolean preventPublicDisplay = (Boolean) state.getAttribute(STATE_PREVENT_PUBLIC_DISPLAY); if (preventPublicDisplay == null) { preventPublicDisplay = Boolean.FALSE; state.setAttribute(STATE_PREVENT_PUBLIC_DISPLAY, preventPublicDisplay); } parent = new ListItem(entity); parent.setPubviewPossible(!preventPublicDisplay); } List<ResourceToolActionPipe> pipes = pipe.getPipes(); int actualCount = 0; for (int i = 0; i <= lastIndex && actualCount < count; i++) { String exists = params.getString("exists" + ListItem.DOT + i); if (exists == null || "".equals(exists)) { continue; } ResourceToolActionPipe fp = pipes.get(actualCount); String folderName = params.getString("content" + ListItem.DOT + i); if (folderName == null || folderName.trim().equals("")) { continue; } fp.setFileName(folderName); ListItem newFolder = (ListItem) fp.getRevisedListItem(); if (newFolder == null) { if (parent == null) { newFolder = new ListItem(folderName); } else { Time defaultRetractDate = (Time) state.getAttribute(STATE_DEFAULT_RETRACT_TIME); if (defaultRetractDate == null) { defaultRetractDate = TimeService.newTime(); state.setAttribute(STATE_DEFAULT_RETRACT_TIME, defaultRetractDate); } newFolder = new ListItem(fp, parent, defaultRetractDate); newFolder.setName(folderName); newFolder.setId(folderName); } } if (ListItem.isOptionalPropertiesEnabled()) { newFolder.initMetadataGroups(); } // capture properties newFolder.captureProperties(params, ListItem.DOT + i); if (newFolder.numberFieldIsInvalid) { addAlert(state, rb.getString("conditions.invalid.condition.argument")); return; } if (newFolder.numberFieldIsOutOfRange) { addAlert(state, rb.getFormattedMessage("conditions.condition.argument.outofrange", new String[] { newFolder.getConditionAssignmentPoints() })); return; } if (!"".equals(newFolder.metadataValidationFails)) { addAlert(state, metaLang.getFormattedMessage("metadata.validation.error", newFolder.metadataValidationFails)); return; } //Control if groups are selected if (!ResourcesAction.checkGroups(params)) { addAlert(state, rb.getString("alert.youchoosegroup")); return; } fp.setRevisedListItem(newFolder); ResourceConditionsHelper.saveCondition(newFolder, params, state, i); actualCount++; } if (actualCount > 0) { pipe.setActionCanceled(false); pipe.setErrorEncountered(false); pipe.setActionCompleted(true); toolSession.setAttribute(ResourceToolAction.DONE, Boolean.TRUE); } else { addAlert(state, rb.getString("alert.nofldr")); } } public void doReplace(RunData data) { logger.debug(this + ".doReplace()"); SessionState state = ((JetspeedRunData) data).getPortletSessionState(((JetspeedRunData) data).getJs_peid()); ParameterParser params = data.getParameters(); ToolSession toolSession = SessionManager.getCurrentToolSession(); int requestStateId = params.getInt("requestStateId", 0); ResourcesAction.restoreRequestState(state, new String[] { ResourcesAction.PREFIX + ResourcesAction.REQUEST }, requestStateId); ResourceToolActionPipe pipe = (ResourceToolActionPipe) toolSession .getAttribute(ResourceToolAction.ACTION_PIPE); if (pipe == null) { return; } String pipe_init_id = pipe.getInitializationId(); String response_init_id = params.getString(ResourcesAction.PIPE_INIT_ID); if (pipe_init_id == null || response_init_id == null || !response_init_id.equalsIgnoreCase(pipe_init_id)) { // in this case, prevent upload to wrong folder pipe.setErrorMessage(rb.getString("alert.try-again")); pipe.setActionCanceled(false); pipe.setErrorEncountered(true); pipe.setActionCompleted(false); logger.debug(this + ".doReplace() setting error on pipe"); String uploadMax = ServerConfigurationService .getString(ResourcesConstants.SAK_PROP_MAX_UPLOAD_FILE_SIZE); addAlert(state, rb.getFormattedMessage("alert.over-per-upload-quota", new Object[] { uploadMax })); return; } FileItem fileitem = null; try { fileitem = params.getFileItem("content"); } catch (Exception e) { logger.warn("Exception ", e); } if (fileitem == null) { String max_file_size_mb = (String) state.getAttribute(STATE_FILE_UPLOAD_MAX_SIZE); int max_bytes = 1024 * 1024; try { max_bytes = Integer.parseInt(max_file_size_mb) * 1024 * 1024; } catch (Exception e) { // if unable to parse an integer from the value // in the properties file, use 1 MB as a default max_file_size_mb = "1"; max_bytes = 1024 * 1024; } String max_bytes_string = ResourcesAction.getFileSizeString(max_bytes, rb); // "The user submitted a file to upload but it was too big!" addAlert(state, rb.getFormattedMessage("size.exceeded", new Object[] { max_bytes_string })); //max_file_size_mb + "MB " + rb.getString("exceeded2")); } else if (fileitem.getFileName() == null || fileitem.getFileName().length() == 0) { addAlert(state, rb.getString("choosefile7")); } else if (fileitem.getFileName().length() > 0) { String filename = Validator.getFileName(fileitem.getFileName()); InputStream stream; stream = fileitem.getInputStream(); if (stream == null) { byte[] bytes = fileitem.get(); pipe.setRevisedContent(bytes); } else { pipe.setRevisedContentStream(stream); } String contentType = fileitem.getContentType().replaceAll("\"", ""); //pipe.setRevisedContent(bytes); pipe.setRevisedMimeType(contentType); pipe.setFileName(filename); if (ResourceType.MIME_TYPE_HTML.equals(contentType) || ResourceType.MIME_TYPE_TEXT.equals(contentType)) { pipe.setRevisedResourceProperty(ResourceProperties.PROP_CONTENT_ENCODING, ResourcesAction.UTF_8_ENCODING); } else if (pipe.getPropertyValue(ResourceProperties.PROP_CONTENT_ENCODING) != null) { pipe.setRevisedResourceProperty(ResourceProperties.PROP_CONTENT_ENCODING, (String) pipe.getPropertyValue(ResourceProperties.PROP_CONTENT_ENCODING)); } ListItem newFile = new ListItem(pipe.getContentEntity()); // notification int noti = determineNotificationPriority(params, newFile.isDropbox, newFile.userIsMaintainer()); newFile.setNotification(noti); pipe.setRevisedListItem(newFile); pipe.setActionCanceled(false); pipe.setErrorEncountered(false); pipe.setActionCompleted(true); toolSession.setAttribute(ResourceToolAction.DONE, Boolean.TRUE); } } public void doAddUrls(RunData data) { logger.debug(this + ".soAddUrls()"); SessionState state = ((JetspeedRunData) data).getPortletSessionState(((JetspeedRunData) data).getJs_peid()); ParameterParser params = data.getParameters(); ToolSession toolSession = SessionManager.getCurrentToolSession(); int requestStateId = params.getInt("requestStateId", 0); ResourcesAction.restoreRequestState(state, new String[] { ResourcesAction.PREFIX + ResourcesAction.REQUEST }, requestStateId); MultiFileUploadPipe mfp = (MultiFileUploadPipe) toolSession.getAttribute(ResourceToolAction.ACTION_PIPE); if (mfp == null) { return; } String pipe_init_id = mfp.getInitializationId(); String response_init_id = params.getString(ResourcesAction.PIPE_INIT_ID); if (pipe_init_id == null || response_init_id == null || !response_init_id.equalsIgnoreCase(pipe_init_id)) { // in this case, prevent upload to wrong folder mfp.setErrorMessage(rb.getString("alert.try-again")); mfp.setActionCanceled(false); mfp.setErrorEncountered(true); mfp.setActionCompleted(false); return; } int count = params.getInt("fileCount"); mfp.setFileCount(count); int lastIndex = params.getInt("lastIndex"); ContentEntity entity = mfp.getContentEntity(); ListItem parent = null; if (entity != null && entity instanceof ContentCollection) { ContentCollection containingCollection = (ContentCollection) entity; Boolean preventPublicDisplay = (Boolean) state.getAttribute(STATE_PREVENT_PUBLIC_DISPLAY); if (preventPublicDisplay == null) { preventPublicDisplay = Boolean.FALSE; state.setAttribute(STATE_PREVENT_PUBLIC_DISPLAY, preventPublicDisplay); } parent = new ListItem(entity); parent.setPubviewPossible(!preventPublicDisplay); } List<String> alerts = new ArrayList<String>(); List<ResourceToolActionPipe> pipes = mfp.getPipes(); int actualCount = 0; for (int i = 0; i <= lastIndex && actualCount < count; i++) { String exists = params.getString("exists" + ListItem.DOT + i); if (exists == null || "".equals(exists)) { continue; } ResourceToolActionPipe pipe = pipes.get(actualCount); String url = params.getString("content" + ListItem.DOT + i); if (url == null) { continue; } else { try { url = ResourcesAction.validateURL(url); } catch (MalformedURLException e) { addAlert(state, rb.getFormattedMessage("url.invalid", new String[] { url })); continue; } try { pipe.setRevisedContent(url.getBytes(ResourcesAction.UTF_8_ENCODING)); } catch (UnsupportedEncodingException e) { pipe.setRevisedContent(url.getBytes()); } } // SAK-11816 - allow much longer URLs by correcting a long basename, make sure no URL resource id exceeds 36 chars // Make the URL a length of 32 chars. This is because the basename registered in CR has to be the same than the basename in resources if (url != null) { // url with a mininum of 18 chars. while (url.length() < 18) { url = url.concat(ListItem.DOT); } // max of 18 chars from the URL itself url = url.substring(0, 18); // add a timestamp to differentiate it (+14 chars) Format f = new SimpleDateFormat("yyyyMMddHHmmss"); url += f.format(new Date()); // total new length of 32 chars } // SAK-11816 - END pipe.setFileName(Validator.escapeResourceName(url)); pipe.setRevisedMimeType(ResourceType.MIME_TYPE_URL); ListItem newFile = (ListItem) pipe.getRevisedListItem(); if (newFile == null) { if (parent == null) { newFile = new ListItem(pipe.getFileName()); } else { Time defaultRetractDate = (Time) state.getAttribute(STATE_DEFAULT_RETRACT_TIME); if (defaultRetractDate == null) { defaultRetractDate = TimeService.newTime(); state.setAttribute(STATE_DEFAULT_RETRACT_TIME, defaultRetractDate); } newFile = new ListItem(mfp, parent, defaultRetractDate); newFile.setName(new String(pipe.getRevisedContent())); newFile.setId(pipe.getFileName()); } } if (ListItem.isOptionalPropertiesEnabled()) { newFile.initMetadataGroups(); } // capture properties newFile.captureProperties(params, ListItem.DOT + i); if (newFile.numberFieldIsInvalid) { addAlert(state, rb.getString("conditions.invalid.condition.argument")); return; } if (newFile.numberFieldIsOutOfRange) { addAlert(state, rb.getFormattedMessage("conditions.condition.argument.outofrange", new String[] { newFile.getConditionAssignmentPoints() })); return; } if (!"".equals(newFile.metadataValidationFails)) { addAlert(state, metaLang.getFormattedMessage("metadata.validation.error", newFile.metadataValidationFails)); return; } //Control if groups are selected if (!ResourcesAction.checkGroups(params)) { addAlert(state, rb.getString("alert.youchoosegroup")); return; } // notification int noti = determineNotificationPriority(params, newFile.isDropbox, newFile.userIsMaintainer()); newFile.setNotification(noti); //alerts.addAll(newFile.checkRequiredProperties()); pipe.setRevisedListItem(newFile); // capture properties newFile.captureProperties(params, ListItem.DOT + i); if (newFile.numberFieldIsInvalid) { addAlert(state, contentResourceBundle.getString("conditions.invalid.condition.argument")); return; } if (newFile.numberFieldIsOutOfRange) { addAlert(state, contentResourceBundle.getFormattedMessage("conditions.condition.argument.outofrange", new String[] { newFile.getConditionAssignmentPoints() })); return; } if (!"".equals(newFile.metadataValidationFails)) { addAlert(state, metaLang.getFormattedMessage("metadata.validation.error", newFile.metadataValidationFails)); return; } ResourceConditionsHelper.saveCondition(newFile, params, state, i); actualCount++; } if (!alerts.isEmpty()) { for (String alert : alerts) { addAlert(state, alert); } } if (actualCount < 1) { addAlert(state, rb.getString("url.noinput")); return; } mfp.setActionCanceled(false); mfp.setErrorEncountered(false); mfp.setActionCompleted(true); toolSession.setAttribute(ResourceToolAction.DONE, Boolean.TRUE); } /** * @return */ protected String getDropboxNotificationsProperty() { Placement placement = ToolManager.getCurrentPlacement(); Properties props = placement.getPlacementConfig(); String dropboxNotifications = props.getProperty(ResourcesAction.DROPBOX_NOTIFICATIONS_PROPERTY); if (dropboxNotifications == null) { dropboxNotifications = ResourcesAction.DROPBOX_NOTIFICATIONS_DEFAULT_VALUE; } logger.debug(this + ".getDropboxNotificationsProperty() dropboxNotifications == " + dropboxNotifications); return dropboxNotifications; } /** * @param params * @param newFile * @return */ protected int determineNotificationPriority(ParameterParser params, boolean contextIsDropbox, boolean userIsMaintainer) { int noti = NotificationService.NOTI_NONE; // %%STATE_MODE_RESOURCES%% if (contextIsDropbox) { boolean notification = false; if (userIsMaintainer) // if the user is a site maintainer { notification = params.getBoolean("notify_dropbox"); if (notification) { noti = NotificationService.NOTI_REQUIRED; } } else { String notifyDropbox = getDropboxNotificationsProperty(); if (ResourcesAction.DROPBOX_NOTIFICATIONS_ALWAYS.equals(notifyDropbox)) { noti = NotificationService.NOTI_OPTIONAL; } else if (ResourcesAction.DROPBOX_NOTIFICATIONS_ALLOW.equals(notifyDropbox)) { notification = params.getBoolean("notify_dropbox"); if (notification) { noti = NotificationService.NOTI_OPTIONAL; } } } logger.debug(this + ".doAddUrls() noti == " + noti); } else { // read the notification options String notification = params.getString("notify"); if ("r".equals(notification)) { noti = NotificationService.NOTI_REQUIRED; } else if ("o".equals(notification)) { noti = NotificationService.NOTI_OPTIONAL; } } return noti; } public void doUpload(RunData data) { logger.debug(this + ".doUpload()"); SessionState state = ((JetspeedRunData) data).getPortletSessionState(((JetspeedRunData) data).getJs_peid()); ParameterParser params = data.getParameters(); ToolSession toolSession = SessionManager.getCurrentToolSession(); int requestStateId = params.getInt("requestStateId", 0); ResourcesAction.restoreRequestState(state, new String[] { ResourcesAction.PREFIX + ResourcesAction.REQUEST }, requestStateId); MultiFileUploadPipe mfp = (MultiFileUploadPipe) toolSession.getAttribute(ResourceToolAction.ACTION_PIPE); if (mfp == null) { logger.debug(this + ".doUpload() mfp is null"); return; } String pipe_init_id = mfp.getInitializationId(); String response_init_id = params.getString(ResourcesAction.PIPE_INIT_ID); if (pipe_init_id == null || response_init_id == null || !response_init_id.equalsIgnoreCase(pipe_init_id)) { // in this case, prevent upload to wrong folder mfp.setErrorMessage(rb.getString("alert.try-again")); mfp.setActionCanceled(false); mfp.setErrorEncountered(true); mfp.setActionCompleted(false); logger.debug(this + ".doUpload() setting error on pipe"); String uploadMax = ServerConfigurationService .getString(ResourcesConstants.SAK_PROP_MAX_UPLOAD_FILE_SIZE); addAlert(state, rb.getFormattedMessage("alert.over-per-upload-quota", new Object[] { uploadMax })); return; } logger.debug(" after doUpload() setting error on pipe"); int count = params.getInt("fileCount"); mfp.setFileCount(count); if (count < 1) { mfp.setFileCount(1); } int lastIndex = params.getInt("lastIndex"); List<String> allAlerts = new ArrayList<String>(); ContentEntity entity = mfp.getContentEntity(); ListItem parent = null; if (entity != null && entity instanceof ContentCollection) { ContentCollection containingCollection = (ContentCollection) entity; Boolean preventPublicDisplay = (Boolean) state.getAttribute(STATE_PREVENT_PUBLIC_DISPLAY); if (preventPublicDisplay == null) { preventPublicDisplay = Boolean.FALSE; state.setAttribute(STATE_PREVENT_PUBLIC_DISPLAY, preventPublicDisplay); } parent = new ListItem(entity); parent.setPubviewPossible(!preventPublicDisplay); } List<ResourceToolActionPipe> pipes = mfp.getPipes(); logger.debug(this + ".doUpload() iterating through pipes"); int uploadCount = 0; for (int i = 0, c = 0; i <= lastIndex && c < count; i++) { String exists = params.getString("exists" + ListItem.DOT + i); if (exists == null || "".equals(exists)) { continue; } ResourceToolActionPipe pipe = pipes.get(c); FileItem fileitem = null; try { fileitem = params.getFileItem("content" + ListItem.DOT + i); } catch (Exception e) { logger.warn("Exception ", e); } if (fileitem == null) { String max_file_size_mb = (String) state.getAttribute(STATE_FILE_UPLOAD_MAX_SIZE); int max_bytes = 1024 * 1024; try { max_bytes = Integer.parseInt(max_file_size_mb) * 1024 * 1024; } catch (Exception e) { // if unable to parse an integer from the value // in the properties file, use 1 MB as a default max_file_size_mb = "1"; max_bytes = 1024 * 1024; } String max_bytes_string = ResourcesAction.getFileSizeString(max_bytes, rb); // "The user submitted a file to upload but it was too big!" addAlert(state, rb.getFormattedMessage("size.exceeded", new Object[] { max_bytes_string })); //max_file_size_mb + "MB " + rb.getString("exceeded2")); } else if (fileitem.getFileName() == null || fileitem.getFileName().length() == 0) { // no file selected -- skip this one } else if (fileitem.getFileName().length() > 0) { String filename = Validator.getFileName(fileitem.getFileName()); pipe.setRevisedContentStream(fileitem.getInputStream()); String contentType = fileitem.getContentType().replaceAll("\"", ""); pipe.setRevisedMimeType(contentType); // If no encoding specified, default to UTF-8 encoding if ((ResourceType.MIME_TYPE_HTML.equals(contentType) || ResourceType.MIME_TYPE_TEXT.equals(contentType)) && pipe.getPropertyValue(ResourceProperties.PROP_CONTENT_ENCODING) == null) { pipe.setRevisedResourceProperty(ResourceProperties.PROP_CONTENT_ENCODING, ResourcesAction.UTF_8_ENCODING); } pipe.setFileName(filename); ListItem newFile = (ListItem) pipe.getRevisedListItem(); if (newFile == null) { if (parent == null) { newFile = new ListItem(filename); } else { Time defaultRetractDate = (Time) state.getAttribute(STATE_DEFAULT_RETRACT_TIME); if (defaultRetractDate == null) { defaultRetractDate = TimeService.newTime(); state.setAttribute(STATE_DEFAULT_RETRACT_TIME, defaultRetractDate); } newFile = new ListItem(pipe, parent, defaultRetractDate); newFile.setName(filename); newFile.setId(filename); } } if (ListItem.isOptionalPropertiesEnabled()) { newFile.initMetadataGroups(); } // capture properties newFile.captureProperties(params, ListItem.DOT + i); // notification int noti = determineNotificationPriority(params, newFile.isDropbox, newFile.userIsMaintainer()); newFile.setNotification(noti); // allAlerts.addAll(newFile.checkRequiredProperties()); pipe.setRevisedListItem(newFile); // capture properties newFile.captureProperties(params, ListItem.DOT + i); if (newFile.numberFieldIsInvalid) { addAlert(state, contentResourceBundle.getString("conditions.invalid.condition.argument")); return; } if (newFile.numberFieldIsOutOfRange) { addAlert(state, contentResourceBundle.getFormattedMessage("conditions.condition.argument.outofrange", new String[] { newFile.getConditionAssignmentPoints() })); return; } if (!"".equals(newFile.metadataValidationFails)) { addAlert(state, metaLang.getFormattedMessage("metadata.validation.error", newFile.metadataValidationFails)); return; } //Control if groups are selected if (!ResourcesAction.checkGroups(params)) { addAlert(state, rb.getString("alert.youchoosegroup")); return; } ResourceConditionsHelper.saveCondition(newFile, params, state, i); uploadCount++; } c++; } logger.debug(this + ".doUpload() checking upload count"); if (uploadCount < 1 && state.getAttribute(ResourcesAction.STATE_MESSAGE) == null) { logger.debug(this + ".doUpload() no files uploaded"); HttpServletRequest req = data.getRequest(); String status = (String) req.getAttribute("upload.status"); logger.debug("Printing out upload.status: " + status); if (status == null) { logger.warn("No files uploaded; upload.status == null"); } else if ("ok".equals(status)) { logger.warn("No files uploaded; upload.status == ok"); } else if ("size_limit_exceeded".equals(status)) { String max_file_size_mb = (String) state.getAttribute(STATE_FILE_UPLOAD_MAX_SIZE); int max_bytes = 1024 * 1024; try { max_bytes = Integer.parseInt(max_file_size_mb) * 1024 * 1024; } catch (Exception e) { // if unable to parse an integer from the value // in the properties file, use 1 MB as a default max_file_size_mb = "1"; max_bytes = 1024 * 1024; } String max_bytes_string = ResourcesAction.getFileSizeString(max_bytes, rb); addAlert(state, rb.getFormattedMessage("size.exceeded", new Object[] { max_bytes_string })); } else if ("exception".equals(status)) { logger.warn("No files uploaded; upload.status == exception"); addAlert(state, rb.getString("choosefile7")); } } logger.debug(this + ".doUpload() checking allAlerts"); if (!allAlerts.isEmpty()) { for (String alert : allAlerts) { addAlert(state, alert); } } logger.debug(this + ".doUpload() checking messages"); if (state.getAttribute(ResourcesAction.STATE_MESSAGE) == null) { mfp.setActionCanceled(false); mfp.setErrorEncountered(false); mfp.setActionCompleted(true); logger.debug(this + ".doUpload() no error messages"); toolSession.setAttribute(ResourceToolAction.DONE, Boolean.TRUE); } } protected void initHelper(VelocityPortlet portlet, Context context, RunData rundata, SessionState state) { logger.debug(this + ".initHelper()"); ToolSession toolSession = SessionManager.getCurrentToolSession(); //toolSession.setAttribute(ResourceToolAction.STARTED, Boolean.TRUE); //state.setAttribute(ResourceToolAction.STATE_MODE, MODE_MAIN); if (state.getAttribute(STATE_USING_CREATIVE_COMMONS) == null) { String usingCreativeCommons = ServerConfigurationService.getString("copyright.use_creative_commons"); if (usingCreativeCommons != null && usingCreativeCommons.equalsIgnoreCase(Boolean.TRUE.toString())) { state.setAttribute(STATE_USING_CREATIVE_COMMONS, Boolean.TRUE.toString()); } else { state.setAttribute(STATE_USING_CREATIVE_COMMONS, Boolean.FALSE.toString()); } } if (state.getAttribute(STATE_COPYRIGHT_TYPES) == null) { if (ServerConfigurationService.getStrings("copyrighttype") != null) { state.setAttribute(STATE_COPYRIGHT_TYPES, new ArrayList(Arrays.asList(ServerConfigurationService.getStrings("copyrighttype")))); } } if (state.getAttribute(STATE_DEFAULT_COPYRIGHT) == null) { if (ServerConfigurationService.getString("default.copyright") != null) { state.setAttribute(STATE_DEFAULT_COPYRIGHT, ServerConfigurationService.getString("default.copyright")); } } if (state.getAttribute(STATE_DEFAULT_COPYRIGHT_ALERT) == null) { if (ServerConfigurationService.getString("default.copyright.alert") != null) { state.setAttribute(STATE_DEFAULT_COPYRIGHT_ALERT, ServerConfigurationService.getString("default.copyright.alert")); } } if (state.getAttribute(STATE_NEW_COPYRIGHT_INPUT) == null) { if (ServerConfigurationService.getString("newcopyrightinput") != null) { state.setAttribute(STATE_NEW_COPYRIGHT_INPUT, ServerConfigurationService.getString("newcopyrightinput")); } } if (state.getAttribute(STATE_COPYRIGHT_FAIRUSE_URL) == null) { if (ServerConfigurationService.getString("fairuse.url") != null) { state.setAttribute(STATE_COPYRIGHT_FAIRUSE_URL, ServerConfigurationService.getString("fairuse.url")); } } if (state.getAttribute(STATE_COPYRIGHT_NEW_COPYRIGHT) == null) { if (ServerConfigurationService.getString("copyrighttype.new") != null) { state.setAttribute(STATE_COPYRIGHT_NEW_COPYRIGHT, ServerConfigurationService.getString("copyrighttype.new")); } } if (state.getAttribute(STATE_FILE_UPLOAD_MAX_SIZE) == null) { String uploadMax = ServerConfigurationService .getString(ResourcesConstants.SAK_PROP_MAX_UPLOAD_FILE_SIZE); String uploadCeiling = ServerConfigurationService.getString("content.upload.ceiling"); if (uploadMax == null && uploadCeiling == null) { state.setAttribute(STATE_FILE_UPLOAD_MAX_SIZE, ResourcesConstants.DEFAULT_MAX_FILE_SIZE_STRING); } else if (uploadCeiling == null) { state.setAttribute(STATE_FILE_UPLOAD_MAX_SIZE, uploadMax); } else if (uploadMax == null) { state.setAttribute(STATE_FILE_UPLOAD_MAX_SIZE, null); } else { int maxNum = Integer.MAX_VALUE; int ceilingNum = Integer.MAX_VALUE; try { maxNum = Integer.parseInt(uploadMax); } catch (Exception e) { } try { ceilingNum = Integer.parseInt(uploadCeiling); } catch (Exception e) { } if (ceilingNum < maxNum) { state.setAttribute(STATE_FILE_UPLOAD_MAX_SIZE, uploadCeiling); } else { state.setAttribute(STATE_FILE_UPLOAD_MAX_SIZE, uploadMax); } } } state.setAttribute(STATE_PREVENT_PUBLIC_DISPLAY, Boolean.FALSE); String[] siteTypes = ServerConfigurationService.getStrings("prevent.public.resources"); String siteType = null; Site site; try { site = SiteService.getSite(ToolManager.getCurrentPlacement().getContext()); siteType = site.getType(); if (siteTypes != null) { for (int i = 0; i < siteTypes.length; i++) { if ((StringUtils.trimToNull(siteTypes[i])).equals(siteType)) { state.setAttribute(STATE_PREVENT_PUBLIC_DISPLAY, Boolean.TRUE); break; } } } } catch (IdUnusedException e) { // allow public display } catch (NullPointerException e) { // allow public display } state.setAttribute(STATE_CONTENT_TYPE_IMAGE_SERVICE, org.sakaiproject.content.cover.ContentTypeImageService.getInstance()); } protected void toolModeDispatch(String methodBase, String methodExt, HttpServletRequest req, HttpServletResponse res) throws ToolException { logger.debug(this + ".toolModeDispatch()"); SessionState sstate = getState(req); ToolSession toolSession = SessionManager.getCurrentToolSession(); //String mode = (String) sstate.getAttribute(ResourceToolAction.STATE_MODE); //Object started = toolSession.getAttribute(ResourceToolAction.STARTED); Object done = toolSession.getAttribute(ResourceToolAction.DONE); if (done != null) { toolSession.removeAttribute(ResourceToolAction.STARTED); Tool tool = ToolManager.getCurrentTool(); String url = (String) SessionManager.getCurrentToolSession() .getAttribute(tool.getId() + Tool.HELPER_DONE_URL); logger.debug(this + ".toolModeDispatch() url == " + url); SessionManager.getCurrentToolSession().removeAttribute(tool.getId() + Tool.HELPER_DONE_URL); try { res.sendRedirect(url); } catch (IOException e) { logger.warn(this + ".toolModeDispatch() IOException", e); } logger.debug(this + ".toolModeDispatch() returning"); return; } logger.debug(this + ".toolModeDispatch() calling super.toolModeDispatch(" + methodBase + ", " + "methodExt" + ", " + req + ", " + res + ")"); super.toolModeDispatch(methodBase, methodExt, req, res); } protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException { String fullPath = request.getParameter("fullPath"); String action = request.getParameter("sakai_action"); logger.debug("Received action: " + action + " for file: " + fullPath); // set up rundata, in case we're called from RSF checkRunData(request); if (fullPath != null) { Long fileSize = Long.parseLong(request.getHeader("content-length")); Long uploadMax; Long siteQuota; try { uploadMax = Long.parseLong( ServerConfigurationService.getString(ResourcesConstants.SAK_PROP_MAX_UPLOAD_FILE_SIZE, ResourcesConstants.DEFAULT_MAX_FILE_SIZE_STRING)); } catch (NumberFormatException ex) { logger.debug("sakai.property '" + ResourcesConstants.SAK_PROP_MAX_UPLOAD_FILE_SIZE + "' does not contain an integer", ex); uploadMax = ResourcesConstants.DEFAULT_MAX_FILE_SIZE; } try { siteQuota = Long.parseLong( ServerConfigurationService.getString(ResourcesConstants.SAK_PROP_MASTER_SITE_QUOTA, ResourcesConstants.DEFAULT_SITE_QUOTA_STRING)); } catch (NumberFormatException ex) { logger.debug("sakai.property '" + ResourcesConstants.SAK_PROP_MASTER_SITE_QUOTA + "' does not contain an integer", ex); siteQuota = ResourcesConstants.DEFAULT_SITE_QUOTA; } // Get the site type specific site quota String siteTypeQuotaProp = ""; Long siteTypeQuota = null; try { Site site = SiteService.getSite(ToolManager.getCurrentPlacement().getContext()); siteTypeQuotaProp = ResourcesConstants.SAK_PROP_MASTER_SITE_QUOTA + "." + site.getType(); siteTypeQuota = Long.parseLong(ServerConfigurationService.getString(siteTypeQuotaProp)); } catch (IdUnusedException ex) { logger.warn("Can't find site: ", ex); } catch (NumberFormatException ex) { logger.debug("sakai.property '" + siteTypeQuotaProp + "' does not contain an integer", ex); } // Determine which site quota to use (if the site specific quota is set, it over-rides the global one) if (siteTypeQuota != null) { siteQuota = siteTypeQuota; } // Determine if the site quota is unlimited boolean siteQuotaUnlimited = siteQuota == 0; // If the file size exceeds the max uploaded file size, post error message Long fileSizeMB = fileSize / 1024L / 1024L; if (fileSizeMB > uploadMax) { addAlert(getState(request), rb.getFormattedMessage("alert.over-per-upload-quota", new Object[] { uploadMax })); } // If the file size exceeds the max quota for the site, post error message else if (!siteQuotaUnlimited && fileSizeMB > siteQuota) { addAlert(getState(request), rb.getFormattedMessage("alert.over-site-upload-quota", new Object[] { siteQuota })); } // Otherwise, continue with upload process else { JetspeedRunData rundata = (JetspeedRunData) request.getAttribute(ATTR_RUNDATA); if (checkCSRFToken(request, rundata, action)) { doDragDropUpload(request, response, fullPath); } } } else { if (action != null) { JetspeedRunData rundata = (JetspeedRunData) request.getAttribute(ATTR_RUNDATA); if (checkCSRFToken(request, rundata, action)) { if (action.equals("doFinishUpload")) { notifyDragAndDropCompleted(request); } super.doPost(request, response); } } else { //Action NULL - Here we have a folder uploaded in a browser that does not support it. logger.warn("Action null and file null in ResourcesHelperAction"); //RequestFilter throws an Exception when a folder is uploaded from a not valid browser (anyone but Chrome 21+): //org.apache.commons.fileupload.FileUploadBase$IOFileUploadException: Processing of multipart/form-data request failed. Stream ended unexpectedly //No way to handle this in server side, unless we modify RequestFilter or create our own FileUpload handler. //The easiest fix is to handle not valid folders in client side. //It is done, so this piece of code should never be reached. } } } private synchronized void doDragDropUpload(HttpServletRequest request, HttpServletResponse response, String fullPath) { //Feel free to sent comments/warnings/advices to me at daniel.merino AT unavarra.es //Full method must be synchronized because a collection can edited and committed in two concurrent requests //Dropzone allows multiple parallel uploads so if all this process is not synchronized, InUseException is thrown //Maybe a more sophisticated concurrence can be set in the future SessionState state = getState(request); ToolSession toolSession = SessionManager.getCurrentToolSession(); ContentResourceEdit resource = null; ContentCollectionEdit collection = null; String uploadFileName = null; String collectionName = null; String resourceGroup = toolSession.getAttribute("resources.request.create_wizard_collection_id").toString(); if (!("undefined".equals(fullPath) || "".equals(fullPath))) { //Received a file that is inside an uploaded folder //Try to create a collection with this folder and to add the file inside it after File myfile = new File(fullPath); String fileName = myfile.getName(); collectionName = resourceGroup + myfile.getParent(); //AFAIK it is not possible to check undoubtedly if a collection exists //isCollection() only tests if name is valid and checkCollection() returns void type //So the procedure is to create the collection and capture thrown Exceptions collection = createCollectionIfNotExists(collectionName); if (collection == null) { addAlert(state, contentResourceBundle.getFormattedMessage("dragndrop.collection.error", new Object[] { collectionName, fileName })); return; } } try { //Now upload the received file //Test that file has been sent in request DiskFileItem uploadFile = (DiskFileItem) request.getAttribute("file"); if (uploadFile != null) { String contentType = uploadFile.getContentType(); uploadFileName = uploadFile.getName(); String extension = ""; String basename = uploadFileName.trim(); if (uploadFileName.contains(".")) { String[] parts = uploadFileName.split("\\."); basename = parts[0]; if (parts.length > 1) { extension = parts[parts.length - 1]; } for (int i = 1; i < parts.length - 1; i++) { basename += "." + parts[i]; } } if (collection != null) { logger.debug("Adding resource " + uploadFileName + " in collection " + collection.getId()); resource = ContentHostingService.addResource(collection.getId(), Validator.escapeResourceName(basename), Validator.escapeResourceName(extension), 5); } else { //Method getUniqueFileName was added to change external name of uploaded resources if they exist already in the collection, just the same way that their internal id. //However, that is not the way Resources tool works. Internal id is changed but external name is the same for every copy of the same file. //So I disable this method call, though it can be enabled again if desired. //String resourceName = getUniqueFileName(uploadFileName, resourceGroup); logger.debug( "Adding resource " + uploadFileName + " in current folder (" + resourceGroup + ")"); resource = ContentHostingService.addResource(resourceGroup, Validator.escapeResourceName(basename), Validator.escapeResourceName(extension), 5); } if (resource != null) { if (contentType != null) resource.setContentType(contentType); ResourcePropertiesEdit resourceProps = resource.getPropertiesEdit(); resourceProps.addProperty(ResourcePropertiesEdit.PROP_DISPLAY_NAME, uploadFileName); resource.setContent(uploadFile.getInputStream()); resource.setContentType(contentType); ContentHostingService.commitResource(resource, NotificationService.NOTI_NONE); if (collection != null) { ContentHostingService.commitCollection(collection); logger.debug("Collection commited: " + collection.getId()); } } else { addAlert(state, contentResourceBundle.getFormattedMessage("dragndrop.upload.error", new Object[] { uploadFileName })); return; } } else { addAlert(state, contentResourceBundle.getFormattedMessage("dragndrop.upload.error", new Object[] { uploadFileName })); return; } } catch (IdUniquenessException e) { addAlert(state, contentResourceBundle.getFormattedMessage("dragndrop.duplicated.error", new Object[] { uploadFileName, ResourcesAction.MAXIMUM_ATTEMPTS_FOR_UNIQUENESS })); return; } catch (OverQuotaException e) { addAlert(state, rb.getString("alert.over-site-upload-quota")); logger.warn("Drag and drop upload exceeded site quota: " + e, e); return; } catch (ServerOverloadException e) { addAlert(state, contentResourceBundle.getFormattedMessage("dragndrop.overload.error", new Object[] { uploadFileName })); logger.warn("Drag and drop upload overloaded the server: " + e, e); return; } catch (Exception e) { addAlert(state, contentResourceBundle.getFormattedMessage("dragndrop.upload.error", new Object[] { uploadFileName })); logger.warn("Drag and drop upload failed: " + e, e); return; } try { //Set an i18n OK message for successfully uploaded files. This message is captured by client side and written in the files of Dropzone. response.setContentType("text/plain"); response.setStatus(200); PrintWriter pw = response.getWriter(); pw.write(contentResourceBundle.getString("dragndrop.success.upload")); pw.flush(); pw.close(); } catch (Exception e) { logger.error("Exception writing response in ResourcesHelperAction"); return; } addFilenameReferenceToList(state, resource.getReference()); toolSession.setAttribute(ResourceToolAction.DONE, Boolean.TRUE); } private ContentCollectionEdit createCollectionIfNotExists(String collectionName) { //Try to get an existing collection or create it if it does not exist //Weird thing: To get existing collections a File.separator must finish the collection's name or a Permissions exception is thrown //This does not happen when creating the collection ContentCollectionEdit cc = null; try { logger.debug("Looking for collection " + collectionName + File.separator); if (ContentHostingService.getCollection(collectionName + File.separator) != null) { //As Sakai usual behaviour in Resources tool, Collections internal ids do not use non-ASCII chars, so for example folder "Videos" and "Vdeos" are asigned to the same id. //So id must be always used. Using collection's name can fail. cc = ContentHostingService.editCollection( ContentHostingService.getCollection(collectionName + File.separator).getId()); logger.debug("Editing collection found with id: " + cc.getId()); } } catch (IdUnusedException e) { logger.debug( "Collection " + collectionName + File.separator + " does not exist, proceed to create it."); //It does not exist, so create the folder String carpetaName = collectionName.substring(collectionName.lastIndexOf(File.separator) + 1, collectionName.length()); //Deepest folder name try { cc = ContentHostingService.addCollection(collectionName); ResourcePropertiesEdit m_oPropEditSub = cc.getPropertiesEdit(); m_oPropEditSub.addProperty(ResourceProperties.PROP_DISPLAY_NAME, carpetaName); if (cc != null) ContentHostingService.commitCollection(cc); } catch (IdUsedException e2) { logger.warn("IdUsedException " + e2.toString()); return null; } catch (Exception e2) { logger.warn("Exception on exception: " + e2.toString()); return null; } } catch (InUseException e) { //This exception can be thrown for concurrence issues with multiple parallel uploads. //Synchronizing doDragDropUpload method avoids it logger.warn("InUseException: " + e.toString()); e.printStackTrace(); return null; } catch (Exception e) { logger.warn("Exception: " + e.toString()); return null; } logger.debug("Returning collection: " + cc.getId()); return cc; } public void notifyDragAndDropCompleted(HttpServletRequest request) { /* * This method uses a new class SiteEmailNotificationDragAndDrop which extends SiteEmailNotification * and uses some modified code of SiteEmailNotificationContent and DropboxNotification classes. * Current Content notifications are managed with information of every uploaded content entity. However, this does not work with a group of entities uploaded through D&D. * Resources D&D notifications can be decided using containing folder as reference instead each uploaded file. * Dropbox D&D notifications are trickier. When a maintain/Instructor sends one notification to access/student, dropbox containing folder can be used as well. * But when a student/access sends one notification to maintains/Instructors, the folder owner is compared with the user who last modificated the uploaded item. * This is not valid in D&D, so I have changed it and folder owner is compared with current user in order to send notifications. */ JetspeedRunData rundata = (JetspeedRunData) request.getAttribute(ATTR_RUNDATA); ParameterParser params = rundata.getParameters(); ToolSession toolSession = SessionManager.getCurrentToolSession(); ResourceToolActionPipe pipe = (ResourceToolActionPipe) toolSession .getAttribute(ResourceToolAction.ACTION_PIPE); ListItem item = new ListItem(pipe.getContentEntity()); int notificationPriority = determineNotificationPriority(params, item.isDropbox(), item.userIsMaintainer()); SessionState state = getState(request); try { Site site = SiteService.getSite(ToolManager.getCurrentPlacement().getContext()); NotificationEdit ne = notificationService.addTransientNotification(); String eventResource; if (item.isDropbox) { eventResource = org.sakaiproject.content.api.ContentHostingService.EVENT_RESOURCE_AVAILABLE; ne.setResourceFilter(ContentHostingService.REFERENCE_ROOT + org.sakaiproject.content.api.ContentHostingService.COLLECTION_DROPBOX); } else { eventResource = org.sakaiproject.content.api.ContentHostingService.EVENT_RESOURCE_ADD; ne.setResourceFilter(ContentHostingService.REFERENCE_ROOT + org.sakaiproject.content.api.ContentHostingService.COLLECTION_SITE); } ne.setFunction(eventResource); SiteEmailNotificationDragAndDrop sendnd = new SiteEmailNotificationDragAndDrop(site.getId()); sendnd.setDropboxFolder(item.isDropbox()); sendnd.setFileList((ArrayList<String>) (state.getAttribute(DRAGNDROP_FILENAME_REFERENCE_LIST))); // Notify when files were successfully added if (sendnd.getFileList() != null && !sendnd.getFileList().isEmpty()) { ne.setAction(sendnd); sendnd.notify(ne, eventTrackingService.newEvent(eventResource, ContentHostingService.REFERENCE_ROOT + item.getId(), true, notificationPriority)); } state.setAttribute(DRAGNDROP_FILENAME_REFERENCE_LIST, null); sendnd.setFileList(null); } catch (IdUnusedException e) { logger.warn("Somehow we couldn't find the site.", e); } } private void addFilenameReferenceToList(SessionState state, String ref) { ArrayList<String> soFar = (ArrayList<String>) state.getAttribute(DRAGNDROP_FILENAME_REFERENCE_LIST); if (soFar == null) soFar = new ArrayList<String>(); soFar.add(ref); state.setAttribute(DRAGNDROP_FILENAME_REFERENCE_LIST, soFar); } // addAlert /* private String getUniqueFileName(String uploadFileName, String resourceGroup) throws org.sakaiproject.exception.PermissionException, org.sakaiproject.exception.TypeException { String resourceId = ""; boolean isNameUnique = false; String fileName = uploadFileName; int attempt = 0; while (!isNameUnique) { try { resourceId = resourceGroup + fileName; ContentResource tempEdit = ContentHostingService.getResource(resourceId); if(tempEdit != null) { attempt++; StringBuffer fileNameBuffer = new StringBuffer(); if(attempt > 1) { fileNameBuffer.append(fileName.substring(0, fileName.lastIndexOf("-"))); } else { fileNameBuffer.append(fileName.substring(0, fileName.lastIndexOf("."))); } fileNameBuffer.append("-"); fileNameBuffer.append(attempt); fileNameBuffer.append(fileName.substring(fileName.lastIndexOf("."), fileName.length())); fileName = fileNameBuffer.toString(); } } catch (IdUnusedException e) { isNameUnique = true; } } return fileName; } */ }