Skip to content

Commit

Permalink
SAK-28184 new account tool should email users a link to activate thei…
Browse files Browse the repository at this point in the history
…r accounts

SAK-28184 adding README.md
  • Loading branch information
bjones86 committed Mar 23, 2015
1 parent 3469596 commit 6e5e083
Show file tree
Hide file tree
Showing 17 changed files with 866 additions and 130 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,10 @@ public class ValidationAccount {
*/
public static final int ACCOUNT_STATUS_PASSWORD_RESET = 5;


/**
* Status for requested accounts (non-mergeable)
**/
public static final int ACCOUNT_STATUS_REQUEST_ACCOUNT = 6;

private Long id;
private String userId;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<?xml version="1.0"?>
<emailTemplates>
<emailTemplate>
<subject>Welcome To ${localSakaiName}!</subject>
<message>Thank you for requesting an account for ${localSakaiName}, ${institution}'s learning management system. You're almost done!

To create an account, click on the following link or paste it into your favourite web browser, and fill in the form.
${url}

If you haven't requested this account, you can safely ignore this message.
</message>
<locale></locale>
</emailTemplate>
</emailTemplates>
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ public class ValidationLogicImpl implements ValidationLogic {
private static final String TEMPLATE_KEY_LEGACYUSER = "validate.legacyuser";
private static final String TEMPLATE_KEY_PASSWORDRESET = "validate.passwordreset";
private static final String TEMPLATE_KEY_DELETED = "validate.deleted";
private static final String TEMPLATE_KEY_REQUEST_ACCOUNT = "validate.requestAccount";

private static final int VALIDATION_PERIOD_MONTHS = -36;
private static Log log = LogFactory.getLog(ValidationLogicImpl.class);
Expand All @@ -98,6 +99,7 @@ public void init(){
loadTemplate("validate_legacyUser.xml", TEMPLATE_KEY_LEGACYUSER);
loadTemplate("validate_newPassword.xml", TEMPLATE_KEY_PASSWORDRESET);
loadTemplate("validate_deleted.xml", TEMPLATE_KEY_DELETED);
loadTemplate("validate_requestAccount.xml", TEMPLATE_KEY_REQUEST_ACCOUNT);

//seeing the GroupProvider is optional we need to load it here
if (groupProvider == null) {
Expand Down Expand Up @@ -494,22 +496,26 @@ public ValidationAccount createValidationAccount(String userRef,
*/
public String getPageForAccountStatus(Integer accountStatus)
{
if (accountStatus == null)
{
log.warn("can't determine which account validation page to use - accountStatus is null. Returning the legacy 'validate'");
return "validate";
}

if (accountStatus.equals(ValidationAccount.ACCOUNT_STATUS_REQUEST_ACCOUNT))
{
return "requestAccount";
}

if (!serverConfigurationService.getBoolean("accountValidator.sendLegacyLinks", false))
{
if (accountStatus != null)
if (accountStatus.equals(ValidationAccount.ACCOUNT_STATUS_PASSWORD_RESET))
{
if (accountStatus.equals(ValidationAccount.ACCOUNT_STATUS_PASSWORD_RESET))
{
return "passwordReset";
}
else
{
return "newUser";
}
return "passwordReset";
}
else
{
log.warn("can't determine which account validation page to use - accountStatus is null");
return "newUser";
}
}
return "validate";
Expand All @@ -526,6 +532,8 @@ private String getTemplateKey(Integer accountStatus) {
templateKey = TEMPLATE_KEY_LEGACYUSER;
} else if ( (ValidationAccount.ACCOUNT_STATUS_PASSWORD_RESET == accountStatus.intValue())) {
templateKey = TEMPLATE_KEY_PASSWORDRESET;
} else if ( (ValidationAccount.ACCOUNT_STATUS_REQUEST_ACCOUNT == accountStatus.intValue())) {
templateKey = TEMPLATE_KEY_REQUEST_ACCOUNT;
}
return templateKey;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ validate.welcome1=Welcome to {0}!
validate.welcome1.reset=Reset your password in {0}
validate.welcome=You have been invited to join the following site(s) in {0}:
validate.welcome.reset=You have access to the following site(s) in {0}:
validate.welcome.request=To activate your new {0} account, please complete the form below.
validate.welcome2=A new account has been reserved for you with user ID {3}.
validate.wait.newUser.1=Wait!
validate.wait.newUser.2=I already have an account in {0}
Expand Down Expand Up @@ -54,7 +55,7 @@ lastname=Last name
lastname.required=Last name is a required field
password=Password
newpassword=New password
password2=Confirm new password
password2=Confirm password

# bbailla2, bjones86 - SAK-24427
password.fail = Strength: too weak
Expand All @@ -77,3 +78,4 @@ submit.new.reset=Change password and log in
activateAccount.title=Activate your account
transferMemberships.title=Accept invitation
passwordReset.title=Reset your password
requestAccount.title=Activate your account
Original file line number Diff line number Diff line change
Expand Up @@ -197,7 +197,7 @@ public String validateAccount() {

int accountStatus = item.getAccountStatus();
//names are required in all cases except password resets
if (ValidationAccount.ACCOUNT_STATUS_NEW == accountStatus || ValidationAccount.ACCOUNT_STATUS_LEGACY_NOPASS == accountStatus)
if (ValidationAccount.ACCOUNT_STATUS_NEW == accountStatus || ValidationAccount.ACCOUNT_STATUS_LEGACY_NOPASS == accountStatus || ValidationAccount.ACCOUNT_STATUS_REQUEST_ACCOUNT == accountStatus)
{
if (firstName == null || firstName.isEmpty())
{
Expand Down Expand Up @@ -253,7 +253,7 @@ public SecurityAdvice isAllowed(String userId, String function, String reference


//if this is a new account set the password
if (ValidationAccount.ACCOUNT_STATUS_NEW == accountStatus || ValidationAccount.ACCOUNT_STATUS_LEGACY_NOPASS == accountStatus || ValidationAccount.ACCOUNT_STATUS_PASSWORD_RESET == accountStatus) {
if (ValidationAccount.ACCOUNT_STATUS_NEW == accountStatus || ValidationAccount.ACCOUNT_STATUS_LEGACY_NOPASS == accountStatus || ValidationAccount.ACCOUNT_STATUS_PASSWORD_RESET == accountStatus || ValidationAccount.ACCOUNT_STATUS_REQUEST_ACCOUNT == accountStatus) {
if (item.getPassword() == null || !item.getPassword().equals(item.getPassword2())) {
//Abandon the edit
userDirectoryService.cancelEdit(u);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ public String claimAccount() {
}

//With sendLegacyLinks disabled, the option to transfer memberships is not available for password resets
if (!serverConfigurationService.getBoolean("accountValidator.sendLegacyLinks", false) && ValidationAccount.ACCOUNT_STATUS_PASSWORD_RESET == va.getStatus())
if (!serverConfigurationService.getBoolean("accountValidator.sendLegacyLinks", false) && (ValidationAccount.ACCOUNT_STATUS_PASSWORD_RESET == va.getStatus() || ValidationAccount.ACCOUNT_STATUS_REQUEST_ACCOUNT == va.getStatus()))
{
log.warn("Was attempting to transfer memberships for a ValidationAccount of status " + va.getStatus());
return "error";
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
package org.sakaiproject.accountvalidator.tool.producers;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.sakaiproject.accountvalidator.model.ValidationAccount;
import org.sakaiproject.entitybroker.EntityReference;
import org.sakaiproject.user.api.User;
import org.sakaiproject.user.api.UserNotDefinedException;
import uk.org.ponder.messageutil.TargettedMessage;
import uk.org.ponder.rsf.components.*;
import uk.org.ponder.rsf.flow.ActionResultInterceptor;
import uk.org.ponder.rsf.view.ComponentChecker;
import uk.org.ponder.rsf.view.ViewComponentProducer;
import uk.org.ponder.rsf.viewstate.ViewParameters;


/**
* Produces requestAccount.html - builds a form that allows the user to claim an account that has been created for them
* @author bbailla2
*/
public class RequestAccountProducer extends BaseValidationProducer implements ViewComponentProducer, ActionResultInterceptor
{
private static final Log log = LogFactory.getLog(RequestAccountProducer.class);
public static final String VIEW_ID = "requestAccount";

public String getViewID()
{
return VIEW_ID;
}

public void init()
{

}

public void fillComponents(UIContainer tofill, ViewParameters viewparams, ComponentChecker checker)
{
Object[] args = new Object[]{serverConfigurationService.getString("ui.service", "Sakai")};
UIMessage.make(tofill, "welcome1", "validate.welcome1", args);
UIMessage.make(tofill, "welcome2", "validate.welcome.request", args);

ValidationAccount va = getValidationAccount(viewparams, tml);
if (va == null)
{
// handled by getValidationAccount
return;
}
else if (!va.getAccountStatus().equals(ValidationAccount.ACCOUNT_STATUS_REQUEST_ACCOUNT))
{
// this form is not appropriate
args = new Object[] {va.getValidationToken()};
// no such validation of the required account status
tml.addMessage(new TargettedMessage("msg.noSuchValidation", args, TargettedMessage.SEVERITY_ERROR));
return;
}
else if (ValidationAccount.STATUS_CONFIRMED.equals(va.getStatus()))
{
args = new Object[] {va.getValidationToken()};
tml.addMessage(new TargettedMessage("msg.alreadyValidated", args, TargettedMessage.SEVERITY_ERROR));
return ;
}
else if (sendLegacyLinksEnabled())
{
// Ignore; the request account feature should work independently of legacy links
}

User u = null;
try
{
u = userDirectoryService.getUser(EntityReference.getIdFromRef(va.getUserId()));
}
catch (UserNotDefinedException e)
{
log.error("user ID does not exist for ValidationAccount with tokenId: " + va.getValidationToken());
tml.addMessage(new TargettedMessage("validate.userNotDefined", new Object[]{}, TargettedMessage.SEVERITY_ERROR));
}

if (u != null)
{
// we need some values to fill in. The nulls are placeholders. Other UIs use the same message with createdBy.getDisplayName() and createdBy.getEmailAddress().
args = new Object[]{
serverConfigurationService.getString("ui.service", "Sakai"),
null,
null,
u.getDisplayId()
};

UIForm detailsForm = UIForm.make(tofill, "setDetailsForm");

UICommand.make(detailsForm, "addDetailsSub", UIMessage.make("submit.new.account"), "accountValidationLocator.validateAccount");

String otp = "accountValidationLocator." + va.getId();
UIMessage.make(detailsForm, "username.new", "username.new", args);
UIOutput.make(detailsForm, "eid", u.getDisplayId());

UIInput.make(detailsForm, "firstName", otp + ".firstName", u.getFirstName());
UIInput.make(detailsForm, "surName", otp + ".surname", u.getLastName());

boolean passwordPolicyEnabled = userDirectoryService.getPasswordPolicy() != null;
String passwordPolicyEnabledJavaScript = "VALIDATOR.isPasswordPolicyEnabled = " + Boolean.toString(passwordPolicyEnabled) + ";";
UIVerbatim.make(tofill, "passwordPolicyEnabled", passwordPolicyEnabledJavaScript);

UIBranchContainer row1 = UIBranchContainer.make(detailsForm, "passrow1:");
UIInput.make(row1, "password1", otp + ".password");

UIBranchContainer row2 = UIBranchContainer.make(detailsForm, "passrow2:");
UIInput.make(row2, "password2", otp + ".password2");

// If we have some terms, get the user to accept them.
if (!"".equals(serverConfigurationService.getString("account-validator.terms")))
{
String termsURL = serverConfigurationService.getString("account-validator.terms");
UIBranchContainer termsRow = UIBranchContainer.make(detailsForm, "termsrow:");

UIBoundBoolean.make(termsRow, "terms", otp + ".terms");
// If someone wants to re-write this to be RSF like great, but this works.
// Although it doesn't escape the bundle strings.
String terms = messageLocator.getMessage("terms", new Object[]
{
"<a href='" + termsURL + "' target='_new'>" + messageLocator.getMessage("terms.link")+"</a>"
});
UIVerbatim.make(termsRow, "termsLabel", terms);
}

detailsForm.parameters.add(new UIELBinding(otp + ".userId", va.getUserId()));
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,17 @@
<property name="springMessageLocator" ref="messageLocator"/>
</bean>

<bean class="org.sakaiproject.accountvalidator.tool.producers.RequestAccountProducer" init-method="init">
<property name="userDirectoryService" ref="org.sakaiproject.user.api.UserDirectoryService"/>
<property name="validationLogic" ref="org.sakaiproject.accountvalidator.logic.ValidationLogic"/>
<property name="targettedMessageList" ref="targettedMessageList"/>
<property name="authzGroupService" ref="org.sakaiproject.authz.api.AuthzGroupService"/>
<property name="siteService" ref="org.sakaiproject.site.api.SiteService"/>
<property name="serverConfigurationService" ref="org.sakaiproject.component.api.ServerConfigurationService"/>
<property name="developerHelperService" ref="org.sakaiproject.entitybroker.DeveloperHelperService"/>
<property name="springMessageLocator" ref="messageLocator"/>
</bean>

<bean name="accountValidationLocator" class="org.sakaiproject.accountvalidator.tool.otp.AcountValidationLocator">
<property name="validationLogic" ref="org.sakaiproject.accountvalidator.logic.ValidationLogic"/>
<property name="userDirectoryService" ref="org.sakaiproject.user.api.UserDirectoryService"/>
Expand Down
Loading

0 comments on commit 6e5e083

Please sign in to comment.