Index: site-manage-participant-helper/src/java/org/sakaiproject/site/tool/helper/participant/impl/ImportedUser.java =================================================================== --- site-manage-participant-helper/src/java/org/sakaiproject/site/tool/helper/participant/impl/ImportedUser.java (revision 0) +++ site-manage-participant-helper/src/java/org/sakaiproject/site/tool/helper/participant/impl/ImportedUser.java (revision 0) @@ -0,0 +1,30 @@ +package org.sakaiproject.site.tool.helper.participant.impl; + +import org.apache.commons.validator.EmailValidator; + + +public class ImportedUser { + public String firstName = ""; + public String lastName = ""; + public String email = ""; + public boolean bad = true; + public String password = ""; + public String role = ""; + + public ImportedUser(String firstName,String lastName,String email,String role) { + this.firstName = firstName; + this.lastName = lastName; + this.email = email; + this.role = role; + + EmailValidator validator = EmailValidator.getInstance(); + if(validator.isValid(email)) { + bad = false; + } + + } + + public void setPassword(String password) { + this.password = password; + } +} Property changes on: site-manage-participant-helper/src/java/org/sakaiproject/site/tool/helper/participant/impl/ImportedUser.java ___________________________________________________________________ Added: svn:keywords + Date Revision Author HeadURL Id Added: svn:eol-style + native Index: site-manage-participant-helper/src/java/org/sakaiproject/site/tool/helper/participant/impl/SiteAddParticipantHandler.java =================================================================== --- site-manage-participant-helper/src/java/org/sakaiproject/site/tool/helper/participant/impl/SiteAddParticipantHandler.java (revision 100779) +++ site-manage-participant-helper/src/java/org/sakaiproject/site/tool/helper/participant/impl/SiteAddParticipantHandler.java (working copy) @@ -1,19 +1,30 @@ package org.sakaiproject.site.tool.helper.participant.impl; +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStreamReader; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashSet; import java.util.Iterator; import java.util.List; +import java.util.Map; import java.util.Set; import java.util.Vector; +import org.apache.commons.fileupload.FileItem; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.commons.validator.EmailValidator; import org.apache.commons.lang.StringUtils; +import org.apache.poi.hssf.usermodel.HSSFCell; +import org.apache.poi.hssf.usermodel.HSSFRow; +import org.apache.poi.hssf.usermodel.HSSFSheet; +import org.apache.poi.hssf.usermodel.HSSFWorkbook; +import org.apache.poi.poifs.filesystem.POIFSFileSystem; + import org.sakaiproject.accountvalidator.logic.ValidationLogic; import org.sakaiproject.authz.api.AuthzGroup; import org.sakaiproject.authz.api.AuthzGroupService; @@ -38,10 +49,16 @@ import org.sakaiproject.user.api.UserIdInvalidException; import org.sakaiproject.user.api.UserNotDefinedException; import org.sakaiproject.user.api.UserPermissionException; +import org.sakaiproject.util.RequestFilter; +import au.com.bytecode.opencsv.CSVReader; + import uk.org.ponder.messageutil.MessageLocator; import uk.org.ponder.messageutil.TargettedMessage; import uk.org.ponder.messageutil.TargettedMessageList; + +import javax.servlet.http.HttpServletRequest; + /** * * @author @@ -69,6 +86,9 @@ '!','@', '#', '$', '%', '^', '&', '*' };*/ + private static final String XLS_MIME_TYPE="application/vnd.ms-excel"; + private static final String CSV_MIME_TYPE="text/csv"; + /** Our log (commons). */ private static Log M_log = LogFactory.getLog(SiteAddParticipantHandler.class); @@ -83,6 +103,43 @@ public MessageLocator messageLocator; private UserNotificationProvider notiProvider; + + /** + * We need this to get the uploaded file as snaffled by the request filter. + */ + private HttpServletRequest httpServletRequest; + public void setHttpServletRequest(HttpServletRequest req) { + this.httpServletRequest = req; + } + + /** + * As we import users we store their details here for use in further stages + * of the import sequence. + */ + private List importedUsers = new ArrayList(); + public List getImportedUsers() { + return importedUsers; + } + + /** + * As we add users to Sakai authn we add them to this list. It allows us to + * demonstrate a degree of transactionalism and remove the users if something + * goes wrong. Implemented as part of the import users from spreadsheet + * capability (SAK-20344). + */ + private List addedSakaiUsers = new ArrayList(); + public List getAddedSakaiUsers() { + return addedSakaiUsers; + } + + /** + * We store the import spreadsheet filename here so we can use it to build the + * filename for the download report later. + */ + private String userImportFilename; + public String getUserImportFilename() { + return userImportFilename; + } // Tool session attribute name used to schedule a whole page refresh. public static final String ATTR_TOP_REFRESH = "sakai.vppa.top.refresh"; @@ -1154,6 +1211,7 @@ sameRoleChoice = null; emailNotiChoice = Boolean.FALSE.toString(); userRoleEntries = new Vector(); + importedUsers = new ArrayList(); } public void setNotiProvider(UserNotificationProvider notiProvider) { @@ -1209,5 +1267,214 @@ } return rndbuf.toString(); } + + /** + * Grabs the uploaded file from the usersfile request attribute and extracts the user details + * from it, addding them to the importedUsers list as it goes. Expects at least three columns, + * the first three being first name, last name and email respectively. + */ + public String processUploadAndCheck() { + String uploadsDone = (String) httpServletRequest.getAttribute(RequestFilter.ATTR_UPLOADS_DONE); + + FileItem usersFileItem; + + if (uploadsDone != null && uploadsDone.equals(RequestFilter.ATTR_UPLOADS_DONE)) { + + try { + usersFileItem = (FileItem) httpServletRequest.getAttribute("usersfile"); + + if(usersFileItem != null && usersFileItem.getSize() > 0) { + + String mimetype = usersFileItem.getContentType(); + + if(StringUtils.equals(mimetype, XLS_MIME_TYPE)) { + return processExcelFile(usersFileItem); + } + else if(StringUtils.equals(mimetype, CSV_MIME_TYPE)) { + return processCsvFile(usersFileItem); + } else { + M_log.error("Invalid file type: " + mimetype); + return "error"; + } + + } + } + catch (Exception e){ + M_log.error(e.getClass() + " : " + e.getMessage()); + return "error"; + } + } + + return "success"; + } + + private void removeAddedSakaiUsers() { + for(User su : addedSakaiUsers) { + + try { + userDirectoryService.removeUser(userDirectoryService.editUser(su.getId())); + } + catch (Exception e1) { + e1.printStackTrace(); + } + } + + addedSakaiUsers = new ArrayList(); + } + + /** + * Creates Sakai accounts for the users in importedUsers if not already present and then + * adds them to the userRoleEntries list. If there is an error adding any of the users then + * all of the users already added are rolled back, ie: removed. + */ + public String processCreateImportedUsers() { + + // We need this so we can rollback user creation on an error + addedSakaiUsers = new ArrayList(); + + for(ImportedUser user: importedUsers) { + + User sakaiUser = null; + + //check if user already exists + try { + sakaiUser = userDirectoryService.getUserByEid(user.email); + user.setPassword("EXISTING SAKAI USER"); + userRoleEntries.add(new UserRoleEntry(user.email, user.role)); + continue; + } + catch(UserNotDefinedException unde) { + //this is ok as the user doesn't exist yet, so we skip this and continue to add them + } + + //get user type for created accounts + String type = serverConfigurationService.getString("user.upload.default.type", "guest"); + + //create the user account + try { + boolean created = false; + + sakaiUser = userDirectoryService.addUser(null, user.email, user.firstName, user.lastName, user.email, generatePassword(), type, null); + addedSakaiUsers.add(sakaiUser); + userRoleEntries.add(new UserRoleEntry(user.email, user.role)); + } + catch(Exception e) { + e.printStackTrace(); + removeAddedSakaiUsers(); + return "error"; + } + } + + return "addedtosakai"; + } + + public String processAddImportedUsersToSite() { + return "emailnotification"; + } + + /** + * Helper to process the uploaded Excel file + * + * @param fileItem + * @return + */ + private String processExcelFile(FileItem fileItem){ + + M_log.debug("Excel file uploaded"); + + byte[] data = fileItem.get(); + userImportFilename = fileItem.getName(); + importedUsers = new ArrayList(); + + try { + POIFSFileSystem fs = new POIFSFileSystem(new ByteArrayInputStream(data)); + HSSFWorkbook wb = new HSSFWorkbook(fs); + HSSFSheet sheet = wb.getSheetAt(0); + + for(Iterator rows = sheet.iterator();rows.hasNext();) { + HSSFRow row = (HSSFRow) rows.next(); + + //check min number of cells + if(row.getPhysicalNumberOfCells() < 3) continue; + + //cell 0: first name + HSSFCell firstNameCell = row.getCell(0); + if(HSSFCell.CELL_TYPE_STRING != firstNameCell.getCellType()) continue; + String firstName = firstNameCell.getStringCellValue().trim(); + + //cell 1: last name + HSSFCell lastNameCell = row.getCell(1); + if(HSSFCell.CELL_TYPE_STRING != lastNameCell.getCellType()) continue; + String lastName = lastNameCell.getStringCellValue().trim(); + + //cell 2: email + HSSFCell emailCell = row.getCell(2); + if(HSSFCell.CELL_TYPE_STRING != emailCell.getCellType()) continue; + String email = emailCell.getStringCellValue().trim().toLowerCase(); + + //cell 3: role (optional. if not given will come from sakai.properties) + HSSFCell roleCell = row.getCell(3); + + String role; + if(roleCell != null && HSSFCell.CELL_TYPE_STRING == roleCell.getCellType()) { + role = roleCell.getStringCellValue().trim().toLowerCase(); + } else { + role = getServerConfigurationString("user.upload.default.role"); + } + + //could possibly add a username field here but we can just get the user by their email address anyway... + + importedUsers.add(new ImportedUser(firstName, lastName, email, role)); + } + } + catch(IOException ioe) { + M_log.error(ioe.getClass() + " : " + ioe.getMessage()); + return "error"; + } + + return "uploaded"; + } + + /** + * Helper to process the uploaded CSV file + * + * @param fileItem + * @return + */ + private String processCsvFile(FileItem fileItem){ + + M_log.debug("CSV file uploaded"); + + CSVReader reader; + try { + reader = new CSVReader(new InputStreamReader(fileItem.getInputStream())); + List lines = reader.readAll(); + for(String[] line: lines){ + + String firstName = line[0]; + String lastName = line[1]; + String email = line[2]; + + //optionally check for role or use default + String role; + if(line.length >= 4) { + role = line[3]; + } else { + role = getServerConfigurationString("user.upload.default.role"); + } + + importedUsers.add(new ImportedUser(firstName, lastName, email, role)); + } + + } catch (IOException ioe) { + M_log.error(ioe.getClass() + " : " + ioe.getMessage()); + return "error"; + } catch (ArrayIndexOutOfBoundsException ae){ + M_log.error(ae.getClass() + " : " + ae.getMessage()); + return "error"; + } + + return "uploaded"; + } } Index: site-manage-participant-helper/src/java/org/sakaiproject/site/tool/helper/participant/rsf/Import1Producer.java =================================================================== --- site-manage-participant-helper/src/java/org/sakaiproject/site/tool/helper/participant/rsf/Import1Producer.java (revision 0) +++ site-manage-participant-helper/src/java/org/sakaiproject/site/tool/helper/participant/rsf/Import1Producer.java (revision 0) @@ -0,0 +1,86 @@ +package org.sakaiproject.site.tool.helper.participant.rsf; + +import java.util.ArrayList; +import java.util.List; + +import org.apache.commons.lang.StringUtils; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.sakaiproject.site.tool.helper.participant.impl.SiteAddParticipantHandler; +import org.sakaiproject.tool.api.SessionManager; +import org.sakaiproject.tool.api.Tool; + +import uk.ac.cam.caret.sakai.rsf.producers.FrameAdjustingProducer; +import uk.ac.cam.caret.sakai.rsf.util.SakaiURLUtil; +import uk.org.ponder.messageutil.MessageLocator; +import uk.org.ponder.rsf.components.UIBranchContainer; +import uk.org.ponder.rsf.components.UICommand; +import uk.org.ponder.rsf.components.UIContainer; +import uk.org.ponder.rsf.components.UIForm; +import uk.org.ponder.rsf.components.UIMessage; +import uk.org.ponder.rsf.components.UIVerbatim; +import uk.org.ponder.rsf.flow.ARIResult; +import uk.org.ponder.rsf.flow.ActionResultInterceptor; +import uk.org.ponder.rsf.flow.jsfnav.NavigationCase; +import uk.org.ponder.rsf.flow.jsfnav.NavigationCaseReporter; +import uk.org.ponder.rsf.view.ComponentChecker; +import uk.org.ponder.rsf.view.ViewComponentProducer; +import uk.org.ponder.rsf.viewstate.RawViewParameters; +import uk.org.ponder.rsf.viewstate.SimpleViewParameters; +import uk.org.ponder.rsf.viewstate.ViewParameters; +import uk.org.ponder.rsf.viewstate.ViewParamsReporter; + +/** + * Producer for page 1 of the user import + */ +public class Import1Producer implements ViewComponentProducer, NavigationCaseReporter, ActionResultInterceptor, ViewParamsReporter { + + /** Our log (commons). */ + private static Log M_log = LogFactory.getLog(Import1Producer.class); + + public SiteAddParticipantHandler handler; + public static final String VIEW_ID = "Import1"; + + public MessageLocator messageLocator; + public FrameAdjustingProducer frameAdjustingProducer; + public SessionManager sessionManager; + + public String getViewID() { + return VIEW_ID; + } + + public void fillComponents(UIContainer tofill, ViewParameters viewParams, ComponentChecker checker) { + + ImportViewParameters params = (ImportViewParameters) viewParams; + + UIBranchContainer content = UIBranchContainer.make(tofill, "content:"); + UIVerbatim.make(content, "import1.step1", messageLocator.getMessage("import1.step1")); + UIForm uploadForm = UIForm.make(content, "uploadform"); + UICommand.make(uploadForm, "continue", messageLocator.getMessage("import1.continue"), "#{siteAddParticipantHandler.processUploadAndCheck}"); + UICommand.make(uploadForm, "cancel", messageLocator.getMessage("gen.cancel"), "#{siteAddParticipantHandler.processCancel}"); + + if(StringUtils.equals(params.status, "error")){ + UIMessage.make(content, "import1.error", "import1.error"); + } + + + } + + public List reportNavigationCases() { + List togo = new ArrayList(); + togo.add(new NavigationCase("uploaded", new SimpleViewParameters(Import2Producer.VIEW_ID))); + togo.add(new NavigationCase("error", new ImportViewParameters(Import1Producer.VIEW_ID, "error"))); + return togo; + } + + public void interceptActionResult(ARIResult result, ViewParameters incoming, Object actionReturn) { + if ("done".equals(actionReturn)) { + Tool tool = handler.getCurrentTool(); + result.resultingView = new RawViewParameters(SakaiURLUtil.getHelperDoneURL(tool, sessionManager)); + } + } + + public ViewParameters getViewParameters() { + return new ImportViewParameters(); + } +} Property changes on: site-manage-participant-helper/src/java/org/sakaiproject/site/tool/helper/participant/rsf/Import1Producer.java ___________________________________________________________________ Added: svn:keywords + Date Revision Author HeadURL Id Added: svn:eol-style + native Index: site-manage-participant-helper/src/java/org/sakaiproject/site/tool/helper/participant/rsf/Import2Producer.java =================================================================== --- site-manage-participant-helper/src/java/org/sakaiproject/site/tool/helper/participant/rsf/Import2Producer.java (revision 0) +++ site-manage-participant-helper/src/java/org/sakaiproject/site/tool/helper/participant/rsf/Import2Producer.java (revision 0) @@ -0,0 +1,142 @@ +package org.sakaiproject.site.tool.helper.participant.rsf; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.sakaiproject.authz.api.Role; +import org.sakaiproject.site.tool.helper.participant.impl.SiteAddParticipantHandler; +import org.sakaiproject.site.tool.helper.participant.impl.ImportedUser; +import org.sakaiproject.tool.api.SessionManager; +import org.sakaiproject.tool.api.Tool; + +import uk.ac.cam.caret.sakai.rsf.producers.FrameAdjustingProducer; +import uk.ac.cam.caret.sakai.rsf.util.SakaiURLUtil; +import uk.org.ponder.messageutil.MessageLocator; +import uk.org.ponder.rsf.components.UIBranchContainer; +import uk.org.ponder.rsf.components.UICommand; +import uk.org.ponder.rsf.components.UIContainer; +import uk.org.ponder.rsf.components.UIForm; +import uk.org.ponder.rsf.components.UIInput; +import uk.org.ponder.rsf.components.UIInternalLink; +import uk.org.ponder.rsf.components.UIMessage; +import uk.org.ponder.rsf.components.UIOutput; +import uk.org.ponder.rsf.components.UIOutputMany; +import uk.org.ponder.rsf.components.UISelect; +import uk.org.ponder.rsf.components.UISelectChoice; +import uk.org.ponder.rsf.components.UISelectLabel; +import uk.org.ponder.rsf.components.decorators.UICSSDecorator; +import uk.org.ponder.rsf.components.decorators.UILabelTargetDecorator; +import uk.org.ponder.rsf.flow.ARIResult; +import uk.org.ponder.rsf.flow.ActionResultInterceptor; +import uk.org.ponder.rsf.flow.jsfnav.NavigationCase; +import uk.org.ponder.rsf.flow.jsfnav.NavigationCaseReporter; +import uk.org.ponder.rsf.view.ComponentChecker; +import uk.org.ponder.rsf.view.ViewComponentProducer; +import uk.org.ponder.rsf.viewstate.RawViewParameters; +import uk.org.ponder.rsf.viewstate.SimpleViewParameters; +import uk.org.ponder.rsf.viewstate.ViewParameters; +import uk.org.ponder.rsf.viewstate.ViewParamsReporter; +import uk.org.ponder.stringutil.StringList; + +/** + * Producer for page 1 of the user import + */ +public class Import2Producer implements ViewComponentProducer, NavigationCaseReporter, ActionResultInterceptor { + + /** Our log (commons). */ + private static Log M_log = LogFactory.getLog(Import2Producer.class); + + public SiteAddParticipantHandler handler; + public static final String VIEW_ID = "Import2"; + + public MessageLocator messageLocator; + public FrameAdjustingProducer frameAdjustingProducer; + public SessionManager sessionManager; + + public String getViewID() { + return VIEW_ID; + } + + public void fillComponents(UIContainer tofill, ViewParameters origviewparams, ComponentChecker checker) { + + UIBranchContainer content = UIBranchContainer.make(tofill, "content:"); + + List users = handler.getImportedUsers(); + + //get roles in this site + List roles = handler.getRoles(); + List roleIds = new ArrayList(); + for(Role r:roles) { + roleIds.add(r.getId()); + } + + boolean badData = false; + for(ImportedUser user: users) { + UIBranchContainer userBranch = UIBranchContainer.make(content,"userrow:",user.email); + UIOutput.make(userBranch,"fn",user.firstName); + UIOutput.make(userBranch,"ln",user.lastName); + UIOutput.make(userBranch,"email",user.email); + UIOutput.make(userBranch,"role",user.role); + + //check role is valid for this site + if(!roleIds.contains(user.role)){ + user.bad = true; + } + + if(user.bad) { + badData = true; + Map cssMap = new HashMap(); + cssMap.put("background-color","red"); + userBranch.decorate(new UICSSDecorator(cssMap)); + } + } + + if(badData) { + UIMessage.make(content, "import2.error", "import2.error"); + } else { + UIMessage.make(content, "import2.okay", "import2.okay"); + + UIForm createForm = UIForm.make(content, "createForm", ""); + + // status choice + String[] statusValues = new String[] { "active", "inactive"}; + String[] statusLabels = new String[] { + messageLocator.getMessage("sitegen.siteinfolist.active"), + messageLocator.getMessage("sitegen.siteinfolist.inactive") + }; + StringList statusItems = new StringList(); + UISelect statusSelect = UISelect.make(createForm, "select-status", null, "#{siteAddParticipantHandler.statusChoice}", handler.statusChoice); + statusSelect.optionnames = UIOutputMany.make(statusLabels); + String statusSelectID = statusSelect.getFullID(); + for (int i = 0; i < statusValues.length; ++i) { + UIBranchContainer statusRow = UIBranchContainer.make(createForm,"status-row:", Integer.toString(i)); + UISelectLabel lb = UISelectLabel.make(statusRow, "status-label", statusSelectID, i); + UISelectChoice choice =UISelectChoice.make(statusRow, "status-select", statusSelectID, i); + UILabelTargetDecorator.targetLabel(lb, choice); + statusItems.add(statusValues[i]); + } + statusSelect.optionlist.setValue(statusItems.toStringArray()); + + UICommand.make(createForm, "createButton", messageLocator.getMessage("import2.continue"), "#{siteAddParticipantHandler.processCreateImportedUsers}"); + UICommand.make(createForm, "cancel", messageLocator.getMessage("gen.cancel"), "#{siteAddParticipantHandler.processCancel}"); + } + } + + public List reportNavigationCases() { + List togo = new ArrayList(); + togo.add(new NavigationCase("uploaded", new SimpleViewParameters(Import2Producer.VIEW_ID))); + togo.add(new NavigationCase("addedtosakai", new SimpleViewParameters(Import3Producer.VIEW_ID))); + return togo; + } + + public void interceptActionResult(ARIResult result, ViewParameters incoming, Object actionReturn) { + if ("done".equals(actionReturn)) { + Tool tool = handler.getCurrentTool(); + result.resultingView = new RawViewParameters(SakaiURLUtil.getHelperDoneURL(tool, sessionManager)); + } + } +} Property changes on: site-manage-participant-helper/src/java/org/sakaiproject/site/tool/helper/participant/rsf/Import2Producer.java ___________________________________________________________________ Added: svn:keywords + Date Revision Author HeadURL Id Added: svn:eol-style + native Index: site-manage-participant-helper/src/java/org/sakaiproject/site/tool/helper/participant/rsf/Import3Producer.java =================================================================== --- site-manage-participant-helper/src/java/org/sakaiproject/site/tool/helper/participant/rsf/Import3Producer.java (revision 0) +++ site-manage-participant-helper/src/java/org/sakaiproject/site/tool/helper/participant/rsf/Import3Producer.java (revision 0) @@ -0,0 +1,94 @@ +package org.sakaiproject.site.tool.helper.participant.rsf; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.sakaiproject.site.tool.helper.participant.impl.SiteAddParticipantHandler; +import org.sakaiproject.site.tool.helper.participant.impl.ImportedUser; +import org.sakaiproject.tool.api.SessionManager; +import org.sakaiproject.tool.api.Tool; + +import uk.ac.cam.caret.sakai.rsf.producers.FrameAdjustingProducer; +import uk.ac.cam.caret.sakai.rsf.util.SakaiURLUtil; +import uk.org.ponder.messageutil.MessageLocator; +import uk.org.ponder.messageutil.TargettedMessage; +import uk.org.ponder.messageutil.TargettedMessageList; +import uk.org.ponder.rsf.components.UIBranchContainer; +import uk.org.ponder.rsf.components.UICommand; +import uk.org.ponder.rsf.components.UIContainer; +import uk.org.ponder.rsf.components.UIForm; +import uk.org.ponder.rsf.components.UIInternalLink; +import uk.org.ponder.rsf.components.UIOutput; +import uk.org.ponder.rsf.flow.ARIResult; +import uk.org.ponder.rsf.flow.ActionResultInterceptor; +import uk.org.ponder.rsf.flow.jsfnav.NavigationCase; +import uk.org.ponder.rsf.flow.jsfnav.NavigationCaseReporter; +import uk.org.ponder.rsf.view.ComponentChecker; +import uk.org.ponder.rsf.view.DefaultView; +import uk.org.ponder.rsf.view.ViewComponentProducer; +import uk.org.ponder.rsf.viewstate.RawViewParameters; +import uk.org.ponder.rsf.viewstate.SimpleViewParameters; +import uk.org.ponder.rsf.viewstate.ViewParameters; +import uk.org.ponder.rsf.viewstate.ViewParamsReporter; +import uk.org.ponder.stringutil.StringList; + +/** + * @author Adrian Fish (a.fish@lancaster.ac.uk) + */ +public class Import3Producer implements ViewComponentProducer, NavigationCaseReporter, ActionResultInterceptor { + + /** Our log (commons). */ + private static Log M_log = LogFactory.getLog(Import3Producer.class); + + public SiteAddParticipantHandler handler; + public static final String VIEW_ID = "Import3"; + + public MessageLocator messageLocator; + public FrameAdjustingProducer frameAdjustingProducer; + public SessionManager sessionManager; + + public String getViewID() { + return VIEW_ID; + } + + public void fillComponents(UIContainer tofill, ViewParameters origviewparams, ComponentChecker checker) { + + UIBranchContainer content = UIBranchContainer.make(tofill, "content:"); + + List users = handler.getImportedUsers(); + + for(ImportedUser user: users) { + UIBranchContainer userBranch = UIBranchContainer.make(content,"userrow:",user.email); + UIOutput.make(userBranch,"login",user.email); + UIOutput.make(userBranch,"fn",user.firstName); + UIOutput.make(userBranch,"ln",user.lastName); + UIOutput.make(userBranch,"role",user.role); + UIOutput.make(userBranch,"pw",user.password); + } + + UIInternalLink.make(content,"reportLink",new SimpleViewParameters(ImportReportProducer.VIEW_ID)); + + UIForm createForm = UIForm.make(content, "createForm", ""); + UICommand.make(createForm, "addToSiteButton", messageLocator.getMessage("import3.continue"), "#{siteAddParticipantHandler.processAddImportedUsersToSite}"); + UICommand.make(createForm, "cancel", messageLocator.getMessage("gen.cancel"), "#{siteAddParticipantHandler.processCancel}"); + } + + public List reportNavigationCases() { + List togo = new ArrayList(); + togo.add(new NavigationCase("uploaded", new SimpleViewParameters(Import2Producer.VIEW_ID))); + togo.add(new NavigationCase("addedtosakai", new SimpleViewParameters(Import3Producer.VIEW_ID))); + togo.add(new NavigationCase("emailnotification", new SimpleViewParameters(EmailNotiProducer.VIEW_ID))); + return togo; + } + + public void interceptActionResult(ARIResult result, ViewParameters incoming, Object actionReturn) { + if ("done".equals(actionReturn)) { + Tool tool = handler.getCurrentTool(); + result.resultingView = new RawViewParameters(SakaiURLUtil.getHelperDoneURL(tool, sessionManager)); + } + } +} Property changes on: site-manage-participant-helper/src/java/org/sakaiproject/site/tool/helper/participant/rsf/Import3Producer.java ___________________________________________________________________ Added: svn:keywords + Date Revision Author HeadURL Id Added: svn:eol-style + native Index: site-manage-participant-helper/src/java/org/sakaiproject/site/tool/helper/participant/rsf/ImportViewParameters.java =================================================================== --- site-manage-participant-helper/src/java/org/sakaiproject/site/tool/helper/participant/rsf/ImportViewParameters.java (revision 0) +++ site-manage-participant-helper/src/java/org/sakaiproject/site/tool/helper/participant/rsf/ImportViewParameters.java (revision 0) @@ -0,0 +1,30 @@ +package org.sakaiproject.site.tool.helper.participant.rsf; + +import uk.org.ponder.rsf.viewstate.SimpleViewParameters; + +/** + * View Producer for importing files + * + */ +public class ImportViewParameters extends SimpleViewParameters { + + public String status; + + + public ImportViewParameters(String viewID, String status) { + this.status= status; + this.viewID = viewID; + } + + + public ImportViewParameters(String status) { + super(); + this.status = status; + } + + + public ImportViewParameters() { + super(); + } + +} Property changes on: site-manage-participant-helper/src/java/org/sakaiproject/site/tool/helper/participant/rsf/ImportViewParameters.java ___________________________________________________________________ Added: svn:keywords + Date Revision Author HeadURL Id Added: svn:eol-style + native Index: site-manage-participant-helper/src/java/org/sakaiproject/site/tool/helper/participant/rsf/ImportReportProducer.java =================================================================== --- site-manage-participant-helper/src/java/org/sakaiproject/site/tool/helper/participant/rsf/ImportReportProducer.java (revision 0) +++ site-manage-participant-helper/src/java/org/sakaiproject/site/tool/helper/participant/rsf/ImportReportProducer.java (revision 0) @@ -0,0 +1,76 @@ +package org.sakaiproject.site.tool.helper.participant.rsf; + +import java.io.BufferedOutputStream; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.poi.hssf.usermodel.HSSFRow; +import org.apache.poi.hssf.usermodel.HSSFSheet; +import org.apache.poi.hssf.usermodel.HSSFWorkbook; +import org.sakaiproject.site.tool.helper.participant.impl.SiteAddParticipantHandler; +import org.sakaiproject.site.tool.helper.participant.impl.ImportedUser; + +import uk.org.ponder.rsf.components.UIContainer; +import uk.org.ponder.rsf.view.ComponentChecker; +import uk.org.ponder.rsf.view.ViewComponentProducer; +import uk.org.ponder.rsf.viewstate.ViewParameters; + +import javax.servlet.http.HttpServletResponse; + +/** + * @author Adrian Fish (a.fish@lancaster.ac.uk) + */ +public class ImportReportProducer implements ViewComponentProducer { + + /** Our log (commons). */ + private static Log M_log = LogFactory.getLog(ImportReportProducer.class); + + public SiteAddParticipantHandler handler; + public static final String VIEW_ID = "ImportReport"; + + private HttpServletResponse httpServletResponse; + public void setHttpServletResponse(HttpServletResponse res) { + this.httpServletResponse = res; + } + + public String getViewID() { + return VIEW_ID; + } + + public void fillComponents(UIContainer tofill, ViewParameters origviewparams, ComponentChecker checker) { + HSSFWorkbook wb = new HSSFWorkbook(); + HSSFSheet sheet = wb.createSheet(); + + HSSFRow headerRow = sheet.createRow(0); + headerRow.createCell(0).setCellValue("Login"); + headerRow.createCell(1).setCellValue("First Name"); + headerRow.createCell(2).setCellValue("Last Name"); + headerRow.createCell(3).setCellValue("Password"); + + int rowNum = 1; + for(ImportedUser user : handler.getImportedUsers()) { + HSSFRow row = sheet.createRow(rowNum++); + row.createCell(0).setCellValue(user.email); + row.createCell(1).setCellValue(user.firstName); + row.createCell(2).setCellValue(user.lastName); + row.createCell(3).setCellValue(user.password); + } + + String fileName = handler.getUserImportFilename(); + fileName = fileName.replaceAll(" ", "_"); + int dotIndex = fileName.lastIndexOf("."); + fileName = fileName.substring(0,dotIndex) + "_report.xls"; + + try { + BufferedOutputStream bos = new BufferedOutputStream(httpServletResponse.getOutputStream()); + httpServletResponse.setStatus(HttpServletResponse.SC_OK); + httpServletResponse.setContentType("application/ms-excel"); + httpServletResponse.setHeader("Content-Disposition", "filename=" + fileName); + wb.write(bos); + bos.close(); + } + catch(Exception e) { + httpServletResponse.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); + } + } +} Property changes on: site-manage-participant-helper/src/java/org/sakaiproject/site/tool/helper/participant/rsf/ImportReportProducer.java ___________________________________________________________________ Added: svn:keywords + Date Revision Author HeadURL Id Added: svn:eol-style + native Index: site-manage-participant-helper/src/java/org/sakaiproject/site/tool/helper/participant/rsf/AddProducer.java =================================================================== --- site-manage-participant-helper/src/java/org/sakaiproject/site/tool/helper/participant/rsf/AddProducer.java (revision 100779) +++ site-manage-participant-helper/src/java/org/sakaiproject/site/tool/helper/participant/rsf/AddProducer.java (working copy) @@ -22,6 +22,7 @@ import uk.org.ponder.rsf.components.UIContainer; import uk.org.ponder.rsf.components.UIForm; import uk.org.ponder.rsf.components.UIInput; +import uk.org.ponder.rsf.components.UIInternalLink; import uk.org.ponder.rsf.components.UIMessage; import uk.org.ponder.rsf.components.UIOutput; import uk.org.ponder.rsf.components.UIOutputMany; @@ -82,6 +83,8 @@ boolean isCourseSite = handler.isCourseSite(); UIBranchContainer content = UIBranchContainer.make(tofill, "content:"); + + UIInternalLink.make(content,"importLink",new SimpleViewParameters(Import1Producer.VIEW_ID)); org.sakaiproject.coursemanagement.api.CourseManagementService cms = (org.sakaiproject.coursemanagement.api.CourseManagementService) ComponentManager.get(org.sakaiproject.coursemanagement.api.CourseManagementService.class); Index: site-manage-participant-helper/src/bundle/org/sakaiproject/site/tool/participant/bundle/sitesetupgeneric.properties =================================================================== --- site-manage-participant-helper/src/bundle/org/sakaiproject/site/tool/participant/bundle/sitesetupgeneric.properties (revision 100779) +++ site-manage-participant-helper/src/bundle/org/sakaiproject/site/tool/participant/bundle/sitesetupgeneric.properties (working copy) @@ -1,5 +1,7 @@ java.theemail = The Email id must be made up of alpha numeric characters or any of !#$&'*+-=?^_`{|}~. (no spaces). java.addp = Add Participants +java.importfromfile = Import from File +java.importfromfileinstruction = Click here to import participants from a spreadsheet or csv file java.realm = The expected realm object was not found. java.isinval = ''{0}'' is invalid. ### (moot) java.nousers = No users available/selected for removal. @@ -107,4 +109,27 @@ confirm.name=Name confirm.id=Id confirm.role=Role -confirm.status=Status \ No newline at end of file +confirm.status=Status + +#Import users Vm's +import1.title = Step 1: Upload a file containing the users you wish to add +import1.step1 = Select a CSV or Excel file (.csv or .xls ONLY) containing your users details in the columns: first name, last name, email (and optionally) role. Do not include a row of column headers. +import1.error = The file you uploaded was not readable. Please check the file is of the correct format, and try again. +import1.continue = Continue +import2.firstname = First Name +import2.lastname = Last Name +import2.email = Email +import2.role = Role +import2.back = Back +import2.check = Step 2: Check that your spreadsheet is ok +import2.error = The data you supplied contained errors (highlighted in red). You need to correct these issues and start again. +import2.okay = The following users were found in the uploaded file. If this is correct, click 'Continue'. +import2.continue = Continue +import3.report = Step 3: Report +import3.createdsuccessfully = These users have been given, or already had, Sakai accounts and their login details are contained in the table below. Click on 'Download Report' to download a spreadsheet version for your records. +import3.downloadreport = Download Report +import3.continue = Continue +import3.login = Login +import3.password = Password +import3.role = Role + Index: site-manage-participant-helper/src/webapp/WEB-INF/requestContext.xml =================================================================== --- site-manage-participant-helper/src/webapp/WEB-INF/requestContext.xml (revision 100779) +++ site-manage-participant-helper/src/webapp/WEB-INF/requestContext.xml (working copy) @@ -1,6 +1,10 @@ + + + + @@ -14,6 +18,7 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + Index: site-manage-participant-helper/src/webapp/WEB-INF/web.xml =================================================================== --- site-manage-participant-helper/src/webapp/WEB-INF/web.xml (revision 100779) +++ site-manage-participant-helper/src/webapp/WEB-INF/web.xml (working copy) @@ -53,6 +53,10 @@ sakai.request org.sakaiproject.util.RequestFilter + + upload.enabled + false + sakai.request Index: site-manage-participant-helper/src/webapp/content/templates/Import2.html =================================================================== --- site-manage-participant-helper/src/webapp/content/templates/Import2.html (revision 0) +++ site-manage-participant-helper/src/webapp/content/templates/Import2.html (revision 0) @@ -0,0 +1,61 @@ + + + + Import from File - Confirm Users + + + + + + +
+
+

import2.check

+
import2.error
+
import2.okay
+ +
+ + + + + + + + + + + + + + + + + + +
First NameLast NameEmailRole
JoeBloggsjoe.bloggs@blogg.comaccess
+ +
+ + +

+ + + + + +
+ + +
+ +

+ + +

+
+
+
+ + Property changes on: site-manage-participant-helper/src/webapp/content/templates/Import2.html ___________________________________________________________________ Added: svn:mime-type + text/html Added: svn:keywords + Date Revision Author HeadURL Id Added: svn:eol-style + native Index: site-manage-participant-helper/src/webapp/content/templates/Import3.html =================================================================== --- site-manage-participant-helper/src/webapp/content/templates/Import3.html (revision 0) +++ site-manage-participant-helper/src/webapp/content/templates/Import3.html (revision 0) @@ -0,0 +1,46 @@ + + + + Import from File - Sakai Users Created + + + + + + +
+
+

import3.report

+ +
import3.createdsuccessfully
+ +
+ + + + + + + + + + + + + + +
LoginFirst NameLast NameRolePassword
joe.bloggs@blogg.comJoeBloggsguestpassword
+

import3.downloadreport

+ +
+

+ + +

+
+ +
+
+ + Property changes on: site-manage-participant-helper/src/webapp/content/templates/Import3.html ___________________________________________________________________ Added: svn:mime-type + text/html Added: svn:keywords + Date Revision Author HeadURL Id Added: svn:eol-style + native Index: site-manage-participant-helper/src/webapp/content/templates/ImportReport.html =================================================================== --- site-manage-participant-helper/src/webapp/content/templates/ImportReport.html (revision 0) +++ site-manage-participant-helper/src/webapp/content/templates/ImportReport.html (revision 0) @@ -0,0 +1,45 @@ + + + + Import from File - Sakai Users Created + + + + + + +
+
+

import3.report

+ +
import3.createdsuccessfully
+ +
+ + + + + + + + + + + + + +
LoginFirst NameLast NamePassword
joe.bloggs@blogg.comJoeBloggspassword
+

import3.downloadreport

+ +
+

+ + +

+
+ +
+
+ + Property changes on: site-manage-participant-helper/src/webapp/content/templates/ImportReport.html ___________________________________________________________________ Added: svn:mime-type + text/html Added: svn:keywords + Date Revision Author HeadURL Id Added: svn:eol-style + native Index: site-manage-participant-helper/src/webapp/content/templates/Add.html =================================================================== --- site-manage-participant-helper/src/webapp/content/templates/Add.html (revision 100779) +++ site-manage-participant-helper/src/webapp/content/templates/Add.html (working copy) @@ -16,6 +16,9 @@

Add Participant

+

msg=java.importfromfile

+

msg=java.importfromfileinstruction

+

@@ -86,4 +89,4 @@

- \ No newline at end of file + Index: site-manage-participant-helper/src/webapp/content/templates/Import1.html =================================================================== --- site-manage-participant-helper/src/webapp/content/templates/Import1.html (revision 0) +++ site-manage-participant-helper/src/webapp/content/templates/Import1.html (revision 0) @@ -0,0 +1,31 @@ + + + + Import from File - Select a file + + + + + + + +
+
+

import1.title

+ import1.step1 +
+ import1.error +
+
+ +
+

+ + +

+
+
+
+ + Property changes on: site-manage-participant-helper/src/webapp/content/templates/Import1.html ___________________________________________________________________ Added: svn:mime-type + text/html Added: svn:keywords + Date Revision Author HeadURL Id Added: svn:eol-style + native Index: site-manage-participant-helper/pom.xml =================================================================== --- site-manage-participant-helper/pom.xml (revision 100779) +++ site-manage-participant-helper/pom.xml (working copy) @@ -75,6 +75,32 @@ ${sakai.resetpass.version} provided + + org.springframework + spring + + + javax.servlet + servlet-api + + + commons-fileupload + commons-fileupload + + + org.apache.poi + poi + 3.6 + + + javax.mail + mail + 1.4.3 + + + net.sf.opencsv + opencsv + commons-lang Index: pom.xml =================================================================== --- pom.xml (revision 100779) +++ pom.xml (working copy) @@ -148,6 +148,12 @@ ${sakai.jsf.version} pom + + net.sf.opencsv + opencsv + 2.3 + compile +