package org.sakaiproject.site.tool.helper.participant.impl;
import java.util.Arrays;
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.Set;
import java.util.Vector;
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.sakaiproject.accountvalidator.logic.ValidationLogic;
import org.sakaiproject.authz.api.AuthzGroup;
import org.sakaiproject.authz.api.AuthzGroupService;
import org.sakaiproject.authz.api.AuthzPermissionException;
import org.sakaiproject.authz.api.GroupNotDefinedException;
import org.sakaiproject.authz.api.Role;
import org.sakaiproject.authz.api.SecurityService;
import org.sakaiproject.component.api.ServerConfigurationService;
import org.sakaiproject.component.cover.ComponentManager;
import org.sakaiproject.event.cover.EventTrackingService;
import org.sakaiproject.exception.IdUnusedException;
import org.sakaiproject.site.api.Site;
import org.sakaiproject.site.api.SiteService;
import org.sakaiproject.site.util.Participant;
import org.sakaiproject.site.util.SiteTypeUtil;
import org.sakaiproject.site.util.SiteParticipantHelper;
import org.sakaiproject.sitemanage.api.SiteHelper;
import org.sakaiproject.sitemanage.api.UserNotificationProvider;
import org.sakaiproject.tool.api.SessionManager;
import org.sakaiproject.tool.api.Tool;
import org.sakaiproject.tool.api.ToolManager;
import org.sakaiproject.tool.api.ToolSession;
import org.sakaiproject.user.api.User;
import org.sakaiproject.user.api.UserAlreadyDefinedException;
import org.sakaiproject.user.api.UserDirectoryService;
import org.sakaiproject.user.api.UserEdit;
import org.sakaiproject.user.api.UserIdInvalidException;
import org.sakaiproject.user.api.UserNotDefinedException;
import org.sakaiproject.user.api.UserPermissionException;
import org.sakaiproject.userauditservice.api.UserAuditRegistration;
import org.sakaiproject.userauditservice.api.UserAuditService;
import uk.org.ponder.messageutil.MessageLocator;
import uk.org.ponder.messageutil.TargettedMessage;
import uk.org.ponder.messageutil.TargettedMessageList;
/**
*
* @author
*
*/
public class SiteAddParticipantHandler {
char[] LOWER_ALPHA_ARRAY =
{
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'm', 'n', 'p',
'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'
};
char[] UPPER_ALPHA_ARRAY =
{
'A', 'B', 'C', 'E', 'F',
'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'P', 'Q', 'R', 'S', 'T', 'U', 'V',
'W', 'X', 'Y', 'Z'
};
char[] NUMBER_ARRAY =
{
'2', '3', '4', '5', '6', '7', '8', '9'
};
/*char[] SYMBOL_ARRAY =
{
'!','@', '#', '$', '%', '^', '&', '*'
};*/
/** Our log (commons). */
private static Log M_log = LogFactory.getLog(SiteAddParticipantHandler.class);
private static final String EMAIL_CHAR = "@";
public SiteService siteService = null;
public AuthzGroupService authzGroupService = null;
public ToolManager toolManager = null;
public SessionManager sessionManager = null;
public ServerConfigurationService serverConfigurationService;
private final String HELPER_ID = "sakai.tool.helper.id";
private static UserAuditRegistration userAuditRegistration = (UserAuditRegistration) ComponentManager.get("org.sakaiproject.userauditservice.api.UserAuditRegistration.sitemanage");
private static UserAuditService userAuditService = (UserAuditService) ComponentManager.get(UserAuditService.class);
public MessageLocator messageLocator;
private UserNotificationProvider notiProvider;
// Tool session attribute name used to schedule a whole page refresh.
public static final String ATTR_TOP_REFRESH = "sakai.vppa.top.refresh";
public TargettedMessageList targettedMessageList;
public void setTargettedMessageList(TargettedMessageList targettedMessageList) {
this.targettedMessageList = targettedMessageList;
}
public Site site = null;
public String officialAccountParticipant = null;
public String getOfficialAccountParticipant() {
return officialAccountParticipant;
}
private SecurityService securityService;
public void setSecurityService( SecurityService securityService )
{
this.securityService = securityService;
}
private UserDirectoryService userDirectoryService;
public void setUserDirectoryService(UserDirectoryService userDirectoryService) {
this.userDirectoryService = userDirectoryService;
}
public void setOfficialAccountParticipant(String officialAccountParticipant) {
this.officialAccountParticipant = officialAccountParticipant;
}
public String nonOfficialAccountParticipant = null;
public String getNonOfficialAccountParticipant() {
return nonOfficialAccountParticipant;
}
public void setNonOfficialAccountParticipant(
String nonOfficialAccountParticipant) {
this.nonOfficialAccountParticipant = nonOfficialAccountParticipant;
}
ValidationLogic validationLogic;
public void setValidationLogic(ValidationLogic validationLogic) {
this.validationLogic = validationLogic;
}
// for eids inside this list, don't look them up as email ids
public List<String> officialAccountEidOnly = new Vector<String>();
public List<String> getOfficialAccountEidOnly()
{
return officialAccountEidOnly;
}
public void setOfficialAccountEidOnly(List<String> officialAccountEidOnly)
{
this.officialAccountEidOnly = officialAccountEidOnly;
}
/*whether the role choice is for same role or different role */
public String roleChoice = "sameRole";
public String getRoleChoice() {
return roleChoice;
}
public void setRoleChoice(String roleChoice) {
this.roleChoice = roleChoice;
}
/*whether the same role used for all users */
public String sameRoleChoice = null;
public String getSameRoleChoice() {
return sameRoleChoice;
}
public void setSameRoleChoice(String sameRoleChoice) {
this.sameRoleChoice = sameRoleChoice;
}
/*status choice */
public String statusChoice = "active";
public String getStatusChoice() {
return statusChoice;
}
public void setStatusChoice(String sChoice) {
this.statusChoice = sChoice;
}
/* the email notification setting */
public String emailNotiChoice = Boolean.FALSE.toString();
public String getEmailNotiChoice() {
return emailNotiChoice;
}
public void setEmailNotiChoice(String emailNotiChoice) {
this.emailNotiChoice = emailNotiChoice;
}
/** realm for the site **/
public AuthzGroup realm = null;
public String siteId = null;
/** the role set for the site **/
public List<Role> roles = new Vector<Role>();
public List<Role> getRoles()
{
if (roles.isEmpty())
init();
Collections.sort(roles);
return roles;
}
public void setRoles (List<Role> roles)
{
this.roles = roles;
}
/** the user selected */
public List<UserRoleEntry> userRoleEntries = new Vector<UserRoleEntry>();
public String getUserRole(String userId)
{
String rv = "";
if (userRoleEntries != null)
{
for (UserRoleEntry entry:userRoleEntries)
{
if (entry.userEId.equals(userId))
{
rv = entry.role;
}
}
}
return rv;
}
public List<String> getUsers()
{
List<String> rv = new Vector<String>();
if (userRoleEntries != null)
{
for (UserRoleEntry entry:userRoleEntries)
{
rv.add(entry.userEId);
}
}
return rv;
}
/**
* Initialization method, just gets the current site in preparation for other calls
* @throws
*
*/
public void init() {
if (site == null) {
try {
siteId = sessionManager.getCurrentToolSession()
.getAttribute(HELPER_ID + ".siteId").toString();
}
catch (java.lang.NullPointerException npe) {
// Site ID wasn't set in the helper call!!
}
if (siteId == null) {
siteId = toolManager.getCurrentPlacement().getContext();
}
try {
site = siteService.getSite(siteId);
realm = authzGroupService.getAuthzGroup(siteService.siteReference(siteId));
// bjones86 - SAK-23257
roles = SiteParticipantHelper.getAllowedRoles( site.getType(), realm.getRoles() );
} catch (IdUnusedException e) {
// The siteId we were given was bogus
e.printStackTrace();
} catch (GroupNotDefinedException e) {
// The siteId we were given was bogus
e.printStackTrace();
}
}
}
/**
* get the site title
* @return
*/
public String getSiteTitle()
{
String rv = "";
if (site == null)
init();
if (site != null)
rv = site.getTitle();
return rv;
}
/**
* is current site a course site?
* @return
*/
public boolean isCourseSite()
{
return site != null ? SiteTypeUtil.isCourseSite(site.getType()): false;
}
/**
* get the configuration string value
* @param param
* @return
*/
public String getServerConfigurationString(String param)
{
return getServerConfigurationString(param, null);
}
/**
* get the configuration string value
* @param param
* @param defaultValue
* @return
*/
public String getServerConfigurationString(String param, String defaultValue)
{
return serverConfigurationService.getString(param, defaultValue);
}
/**
* Allows the Cancel button to return control to the tool calling this helper
* @return
*/
public String processCancel() {
ToolSession session = sessionManager.getCurrentToolSession();
session.setAttribute(ATTR_TOP_REFRESH, Boolean.TRUE);
resetTargettedMessageList();
reset();
return "done";
}
/**
* get role choice and go to difference html page based on that
* @return
*/
public String processGetParticipant() {
// reset errors
resetTargettedMessageList();
// reset user list
resetUserRolesEntries();
checkAddParticipant();
if (targettedMessageList != null && targettedMessageList.size() > 0)
{
// there is error, remain on the same page
return "";
}
else
{
// go to next step
return roleChoice;
}
}
private void resetTargettedMessageList()
{
targettedMessageList.clear();
}
private void resetUserRolesEntries()
{
userRoleEntries = new Vector<UserRoleEntry>();
}
/**
* get the same role choice and continue
* @return
*/
public String processSameRoleContinue() {
targettedMessageList.clear();
if (sameRoleChoice == null)
{
targettedMessageList.addMessage(new TargettedMessage("java.pleasechoose", null, TargettedMessage.SEVERITY_ERROR));
return null;
}
else
{
resetTargettedMessageList();
// if user doesn't have full rights, don't let him add one with site update
if (!authzGroupService.allowUpdate("/site/" + siteId)) {
if (realm == null)
init();
Role r = realm.getRole(sameRoleChoice);
if (r != null && r.isAllowed("site.upd")) {
targettedMessageList.addMessage(new TargettedMessage("java.roleperm", new Object[] { sameRoleChoice }, TargettedMessage.SEVERITY_ERROR));
return null;
}
}
if (userRoleEntries != null)
{
for (UserRoleEntry entry:userRoleEntries)
{
entry.role = sameRoleChoice;
}
}
// check whether there is a no or valid change to current user role
if (!checkCurrentUserRoleChange())
return null;
return "continue";
}
}
/**
* back to the first add participant page
* @return
*/
public String processSameRoleBack() {
resetTargettedMessageList();
return "back";
}
/**
* get the different role choice and continue
* @return
*/
public String processDifferentRoleContinue() {
resetTargettedMessageList();
if (!authzGroupService.allowUpdate("/site/" + siteId)) {
Set<String> roles = new HashSet<String>();
for (UserRoleEntry entry : userRoleEntries)
roles.add(entry.role);
for (String rolename: roles) {
Role r = realm.getRole(rolename);
if (r != null && r.isAllowed("site.upd")) {
targettedMessageList.addMessage(new TargettedMessage("java.roleperm", new Object[] { rolename }, TargettedMessage.SEVERITY_ERROR));
return null;
}
}
}
// check whether there is a no or valid change to current user role
if (!checkCurrentUserRoleChange())
return null;
return "continue";
}
private boolean checkCurrentUserRoleChange() {
boolean rv = true;
// check the change of roles whether it is valid: changed current user into role without "membership edit" permission? leaving the site without maintain role?
User currentUser = userDirectoryService.getCurrentUser();
String currentUserEid = currentUser != null ? currentUser.getEid():"";
for (UserRoleEntry entry : userRoleEntries)
{
if (currentUserEid.equals(entry.userEId))
{
String roleName = entry.role;
Role r = realm.getRole(roleName);
if (r != null && !r.isAllowed(siteService.SECURE_UPDATE_SITE_MEMBERSHIP))
{
// this seems to be down-grading current user's role from being able to update site membership into not being able to
// show alert message
targettedMessageList.addMessage(new TargettedMessage("java.roleperm.currentuser.downgrade", new Object[] {roleName}, TargettedMessage.SEVERITY_ERROR));
rv = false;
}
}
}
return rv;
}
/**
* back to the first add participant page
* @return
*/
public String processDifferentRoleBack() {
resetTargettedMessageList();
return "back";
}
/**
* get the email noti choice and continue
* @return
*/
public String processEmailNotiContinue() {
resetTargettedMessageList();
return "continue";
}
/**
* back to the previous role choice page
* @return
*/
public String processEmailNotiBack() {
resetTargettedMessageList();
if ("sameRole".equals(roleChoice))
{
return "backSameRole";
}
else
{
return "backDifferentRole";
}
}
/**
* whether the eId is considered of official account
* @param eId
* @return
*/
private boolean isOfficialAccount(String eId) {
return eId.indexOf(EMAIL_CHAR) == -1;
}
/*
* Given a list of user eids, add users to realm If the user account does
* not exist yet inside the user directory, assign role to it @return A list
* of eids for successfully added users
*/
private List<String> addUsersRealm( boolean notify) {
// return the list of user eids for successfully added user
List<String> addedUserEIds = new Vector<String>();
// this list contains all added user, their roles, and active status
List<String> addedUserInfos = new Vector<String>();
if (userRoleEntries != null && !userRoleEntries.isEmpty()) {
if (site == null)
init();
if (site != null) {
// get realm object
String realmId = site.getReference();
try {
AuthzGroup realmEdit = authzGroupService.getAuthzGroup(realmId);
boolean allowUpdate = authzGroupService.allowUpdate(realmId);
Set<String>okRoles = new HashSet<String>();
// List used for user auditing
List<String[]> userAuditList = new ArrayList<String[]>();
for (UserRoleEntry entry: userRoleEntries) {
String eId = entry.userEId;
String role =entry.role;
// this check should never trigger, as we check it earlier
// however I'm worried about users manually calling this page directly
if (!allowUpdate && !okRoles.contains(role)) {
Role r = realmEdit.getRole(role);
if (r != null && r.isAllowed("site.upd")) {
targettedMessageList.addMessage(new TargettedMessage("java.roleperm",
new Object[] { role },
TargettedMessage.SEVERITY_ERROR));
continue;
}
okRoles.add(role);
}
// SAK-23257 - display an error message if the new role is in the restricted role list
String siteType = site.getType();
Role r = realmEdit.getRole( role );
if( !SiteParticipantHelper.getAllowedRoles( siteType, realm.getRoles() ).contains( r ) )
{
targettedMessageList.addMessage( new TargettedMessage( "java.roleperm", new Object[] { role }, TargettedMessage.SEVERITY_ERROR ) );
continue;
}
try {
User user = userDirectoryService.getUserByEid(eId);
if (authzGroupService.allowUpdate(realmId)
|| siteService.allowUpdateSiteMembership(site.getId()))
{
realmEdit.addMember(user.getId(), role, statusChoice.equals("active"),
false);
addedUserEIds.add(eId);
addedUserInfos.add("uid=" + user.getId() + ";role=" + role + ";active=" + statusChoice.equals("active") + ";provided=false");
// Add the user to the list for the User Auditing Event Log
String currentUserId = userDirectoryService.getUserEid(sessionManager.getCurrentSessionUserId());
String[] userAuditString = {site.getId(),eId,role,userAuditService.USER_AUDIT_ACTION_ADD,userAuditRegistration.getDatabaseSourceKey(),currentUserId};
userAuditList.add(userAuditString);
// send notification
if (notify) {
// send notification email
notiProvider.notifyAddedParticipant(!isOfficialAccount(eId), user, site.getTitle());
}
}
} catch (UserNotDefinedException e) {
targettedMessageList.addMessage(new TargettedMessage("java.account",
new Object[] { eId },
TargettedMessage.SEVERITY_INFO));
M_log.debug(this + ".addUsersRealm: cannot find user with eid= " + eId);
} // try
} // for
try {
authzGroupService.save(realmEdit);
// do the audit logging - Doing this in one bulk call to the database will cause the actual audit stamp to be off by maybe 1 second at the most
// but seems to be a better solution than call this multiple time for every update
if (!userAuditList.isEmpty())
{
userAuditRegistration.addToUserAuditing(userAuditList);
}
// post event about adding participant
EventTrackingService.post(EventTrackingService.newEvent(SiteService.SECURE_UPDATE_SITE_MEMBERSHIP, realmEdit.getId(),false));
// check the configuration setting, whether logging membership change at individual level is allowed
if (serverConfigurationService.getBoolean(SiteHelper.WSETUP_TRACK_USER_MEMBERSHIP_CHANGE, true))
{
for(String userInfo : addedUserInfos)
{
// post the add event for each added participant
EventTrackingService.post(EventTrackingService.newEvent(SiteService.EVENT_USER_SITE_MEMBERSHIP_ADD, userInfo, true));
}
}
} catch (GroupNotDefinedException ee) {
targettedMessageList.addMessage(new TargettedMessage("java.realm",new Object[] { realmId }, TargettedMessage.SEVERITY_INFO));
M_log.warn(this + ".addUsersRealm: cannot find realm for" + realmId);
} catch (AuthzPermissionException ee) {
targettedMessageList.addMessage(new TargettedMessage("java.permeditsite",new Object[] { realmId }, TargettedMessage.SEVERITY_INFO));
M_log.warn(this + ".addUsersRealm: don't have permission to edit realm " + realmId);
}
} catch (GroupNotDefinedException eee) {
targettedMessageList.addMessage(new TargettedMessage("java.realm",new Object[] { realmId }, TargettedMessage.SEVERITY_INFO));
M_log.warn(this + ".addUsersRealm: cannot find realm for " + realmId);
} catch (Exception eee) {
M_log.warn(this + ".addUsersRealm: " + eee.getMessage() + " realmId=" + realmId);
}
}
}
return addedUserEIds;
} // addUsersRealm
/**
* get the confirm choice and continue
* @return
*/
public String processConfirmContinue() {
List<String> validationUsers = new ArrayList<String>();
resetTargettedMessageList();
if (site == null)
init();
for (UserRoleEntry entry:userRoleEntries) {
String eId = entry.userEId;
if (isOfficialAccount(eId)) {
// if this is a officialAccount
} else {
// if this is an nonOfficialAccount
try {
userDirectoryService.getUserByEid(eId);
} catch (UserNotDefinedException e) {
// if there is no such user yet, add the user
try {
UserEdit uEdit = userDirectoryService
.addUser(null, eId);
// set email address
uEdit.setEmail(eId);
// set the guest user type
uEdit.setType("guest");
// set the guest first name
String firstName = entry.firstName;
if (firstName != null && firstName.length() > 0)
uEdit.setFirstName(entry.firstName);
// set the guest last name
String lastName = entry.firstName;
if (lastName != null && lastName.length() > 0)
uEdit.setLastName(entry.lastName);
String pw = generatePassword();
uEdit.setPassword(pw);
// and save
userDirectoryService.commitEdit(uEdit);
boolean notifyNewUserEmail = (getServerConfigurationString("notifyNewUserEmail", Boolean.TRUE.toString()))
.equalsIgnoreCase(Boolean.TRUE.toString());
boolean validateUsers = serverConfigurationService.getBoolean("siteManage.validateNewUsers", true);
if (notifyNewUserEmail && !validateUsers) {
notiProvider.notifyNewUserEmail(uEdit, pw, site != null ? site.getTitle():"");
} else if (notifyNewUserEmail && validateUsers) {
validationUsers.add(uEdit.getId());
}
} catch (UserIdInvalidException ee) {
targettedMessageList.addMessage(new TargettedMessage("java.isinval",new Object[] { eId }, TargettedMessage.SEVERITY_INFO));
M_log.warn(this + ".doAdd_participant: id " + eId + " is invalid");
} catch (UserAlreadyDefinedException ee) {
targettedMessageList.addMessage(new TargettedMessage("java.beenused",new Object[] { eId }, TargettedMessage.SEVERITY_INFO));
M_log.warn(this + ".doAdd_participant: id " + eId + " has been used");
} catch (UserPermissionException ee) {
targettedMessageList.addMessage(new TargettedMessage("java.haveadd",new Object[] { eId }, TargettedMessage.SEVERITY_INFO));
M_log.warn(this + ".doAdd_participant: You don't have permission to add " + eId);
}
}
}
}
// batch add and updates the successful added list
List<String> addedParticipantEIds = addUsersRealm(Boolean.parseBoolean(emailNotiChoice));
// update the not added user list
String notAddedOfficialAccounts = "";
String notAddedNonOfficialAccounts = "";
for (UserRoleEntry entry:userRoleEntries)
{
String iEId = entry.userEId;
if (!addedParticipantEIds.contains(iEId)) {
if (isOfficialAccount(iEId)) {
// no email in eid
notAddedOfficialAccounts = notAddedOfficialAccounts
.concat(iEId + "\n");
} else {
// email in eid
notAddedNonOfficialAccounts = notAddedNonOfficialAccounts
.concat(iEId + "\n");
}
}
}
//finally send any account validations
for (int i = 0; i < validationUsers.size(); i++) {
String userId = validationUsers.get(i);
validationLogic.createValidationAccount(userId, true);
}
if (addedParticipantEIds.size() != 0
&& (!"".equals(notAddedOfficialAccounts) || !"".equals(notAddedNonOfficialAccounts))) {
// at lease one officialAccount account or an nonOfficialAccount
// account added, and there are also failures
targettedMessageList.addMessage(new TargettedMessage("java.allusers", null, TargettedMessage.SEVERITY_INFO));
}
if (targettedMessageList.size() == 0)
{
// time to reset user inputs
reset();
return "done";
}
else
{
// there is error
return "errorWithAddingParticipants";
}
}
/**
* back to the email notification page
* @return
*/
public String processConfirmBack() {
resetTargettedMessageList();
return "back";
}
/**
* Gets the current tool
* @return Tool
*/
public Tool getCurrentTool() {
return toolManager.getCurrentTool();
}
/** check the participant input **/
private void checkAddParticipant() {
// get the participants to be added
int i;
if (site == null)
init();
Vector<Participant> pList = new Vector<Participant>();
HashSet<String> existingUsers = new HashSet<String>();
// accept officialAccounts and/or nonOfficialAccount account names
String officialAccounts = "";
String nonOfficialAccounts = "";
// check that there is something with which to work
officialAccounts = StringUtils.trimToNull(officialAccountParticipant);
nonOfficialAccounts = StringUtils.trimToNull(nonOfficialAccountParticipant);
String updatedOfficialAccountParticipant = "";
String updatedNonOfficialAccountParticipant = "";
// if there is no eid or nonOfficialAccount entered
if (officialAccounts == null && nonOfficialAccounts == null) {
targettedMessageList.addMessage(new TargettedMessage("java.guest", null, TargettedMessage.SEVERITY_ERROR));
}
String at = "@";
if (officialAccounts != null) {
// adding officialAccounts
String[] officialAccountArray = officialAccounts
.split("\r\n");
for (i = 0; i < officialAccountArray.length; i++) {
String currentOfficialAccount = officialAccountArray[i];
String officialAccount = StringUtils.trimToNull(currentOfficialAccount.replaceAll("[\t\r\n]", ""));
// if there is some text, try to use it
if (officialAccount != null) {
// automatically add nonOfficialAccount account
Participant participant = new Participant();
User u = null;
StringBuffer eidsForAllMatches = new StringBuffer();
StringBuffer eidsForAllMatchesAlertBuffer = new StringBuffer();
if (officialAccount.indexOf(at) == -1)
{
// is not of email format, then look up by eid only
try {
// look for user based on eid first
u = userDirectoryService.getUserByEid(officialAccount);
} catch (UserNotDefinedException e) {
M_log.debug(this + ".checkAddParticipant: " + messageLocator.getMessage("java.username",officialAccount));
}
}
else
{
// is email. Need to lookup by both eid and email address
try {
// look for user based on eid first
u = userDirectoryService.getUserByEid(officialAccount);
} catch (UserNotDefinedException e) {
M_log.debug(this + ".checkAddParticipant: " + messageLocator.getMessage("java.username",officialAccount));
}
//Changed user lookup to satisfy BSP-1010 (jholtzman)
// continue to look for the user by their email address
// if the email address is not marked as eid only
if (!officialAccountEidOnly.contains(officialAccount))
{
Collection<User> usersWithEmail = userDirectoryService.findUsersByEmail(officialAccount);
if(usersWithEmail != null) {
if(usersWithEmail.size() == 0) {
// If the collection is empty, we didn't find any users with this email address
M_log.debug("Unable to find users with email " + officialAccount);
} else if (usersWithEmail.size() == 1) {
if (u == null)
{
// We found one user with this email address. Use it.
u = (User)usersWithEmail.iterator().next();
}
} else if (!usersWithEmail.isEmpty()) {
// If we have multiple users with this email address, expand the list with all matching user's eids and let the instructor choose from them
M_log.debug("Found multiple user with email " + officialAccount);
// multiple matches
for (User user : usersWithEmail)
{
String eid = user.getEid();
eidsForAllMatches.append(eid).append("\n");
eidsForAllMatchesAlertBuffer.append(eid).append(", ");
// this is to mark the eid so that it won't be used again for email lookup in the future
officialAccountEidOnly.add(eid);
}
// trim the alert message
String eidsForAllMatchesAlert = eidsForAllMatchesAlertBuffer.toString();
if (eidsForAllMatchesAlert.endsWith(", "))
{
eidsForAllMatchesAlert = eidsForAllMatchesAlert.substring(0, eidsForAllMatchesAlert.length()-2);
}
// update ui input
updateOfficialAccountParticipant(officialAccount, u, eidsForAllMatches.toString());
// show alert message
targettedMessageList.addMessage(new TargettedMessage("java.username.multiple",
new Object[] { officialAccount, eidsForAllMatchesAlert },
TargettedMessage.SEVERITY_INFO));
}
}
}
}
if (u != null)
{
M_log.debug("found user with eid " + u.getEid());
if (site != null && site.getUserRole(u.getId()) != null) {
// user already exists in the site, cannot be added
// again
existingUsers.add(officialAccount);
} else {
participant.name = u.getDisplayName();
participant.uniqname = u.getEid();
participant.active = true;
pList.add(participant);
}
// update the userRoleTable
if (!getUsers().contains(officialAccount) && !existingUsers.contains(officialAccount))
{
userRoleEntries.add(new UserRoleEntry(u.getEid(), ""));
// not existed user, update account
updatedOfficialAccountParticipant += currentOfficialAccount+ "\n";
}
}
else if (eidsForAllMatches.length() == 0)
{
// not valid user
targettedMessageList.addMessage(new TargettedMessage("java.username",
new Object[] { officialAccount },
TargettedMessage.SEVERITY_ERROR));
}
}
}
} // officialAccounts
if (nonOfficialAccounts != null) {
String[] nonOfficialAccountArray = nonOfficialAccounts.split("\r\n");
for (i = 0; i < nonOfficialAccountArray.length; i++) {
String currentNonOfficialAccount = nonOfficialAccountArray[i];
String nonOfficialAccountAll = StringUtils.trimToNull(currentNonOfficialAccount.replaceAll("[\t\r\n]", ""));
//there could be an empty line SAK-22497
if (nonOfficialAccountAll == null) {
continue;
}
// the format of per user entry is: email address,first name,last name
// comma separated
String[] nonOfficialAccountParts = nonOfficialAccountAll.split(",");
if (nonOfficialAccountParts.length > 3)
{
// if the input contains more fields than "email address,first name,last name", show an alert
targettedMessageList.addMessage(new TargettedMessage("add.multiple.nonofficial.alert.more",
new Object[] {nonOfficialAccountAll},
TargettedMessage.SEVERITY_ERROR));
break;
}
String userEid = nonOfficialAccountParts[0].trim();
// get last name, if any
String userLastName = "";
if (nonOfficialAccountParts.length > 1)
{
userLastName = nonOfficialAccountParts[1].trim();
}
// get first name, if any
String userFirstName = "";
if (nonOfficialAccountParts.length > 2)
{
userFirstName = nonOfficialAccountParts[2].trim();
}
// remove the trailing dots
while (userEid != null && userEid.endsWith(".")) {
userEid = userEid.substring(0, userEid.length() - 1);
}
if (userEid != null && userEid.length() > 0) {
String[] parts = userEid.split(at);
if (userEid.indexOf(at) == -1) {
// must be a valid email address
targettedMessageList.addMessage(new TargettedMessage("java.emailaddress",
new Object[] { userEid },
TargettedMessage.SEVERITY_ERROR));
} else if ((parts.length != 2) || (parts[0].length() == 0)) {
// must have both id and address part
targettedMessageList.addMessage(new TargettedMessage("java.notemailid",
new Object[] { userEid },
TargettedMessage.SEVERITY_ERROR));
} else if (!EmailValidator.getInstance().isValid(userEid)) {
targettedMessageList.addMessage(new TargettedMessage("java.emailaddress",
new Object[] { userEid },
TargettedMessage.SEVERITY_ERROR));
targettedMessageList.addMessage(new TargettedMessage("java.theemail", "no text"));
} else if (userEid != null
&& !isValidDomain(userEid)) {
// wrong string inside nonOfficialAccount id
targettedMessageList.addMessage(new TargettedMessage("java.emailbaddomain",
new Object[] { userEid, messageLocator.getMessage("nonOfficialAccountSectionTitle")},
TargettedMessage.SEVERITY_ERROR));
} else if (!isValidMail(userEid)) {
// must be a valid email address
targettedMessageList.addMessage(new TargettedMessage("java.emailaddress",
new Object[] { userEid },
TargettedMessage.SEVERITY_ERROR));
} else {
Participant participant = new Participant();
try {
// if the nonOfficialAccount user already exists
User u = userDirectoryService
.getUserByEid(userEid);
if (site != null && site.getUserRole(u.getId()) != null) {
// user already exists in the site, cannot be
// added again
existingUsers.add(userEid);
} else {
participant.name = u.getDisplayName();
participant.uniqname = userEid;
participant.active = true;
pList.add(participant);
}
} catch (UserNotDefinedException e) {
M_log.debug("no user with eid: " + userEid);
/*
* The account may exist with a different eid
*/
User u = null;
Collection<User> usersWithEmail = userDirectoryService.findUsersByEmail(userEid);
if(usersWithEmail != null) {
M_log.debug("found a collection of matching email users: " + usersWithEmail.size());
if(usersWithEmail.size() == 0) {
// If the collection is empty, we didn't find any users with this email address
M_log.info("Unable to find users with email " + userEid);
} else if (usersWithEmail.size() == 1) {
// We found one user with this email address. Use it.
u = (User)usersWithEmail.iterator().next();
} else if (usersWithEmail.size() > 1) {
// If we have multiple users with this email address, pick one and log this error condition
// TODO Should we not pick a user? Throw an exception?
M_log.warn("Found multiple user with email " + userEid);
u = (User)usersWithEmail.iterator().next();
}
}
if (u == null) {
// if the nonOfficialAccount user is not in the system
// yet
participant.name = userEid;
participant.uniqname = userEid; // TODO:
// what
// would
// the
// UDS
// case
// this
// name
// to?
// -ggolden
participant.active = true;
if (!userDirectoryService.allowAddUser())
{
targettedMessageList.addMessage(new TargettedMessage("java.haveadd",new Object[] { userEid }, TargettedMessage.SEVERITY_ERROR));
M_log.warn(this + ".checkAddParticipant: user" + userDirectoryService.getCurrentUser()!= null ? userDirectoryService.getCurrentUser().getEid():"" + " don't have permission to add " + userEid);
}
} else {
M_log.debug("adding: " + u.getDisplayName() + ", " + u.getEid());
participant.name = u.getDisplayName();
participant.uniqname = u.getEid();
participant.active = true;
userEid = u.getEid();
}
pList.add(participant);
}
// update the userRoleTable
if (!getUsers().contains(userEid) && !existingUsers.contains(userEid))
{
userRoleEntries.add(new UserRoleEntry(userEid, "", userFirstName, userLastName));
// not existed user, update account
updatedNonOfficialAccountParticipant += currentNonOfficialAccount+ "\n";
}
}
} // if
} //
} // nonOfficialAccounts
// update participant attributes
officialAccountParticipant = updatedOfficialAccountParticipant;
nonOfficialAccountParticipant = updatedNonOfficialAccountParticipant;
if ("same_role".equals(roleChoice)) {
targettedMessageList.addMessage(new TargettedMessage("java.roletype", null, TargettedMessage.SEVERITY_ERROR));
}
// remove duplicate or existing user from participant list
pList = removeDuplicateParticipants(pList);
// if the add participant list is empty after above removal, stay in the
// current page
// add alert for attempting to add existing site user(s)
if (!existingUsers.isEmpty()) {
int count = 0;
String accounts = "";
for (Iterator<String> eIterator = existingUsers.iterator(); eIterator
.hasNext();) {
if (count == 0) {
accounts = (String) eIterator.next();
} else {
accounts = accounts + ", " + (String) eIterator.next();
}
count++;
}
targettedMessageList.addMessage(new TargettedMessage("add.existingpart.1", new Object[]{accounts}, TargettedMessage.SEVERITY_INFO));
if (!pList.isEmpty())
{
// continue add
targettedMessageList.addMessage(new TargettedMessage("add.existingpart.2", null, TargettedMessage.SEVERITY_INFO));
}
else
{
// no valid user input left, prompt for more
targettedMessageList.addMessage(new TargettedMessage("java.guest", null, TargettedMessage.SEVERITY_ERROR));
}
}
return;
} // checkAddParticipant
private boolean isValidDomain(String email) {
String invalidNonOfficialAccountString = getServerConfigurationString("invalidNonOfficialAccountString", null);
if (invalidNonOfficialAccountString != null) {
String[] invalidDomains = invalidNonOfficialAccountString.split(",");
for (int i = 0; i < invalidDomains.length; i++) {
String domain = invalidDomains[i].trim();
if (email.toLowerCase().indexOf(domain.toLowerCase()) != -1) {
return false;
}
}
}
return true;
}
private boolean isValidMail(String email) {
if (email == null || "".equals(email))
return false;
email = email.trim();
EmailValidator ev = EmailValidator.getInstance();
return ev.isValid(email);
}
private Vector<Participant> removeDuplicateParticipants(List<Participant> pList) {
// check the uniqueness of list member
Set<String> s = new HashSet<String>();
Set<String> uniqnameSet = new HashSet<String>();
Vector<Participant> rv = new Vector<Participant>();
for (int i = 0; i < pList.size(); i++) {
Participant p = (Participant) pList.get(i);
if (!uniqnameSet.contains(p.getUniqname())) {
// no entry for the account yet
rv.add(p);
uniqnameSet.add(p.getUniqname());
} else {
// found duplicates
s.add(p.getUniqname());
}
}
if (!s.isEmpty()) {
int count = 0;
String accounts = "";
for (Iterator<String> i = s.iterator(); i.hasNext();) {
if (count == 0) {
accounts = (String) i.next();
} else {
accounts = accounts + ", " + (String) i.next();
}
count++;
}
targettedMessageList.addMessage(new TargettedMessage(count==1?"add.duplicatedpart.single":"add.duplicatedpart",new Object[]{accounts}, TargettedMessage.SEVERITY_INFO));
}
return rv;
}
private void reset()
{
site = null;
siteId = null;
realm = null;
roles.clear();
officialAccountParticipant = null;
officialAccountEidOnly = new Vector<String>();
nonOfficialAccountParticipant = null;
roleChoice = "sameRole";
statusChoice = "active";
sameRoleChoice = null;
emailNotiChoice = Boolean.FALSE.toString();
userRoleEntries = new Vector<UserRoleEntry>();
}
public void setNotiProvider(UserNotificationProvider notiProvider) {
this.notiProvider = notiProvider;
}
/**
* This is to update the handler's officialAccountParticipant attribute when encountering multiple users with same email address.
* The visual result is that the official account list will be expanded to include eids from all matches
*
* @param officialAccount
* @param u
*/
protected void updateOfficialAccountParticipant(String officialAccount, User u, String eidsForAllMatches)
{
if (u != null && !eidsForAllMatches.contains(u.getEid()))
{
eidsForAllMatches = u.getEid() + "\n" + eidsForAllMatches;
}
// replace the original official account entry with eids from all matches.
officialAccountParticipant = officialAccountParticipant.replaceAll(officialAccount, eidsForAllMatches);
}
/**
* generate a 9 digit password. Chars are randomly picked from lower-case/upper-case alpha lists, a numerical list, and a symbol list
* @return
*/
protected String generatePassword()
{
// set random password
int length = 9;
StringBuffer rndbuf = new StringBuffer(length);
for (int i = 0; i < length; ++i){
int chooseArray = (int) (4 * Math.random());
switch (chooseArray) {
case 0:
rndbuf.append(LOWER_ALPHA_ARRAY[(int) ( LOWER_ALPHA_ARRAY.length * Math.random())]);
break;
case 1:
rndbuf.append(UPPER_ALPHA_ARRAY[(int) ( UPPER_ALPHA_ARRAY.length * Math.random())]);
break;
case 2:
rndbuf.append(NUMBER_ARRAY[(int) ( NUMBER_ARRAY.length * Math.random())]);
break;
/*case 3:
rndbuf.append(SYMBOL_ARRAY[(int) ( SYMBOL_ARRAY.length * Math.random())]);
break;*/
default:
break;
}
}
return rndbuf.toString();
}
/**
* get the settings whether non official account users are allowed or not
* site-wide settings can override the system-wide settings
* @return
*/
public String getAllowNonOfficialAccount()
{
// get system setting first
String rv = getServerConfigurationString("nonOfficialAccount", "true");
// get site property, if different, it overrides sakai.properties setting
if (site == null) {
M_log.error("Could not get site and thus, site properties.");
}
else
{
String allowThisSiteAddNonOfficialParticipant = site.getProperties().getProperty("nonOfficialAccount");
M_log.debug("Site non-official allowed? "+allowThisSiteAddNonOfficialParticipant);
if (allowThisSiteAddNonOfficialParticipant != null && !allowThisSiteAddNonOfficialParticipant.equalsIgnoreCase(rv)) {
rv = allowThisSiteAddNonOfficialParticipant;
}
}
return rv;
}
}