NIHVIVO-2279 Implement Add Account (no associations) and Delete Accounts.

This commit is contained in:
j2blake 2011-05-24 21:15:56 +00:00
parent 3fbbd561c5
commit 0aef0368c6
12 changed files with 426 additions and 90 deletions

View file

@ -7,6 +7,8 @@ import java.util.Collections;
import java.util.HashSet; import java.util.HashSet;
import java.util.Set; import java.util.Set;
import edu.cornell.mannlib.vitro.webapp.controller.authenticate.Authenticator;
/** /**
* Information about the account of a user. URI, email, password, etc. * Information about the account of a user. URI, email, password, etc.
*/ */
@ -107,6 +109,11 @@ public class UserAccount {
return passwordLinkExpires; return passwordLinkExpires;
} }
public String getPasswordLinkExpiresHash() {
return Authenticator.applyMd5Encoding(String
.valueOf(passwordLinkExpires));
}
public void setPasswordLinkExpires(long passwordLinkExpires) { public void setPasswordLinkExpires(long passwordLinkExpires) {
this.passwordLinkExpires = Math.max(0, passwordLinkExpires); this.passwordLinkExpires = Math.max(0, passwordLinkExpires);
} }

View file

@ -16,11 +16,6 @@ import edu.cornell.mannlib.vitro.webapp.controller.freemarker.responsevalues.Tem
* Handle the "Add new account" form display and submission. * Handle the "Add new account" form display and submission.
* *
* TODO Associate a profile from this account * TODO Associate a profile from this account
*
* TODO Handle sending of email.
*
* TODO Handle initial password set if email isn't available. Set password
* fields, change-required flag, account is active.
*/ */
public class UserAccountsAddPage extends UserAccountsPage { public class UserAccountsAddPage extends UserAccountsPage {
private static final String PARAMETER_SUBMIT = "submitAdd"; private static final String PARAMETER_SUBMIT = "submitAdd";
@ -38,6 +33,8 @@ public class UserAccountsAddPage extends UserAccountsPage {
private static final String TEMPLATE_NAME = "userAccounts-add.ftl"; private static final String TEMPLATE_NAME = "userAccounts-add.ftl";
private final UserAccountsAddPageStrategy strategy;
/* The request parameters */ /* The request parameters */
private boolean submit; private boolean submit;
private String emailAddress = ""; private String emailAddress = "";
@ -46,14 +43,18 @@ public class UserAccountsAddPage extends UserAccountsPage {
private String selectedRoleUri = ""; private String selectedRoleUri = "";
private boolean associateWithProfile; private boolean associateWithProfile;
/* The result of validating a "submit" request. */ /** The result of validating a "submit" request. */
private String errorCode = ""; private String errorCode = "";
/** The new user account, if one was created. */
private UserAccount addedAccount;
public UserAccountsAddPage(VitroRequest vreq) { public UserAccountsAddPage(VitroRequest vreq) {
super(vreq); super(vreq);
}
public void parseParametersAndValidate() { this.strategy = UserAccountsAddPageStrategy.getInstance(this,
isEmailEnabled(vreq));
parseRequestParameters(); parseRequestParameters();
if (submit) { if (submit) {
@ -68,6 +69,8 @@ public class UserAccountsAddPage extends UserAccountsPage {
lastName = getStringParameter(PARAMETER_LAST_NAME, ""); lastName = getStringParameter(PARAMETER_LAST_NAME, "");
selectedRoleUri = getRoleChoices(); selectedRoleUri = getRoleChoices();
associateWithProfile = getAssociateFlag(); associateWithProfile = getAssociateFlag();
strategy.parseAdditionalParameters();
} }
public boolean isSubmit() { public boolean isSubmit() {
@ -85,6 +88,8 @@ public class UserAccountsAddPage extends UserAccountsPage {
errorCode = ERROR_NO_LAST_NAME; errorCode = ERROR_NO_LAST_NAME;
} else if (selectedRoleUri.isEmpty()) { } else if (selectedRoleUri.isEmpty()) {
errorCode = ERROR_NO_ROLE; errorCode = ERROR_NO_ROLE;
} else {
errorCode = strategy.additionalValidations();
} }
} }
@ -96,24 +101,28 @@ public class UserAccountsAddPage extends UserAccountsPage {
return errorCode.isEmpty(); return errorCode.isEmpty();
} }
public UserAccount createNewAccount() { public void createNewAccount() {
UserAccount u = new UserAccount(); UserAccount u = new UserAccount();
u.setEmailAddress(emailAddress); u.setEmailAddress(emailAddress);
u.setFirstName(firstName); u.setFirstName(firstName);
u.setLastName(lastName); u.setLastName(lastName);
u.setExternalAuthId(""); u.setExternalAuthId("");
u.setMd5Password(""); u.setMd5Password("");
u.setOldPassword(""); u.setOldPassword("");
u.setPasswordChangeRequired(false); u.setPasswordChangeRequired(false);
u.setPasswordLinkExpires(0); u.setPasswordLinkExpires(0);
u.setLoginCount(0); u.setLoginCount(0);
u.setStatus(Status.INACTIVE); u.setStatus(Status.INACTIVE);
u.setPermissionSetUris(Collections.singleton(selectedRoleUri)); u.setPermissionSetUris(Collections.singleton(selectedRoleUri));
strategy.setAdditionalProperties(u);
String uri = userAccountsDao.insertUserAccount(u); String uri = userAccountsDao.insertUserAccount(u);
return userAccountsDao.getUserAccountByUri(uri); this.addedAccount = userAccountsDao.getUserAccountByUri(uri);
strategy.notifyUser();
} }
/** What role are they asking for? */ /** What role are they asking for? */
@ -132,40 +141,34 @@ public class UserAccountsAddPage extends UserAccountsPage {
PARAMETER_ASSOCIATE_WITH_PROFILE, "no")); PARAMETER_ASSOCIATE_WITH_PROFILE, "no"));
} }
public ResponseValues showPage() { public final ResponseValues showPage() {
Map<String, Object> body = new HashMap<String, Object>(); Map<String, Object> body = new HashMap<String, Object>();
body.put("emailAddress", emailAddress); body.put("emailAddress", emailAddress);
body.put("firstName", firstName); body.put("firstName", firstName);
body.put("lastName", lastName); body.put("lastName", lastName);
body.put("selectedRole", selectedRoleUri); body.put("selectedRole", selectedRoleUri);
body.put("associate", associateWithProfile); if (associateWithProfile) {
body.put("associate", Boolean.TRUE);
}
body.put("roles", buildRolesList()); body.put("roles", buildRolesList());
body.put("formUrls", buildUrlsMap()); body.put("formUrls", buildUrlsMap());
if (!errorCode.isEmpty()) { if (!errorCode.isEmpty()) {
body.put(errorCode, Boolean.TRUE); body.put(errorCode, Boolean.TRUE);
} }
strategy.addMoreBodyValues(body);
return new TemplateResponseValues(TEMPLATE_NAME, body); return new TemplateResponseValues(TEMPLATE_NAME, body);
} }
/**
* @return
*/
public UserAccount getAddedAccount() { public UserAccount getAddedAccount() {
// TODO Auto-generated method stub return addedAccount;
throw new RuntimeException("UserAccountsAddPage.getAddedAccount() not implemented.");
} }
/**
* @return
*/
public boolean wasPasswordEmailSent() { public boolean wasPasswordEmailSent() {
// TODO Auto-generated method stub return this.strategy.wasPasswordEmailSent();
throw new RuntimeException("UserAccountsAddPage.wasPasswordEmailSent() not implemented.");
} }
} }

View file

@ -0,0 +1,197 @@
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
package edu.cornell.mannlib.vitro.webapp.controller.accounts;
import static javax.mail.Message.RecipientType.TO;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import edu.cornell.mannlib.vitro.webapp.beans.UserAccount;
import edu.cornell.mannlib.vitro.webapp.beans.UserAccount.Status;
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.UrlBuilder;
import edu.cornell.mannlib.vitro.webapp.email.FreemarkerEmailFactory;
import edu.cornell.mannlib.vitro.webapp.email.FreemarkerEmailMessage;
/**
* Handle the variant details of the UserAccountsAddPage.
*/
public abstract class UserAccountsAddPageStrategy {
protected final UserAccountsAddPage page;
public static UserAccountsAddPageStrategy getInstance(
UserAccountsAddPage page, boolean emailEnabled) {
if (emailEnabled) {
return new EmailStrategy(page);
} else {
return new NoEmailStrategy(page);
}
}
public UserAccountsAddPageStrategy(UserAccountsAddPage page) {
this.page = page;
}
protected abstract void parseAdditionalParameters();
protected abstract String additionalValidations();
protected abstract void addMoreBodyValues(Map<String, Object> body);
protected abstract void setAdditionalProperties(UserAccount u);
protected abstract void notifyUser();
protected abstract boolean wasPasswordEmailSent();
// ----------------------------------------------------------------------
// Strategy to use if email is enabled.
// ----------------------------------------------------------------------
private static class EmailStrategy extends UserAccountsAddPageStrategy {
public static final String CREATE_PASSWORD_URL = "/userAccounts/createPassword";
private boolean sentEmail;
public EmailStrategy(UserAccountsAddPage page) {
super(page);
}
@Override
protected void parseAdditionalParameters() {
// No additional parameters
}
@Override
protected String additionalValidations() {
// No additional validations
return "";
}
@Override
protected void setAdditionalProperties(UserAccount u) {
u.setPasswordLinkExpires(new Date().getTime());
u.setStatus(Status.INACTIVE);
}
@Override
protected void addMoreBodyValues(Map<String, Object> body) {
body.put("emailIsEnabled", Boolean.TRUE);
}
@Override
protected void notifyUser() {
Map<String, Object> body = new HashMap<String, Object>();
body.put("userAccount", page.getAddedAccount());
body.put("passwordLink", buildCreatePasswordLink());
body.put("subjectLine", "Your VIVO account has been created.");
FreemarkerEmailMessage email = FreemarkerEmailFactory
.createNewMessage(page.vreq);
email.addRecipient(TO, page.getAddedAccount().getEmailAddress());
email.setSubject("Your VIVO account has been created.");
email.setHtmlTemplate("userAccounts-createdEmail-html.ftl");
email.setTextTemplate("userAccounts-createdEmail-text.ftl");
email.setBodyMap(body);
email.send();
sentEmail = true;
}
private String buildCreatePasswordLink() {
try {
String uri = page.getAddedAccount().getUri();
String hash = page.getAddedAccount()
.getPasswordLinkExpiresHash();
String relativeUrl = UrlBuilder.getUrl(CREATE_PASSWORD_URL, "user",
uri, "key", hash);
URL context = new URL(page.vreq.getRequestURL().toString());
URL url = new URL(context, relativeUrl);
return url.toExternalForm();
} catch (MalformedURLException e) {
return "error_creating_password_link";
}
}
@Override
protected boolean wasPasswordEmailSent() {
return sentEmail;
}
}
// ----------------------------------------------------------------------
// Strategy to use if email is not enabled.
// ----------------------------------------------------------------------
private static class NoEmailStrategy extends UserAccountsAddPageStrategy {
private static final String PARAMETER_INITIAL_PASSWORD = "initialPassword";
private static final String PARAMETER_CONFIRM_PASSWORD = "confirmPassword";
private static final String ERROR_NO_PASSWORD = "errorPasswordIsEmpty";
private static final String ERROR_WRONG_PASSWORD_LENGTH = "errorPasswordIsWrongLength";
private static final String ERROR_PASSWORDS_DONT_MATCH = "errorPasswordsDontMatch";
private String initialPassword;
private String confirmPassword;
public NoEmailStrategy(UserAccountsAddPage page) {
super(page);
}
@Override
protected void parseAdditionalParameters() {
initialPassword = page.getStringParameter(
PARAMETER_INITIAL_PASSWORD, "");
confirmPassword = page.getStringParameter(
PARAMETER_CONFIRM_PASSWORD, "");
}
@Override
protected String additionalValidations() {
if (initialPassword.isEmpty()) {
return ERROR_NO_PASSWORD;
} else if (!checkPasswordLength()) {
return ERROR_WRONG_PASSWORD_LENGTH;
} else if (!initialPassword.equals(confirmPassword)) {
return ERROR_PASSWORDS_DONT_MATCH;
} else {
return "";
}
}
private boolean checkPasswordLength() {
return initialPassword.length() >= UserAccount.MIN_PASSWORD_LENGTH
&& initialPassword.length() <= UserAccount.MAX_PASSWORD_LENGTH;
}
@Override
protected void addMoreBodyValues(Map<String, Object> body) {
body.put("initialPassword", initialPassword);
body.put("confirmPassword", confirmPassword);
}
@Override
protected void setAdditionalProperties(UserAccount u) {
u.setMd5Password(initialPassword);
u.setPasswordChangeRequired(true);
u.setStatus(Status.ACTIVE);
}
@Override
protected void notifyUser() {
// Do nothing.
}
@Override
protected boolean wasPasswordEmailSent() {
return false;
}
}
}

View file

@ -39,50 +39,52 @@ public class UserAccountsController extends FreemarkerHttpServlet {
log.debug("action = '" + action + "'"); log.debug("action = '" + action + "'");
if (ACTION_ADD.equals(action)) { if (ACTION_ADD.equals(action)) {
UserAccountsAddPage page = new UserAccountsAddPage(vreq); return handleAddRequest(vreq);
page.parseParametersAndValidate();
if (page.isSubmit() && page.isValid()) {
return addAccountAndShowList(vreq, page);
} else {
return page.showPage();
}
} else if (ACTION_EDIT.equals(action)) { } else if (ACTION_EDIT.equals(action)) {
UserAccountsEditPage page = new UserAccountsEditPage(vreq); return handleEditRequest(vreq);
page.parseParametersAndValidate();
if (page.isSubmit() && page.isValid()) {
return editAccountAndShowList(vreq, page);
} else {
return page.showPage();
}
} else if (ACTION_DELETE.equals(action)) { } else if (ACTION_DELETE.equals(action)) {
UserAccountsDeleter deleter = new UserAccountsDeleter(vreq); return handleDeleteRequest(vreq);
Collection<String> deletedUris = deleter.delete(); } else {
return handleListRequest(vreq);
return new UserAccountsListPage(vreq) }
.showPageWithDeletions(deletedUris); }
private ResponseValues handleAddRequest(VitroRequest vreq) {
UserAccountsAddPage page = new UserAccountsAddPage(vreq);
if (page.isSubmit() && page.isValid()) {
page.createNewAccount();
UserAccountsListPage listPage = new UserAccountsListPage(vreq);
return listPage.showPageWithNewAccount(page.getAddedAccount(),
page.wasPasswordEmailSent());
} else { } else {
UserAccountsListPage page = new UserAccountsListPage(vreq);
return page.showPage(); return page.showPage();
} }
} }
private ResponseValues addAccountAndShowList(VitroRequest vreq, private ResponseValues handleEditRequest(VitroRequest vreq) {
UserAccountsAddPage addPage) { UserAccountsEditPage page = new UserAccountsEditPage(vreq);
addPage.createNewAccount(); page.parseParametersAndValidate();
if (page.isSubmit() && page.isValid()) {
UserAccountsListPage listPage = new UserAccountsListPage(vreq); page.updateAccount();
return listPage.showPageWithNewAccount(addPage.getAddedAccount(), UserAccountsListPage listPage = new UserAccountsListPage(vreq);
addPage.wasPasswordEmailSent()); return listPage.showPageWithUpdatedAccount(
page.getUpdatedAccount(), page.wasPasswordEmailSent());
} else {
return page.showPage();
}
} }
private ResponseValues editAccountAndShowList(VitroRequest vreq, private ResponseValues handleDeleteRequest(VitroRequest vreq) {
UserAccountsEditPage editPage) { UserAccountsDeleter deleter = new UserAccountsDeleter(vreq);
editPage.updateAccount(); Collection<String> deletedUris = deleter.delete();
UserAccountsListPage listPage = new UserAccountsListPage(vreq);
return listPage.showPageWithUpdatedAccount( return new UserAccountsListPage(vreq)
editPage.getUpdatedAccount(), editPage.wasPasswordEmailSent()); .showPageWithDeletions(deletedUris);
}
private ResponseValues handleListRequest(VitroRequest vreq) {
UserAccountsListPage page = new UserAccountsListPage(vreq);
return page.showPage();
} }
} }

View file

@ -2,29 +2,51 @@
package edu.cornell.mannlib.vitro.webapp.controller.accounts; package edu.cornell.mannlib.vitro.webapp.controller.accounts;
import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.List;
import edu.cornell.mannlib.vitro.webapp.beans.UserAccount;
import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest; import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest;
import edu.cornell.mannlib.vitro.webapp.dao.UserAccountsDao;
import edu.cornell.mannlib.vitro.webapp.dao.WebappDaoFactory;
/** /**
* TODO delete and kick to Accounts list with message, telling how many were * Process a request to delete User Accounts.
* deleted. If there was a problem, the user will need to infer it from the
* count??
*/ */
public class UserAccountsDeleter extends UserAccountsPage { public class UserAccountsDeleter extends UserAccountsPage {
private static final String PARAMETER_DELETE_ACCOUNT = "deleteAccount";
/** Might be empty, but never null. */
private final String[] uris;
protected UserAccountsDeleter(VitroRequest vreq) { protected UserAccountsDeleter(VitroRequest vreq) {
super(vreq); super(vreq);
String[] values = vreq.getParameterValues(PARAMETER_DELETE_ACCOUNT);
if (values == null) {
this.uris = new String[0];
} else {
this.uris = values;
}
} }
/**
* @return
*
*/
public Collection<String> delete() { public Collection<String> delete() {
// TODO Auto-generated method stub List<String> deletedUris = new ArrayList<String>();
throw new RuntimeException(
"UserAccountsDeleter.delete() not implemented."); WebappDaoFactory wadf = vreq.getWebappDaoFactory();
UserAccountsDao dao = wadf.getUserAccountsDao();
for (String uri: uris) {
UserAccount u = dao.getUserAccountByUri(uri);
if (u != null) {
dao.deleteUserAccount(uri);
deletedUris.add(uri);
}
}
return deletedUris;
} }
} }

View file

@ -54,12 +54,13 @@ public class UserAccountsListPage extends UserAccountsPage {
public UserAccountsListPage(VitroRequest vreq) { public UserAccountsListPage(VitroRequest vreq) {
super(vreq); super(vreq);
parseParameters();
} }
/** /**
* Build the criteria from the request parameters. * Build the criteria from the request parameters.
*/ */
public void parseParameters() { private void parseParameters() {
int accountsPerPage = getIntegerParameter(PARAMETER_ACCOUNTS_PER_PAGE, int accountsPerPage = getIntegerParameter(PARAMETER_ACCOUNTS_PER_PAGE,
DEFAULT_ACCOUNTS_PER_PAGE); DEFAULT_ACCOUNTS_PER_PAGE);
int pageIndex = getIntegerParameter(PARAMETER_PAGE_INDEX, 1); int pageIndex = getIntegerParameter(PARAMETER_PAGE_INDEX, 1);
@ -76,6 +77,7 @@ public class UserAccountsListPage extends UserAccountsPage {
criteria = new UserAccountsSelectionCriteria(accountsPerPage, criteria = new UserAccountsSelectionCriteria(accountsPerPage,
pageIndex, ordering, roleFilterUri, searchTerm); pageIndex, ordering, roleFilterUri, searchTerm);
log.debug("selection criteria is: " + criteria);
} }
/** /**

View file

@ -2,7 +2,6 @@
package edu.cornell.mannlib.vitro.webapp.controller.accounts; package edu.cornell.mannlib.vitro.webapp.controller.accounts;
/** /**
* How are the accounts to be sorted? * How are the accounts to be sorted?
*/ */
@ -78,4 +77,10 @@ public class UserAccountsOrdering {
public Direction getDirection() { public Direction getDirection() {
return direction; return direction;
} }
@Override
public String toString() {
return "UserAccountsOrdering[field=" + field + ", direction="
+ direction + "]";
}
} }

View file

@ -10,6 +10,7 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import javax.servlet.ServletContext; import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.LogFactory;
@ -22,6 +23,7 @@ import edu.cornell.mannlib.vitro.webapp.controller.freemarker.UrlBuilder;
import edu.cornell.mannlib.vitro.webapp.dao.UserAccountsDao; import edu.cornell.mannlib.vitro.webapp.dao.UserAccountsDao;
import edu.cornell.mannlib.vitro.webapp.dao.WebappDaoFactory; import edu.cornell.mannlib.vitro.webapp.dao.WebappDaoFactory;
import edu.cornell.mannlib.vitro.webapp.dao.jena.OntModelSelector; import edu.cornell.mannlib.vitro.webapp.dao.jena.OntModelSelector;
import edu.cornell.mannlib.vitro.webapp.email.FreemarkerEmailFactory;
/** /**
* Common routines for the page controllers. * Common routines for the page controllers.
@ -47,6 +49,10 @@ public abstract class UserAccountsPage {
userAccountsDao = wdf.getUserAccountsDao(); userAccountsDao = wdf.getUserAccountsDao();
} }
protected static boolean isEmailEnabled(HttpServletRequest req) {
return FreemarkerEmailFactory.isConfigured(req);
}
protected String getStringParameter(String key, String defaultValue) { protected String getStringParameter(String key, String defaultValue) {
String value = vreq.getParameter(key); String value = vreq.getParameter(key);
return (value == null) ? defaultValue : value; return (value == null) ? defaultValue : value;
@ -74,7 +80,7 @@ public abstract class UserAccountsPage {
String value = vreq.getParameter(key); String value = vreq.getParameter(key);
return (value != null); return (value != null);
} }
/** /**
* Create a list of all known PermissionSets. * Create a list of all known PermissionSets.
*/ */
@ -94,13 +100,11 @@ public abstract class UserAccountsPage {
* Make these URLs available to all of the pages. * Make these URLs available to all of the pages.
*/ */
protected Map<String, String> buildUrlsMap() { protected Map<String, String> buildUrlsMap() {
UrlBuilder urlBuilder = new UrlBuilder(vreq.getAppBean());
Map<String, String> map = new HashMap<String, String>(); Map<String, String> map = new HashMap<String, String>();
map.put("list", urlBuilder.getPortalUrl("/userAccounts/list")); map.put("list", UrlBuilder.getUrl("/userAccounts/list"));
map.put("add", urlBuilder.getPortalUrl("/userAccounts/add")); map.put("add", UrlBuilder.getUrl("/userAccounts/add"));
map.put("delete", urlBuilder.getPortalUrl("/userAccounts/delete")); map.put("delete", UrlBuilder.getUrl("/userAccounts/delete"));
return map; return map;
} }

View file

@ -75,4 +75,11 @@ public class UserAccountsSelectionCriteria {
return (t == null) ? nullValue : t; return (t == null) ? nullValue : t;
} }
@Override
public String toString() {
return "UserAccountsSelectionCriteria[accountsPerPage="
+ accountsPerPage + ", pageIndex=" + pageIndex + ", orderBy="
+ orderBy + ", roleFilterUri='" + roleFilterUri
+ "', searchTerm='" + searchTerm + "']";
}
} }

View file

@ -24,6 +24,18 @@
<#assign errorMessage = "You must select a role." /> <#assign errorMessage = "You must select a role." />
</#if> </#if>
<#if errorPasswordIsEmpty??>
<#assign errorMessage = "No password supplied." />
</#if>
<#if errorPasswordIsWrongLength??>
<#assign errorMessage = "Password must be between 6 and 12 characters." />
</#if>
<#if errorPasswordsDontMatch??>
<#assign errorMessage = "Passwords do not match." />
</#if>
<#if errorMessage?has_content> <#if errorMessage?has_content>
<section id="error-alert" role="alert"> <section id="error-alert" role="alert">
<img src="${urls.images}/iconAlert.png" width="24" height="24" alert="Error alert icon"/> <img src="${urls.images}/iconAlert.png" width="24" height="24" alert="Error alert icon"/>
@ -48,10 +60,20 @@
Roles * Roles *
<br/> <br/>
<#list roles as role> <#list roles as role>
<input type="radio" name="role" value="${role.uri}" <#if selectedRole = role.uri>selected</#if> />${role.label} <input type="radio" name="role" value="${role.uri}" <#if selectedRole = role.uri>checked</#if> />${role.label}
<br> <br>
</#list> </#list>
<br/> <br/>
<#if !emailIsEnabled??>
Initial password *
<input type="password" name="initialPassword" value="${initialPassword}" />
<br/>
Confirm initial password *
<input type="password" name="confirmPassword" value="${confirmPassword}" />
<br/>
</#if>
Associate a profile with this account Associate a profile with this account
<br/> <br/>
<input type="radio" name="associate" value="yes" <#if associate??>checked</#if> />Yes <input type="radio" name="associate" value="yes" <#if associate??>checked</#if> />Yes
@ -59,11 +81,13 @@
<input type="radio" name="associate" value="no" <#if !associate??>checked</#if> />No <input type="radio" name="associate" value="no" <#if !associate??>checked</#if> />No
<br/> <br/>
<p> <#if emailIsEnabled??>
Note: An email will be sent to the address entered above <p>
notifying that an account has been created. Note: An email will be sent to the address entered above
It will include instructions for activating the account and creating a password. notifying that an account has been created.
</p> It will include instructions for activating the account and creating a password.
</p>
</#if>
<input type="submit" name="submitAdd" value="Add new account" /> <input type="submit" name="submitAdd" value="Add new account" />
or <a href="${formUrls.list}">Cancel</a> or <a href="${formUrls.list}">Cancel</a>

View file

@ -0,0 +1,43 @@
<#-- $This file is distributed under the terms of the license in /doc/license.txt$ -->
<#-- Confirmation that an account has been created. -->
<html>
<head>
<title>${subjectLine}</title>
</head>
<body>
<p>
${userAccount.firstName} ${userAccount.lastName}
</p>
<p>
<strong>Congratulations!</strong>
</p>
<p>
We have created your new VIVO account associated with ${userAccount.emailAddress}.
</p>
<p>
If you did not request this new account you can safely ignore this email.
This request will expire if not acted upon for 30 days.
</p>
<p>
Click the link below to create your password for your new account using our secure server.
</p>
<p>
<a href="${passwordLink}">${passwordLink}</a>
</p>
<p>
If the link above doesn't work, you can copy and paste the link directly into your browser's address bar.
</p>
<p>
Thanks!
</p>
</body>
</html>

View file

@ -0,0 +1,20 @@
<#-- $This file is distributed under the terms of the license in /doc/license.txt$ -->
<#-- Confirmation that an account has been created. -->
${userAccount.firstName} ${userAccount.lastName}
Congratulations!
We have created your new VIVO account associated with
${userAccount.emailAddress}.
If you did not request this new account you can safely ignore this email.
This request will expire if not acted upon for 30 days.
Paste the link below into your browser's address bar to create your password
for your new account using our secure server.
${passwordLink}
Thanks!