NIHVIVO-2279 Implement CreatePassword - start to separate into user vs. admin functions.
This commit is contained in:
parent
a220c5cba6
commit
1bac5c5fbc
18 changed files with 538 additions and 45 deletions
|
@ -766,12 +766,21 @@
|
||||||
</servlet-mapping>
|
</servlet-mapping>
|
||||||
|
|
||||||
<servlet>
|
<servlet>
|
||||||
<servlet-name>UserAccounts</servlet-name>
|
<servlet-name>AccountsAdmin</servlet-name>
|
||||||
<servlet-class>edu.cornell.mannlib.vitro.webapp.controller.accounts.UserAccountsController</servlet-class>
|
<servlet-class>edu.cornell.mannlib.vitro.webapp.controller.accounts.admin.UserAccountsAdminController</servlet-class>
|
||||||
</servlet>
|
</servlet>
|
||||||
<servlet-mapping>
|
<servlet-mapping>
|
||||||
<servlet-name>UserAccounts</servlet-name>
|
<servlet-name>AccountsAdmin</servlet-name>
|
||||||
<url-pattern>/userAccounts/*</url-pattern>
|
<url-pattern>/accountsAdmin/*</url-pattern>
|
||||||
|
</servlet-mapping>
|
||||||
|
|
||||||
|
<servlet>
|
||||||
|
<servlet-name>AccountsUser</servlet-name>
|
||||||
|
<servlet-class>edu.cornell.mannlib.vitro.webapp.controller.accounts.user.UserAccountsUserController</servlet-class>
|
||||||
|
</servlet>
|
||||||
|
<servlet-mapping>
|
||||||
|
<servlet-name>AccountsUser</servlet-name>
|
||||||
|
<url-pattern>/accounts/*</url-pattern>
|
||||||
</servlet-mapping>
|
</servlet-mapping>
|
||||||
|
|
||||||
<servlet>
|
<servlet>
|
||||||
|
|
|
@ -11,11 +11,17 @@ 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.
|
||||||
|
*
|
||||||
|
* The "password link expires hash" is just a string that is derived from the
|
||||||
|
* value in the passwordLinkExpires field. It doesn't have to be a hash, and
|
||||||
|
* there is no need for it to be cryptographic, but it seems embarrassing to
|
||||||
|
* just send the value as a clear string. There is no real need for security
|
||||||
|
* here, except that a brute force attack would allow someone to change the
|
||||||
|
* password on an account that they know has a password change pending.
|
||||||
*/
|
*/
|
||||||
public class UserAccount {
|
public class UserAccount {
|
||||||
|
public static final int MIN_PASSWORD_LENGTH = 6;
|
||||||
public final static int MIN_PASSWORD_LENGTH = 6;
|
public static final int MAX_PASSWORD_LENGTH = 12;
|
||||||
public final static int MAX_PASSWORD_LENGTH = 12;
|
|
||||||
|
|
||||||
public enum Status {
|
public enum Status {
|
||||||
ACTIVE, INACTIVE;
|
ACTIVE, INACTIVE;
|
||||||
|
@ -110,8 +116,8 @@ public class UserAccount {
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getPasswordLinkExpiresHash() {
|
public String getPasswordLinkExpiresHash() {
|
||||||
return Authenticator.applyMd5Encoding(String
|
return limitStringLength(8, Authenticator.applyMd5Encoding(String
|
||||||
.valueOf(passwordLinkExpires));
|
.valueOf(passwordLinkExpires)));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setPasswordLinkExpires(long passwordLinkExpires) {
|
public void setPasswordLinkExpires(long passwordLinkExpires) {
|
||||||
|
@ -169,6 +175,16 @@ public class UserAccount {
|
||||||
private <T> T nonNull(T value, T defaultValue) {
|
private <T> T nonNull(T value, T defaultValue) {
|
||||||
return (value == null) ? defaultValue : value;
|
return (value == null) ? defaultValue : value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private String limitStringLength(int limit, String s) {
|
||||||
|
if (s == null) {
|
||||||
|
return "";
|
||||||
|
} else if (s.length() <= limit) {
|
||||||
|
return s;
|
||||||
|
} else {
|
||||||
|
return s.substring(0, limit);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
|
|
|
@ -6,12 +6,14 @@ import static javax.mail.Message.RecipientType.TO;
|
||||||
|
|
||||||
import java.net.MalformedURLException;
|
import java.net.MalformedURLException;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
|
import java.util.Calendar;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import edu.cornell.mannlib.vitro.webapp.beans.UserAccount;
|
import edu.cornell.mannlib.vitro.webapp.beans.UserAccount;
|
||||||
import edu.cornell.mannlib.vitro.webapp.beans.UserAccount.Status;
|
import edu.cornell.mannlib.vitro.webapp.beans.UserAccount.Status;
|
||||||
|
import edu.cornell.mannlib.vitro.webapp.config.ConfigurationProperties;
|
||||||
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.UrlBuilder;
|
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.UrlBuilder;
|
||||||
import edu.cornell.mannlib.vitro.webapp.email.FreemarkerEmailFactory;
|
import edu.cornell.mannlib.vitro.webapp.email.FreemarkerEmailFactory;
|
||||||
import edu.cornell.mannlib.vitro.webapp.email.FreemarkerEmailMessage;
|
import edu.cornell.mannlib.vitro.webapp.email.FreemarkerEmailMessage;
|
||||||
|
@ -52,7 +54,8 @@ public abstract class UserAccountsAddPageStrategy {
|
||||||
// ----------------------------------------------------------------------
|
// ----------------------------------------------------------------------
|
||||||
|
|
||||||
private static class EmailStrategy extends UserAccountsAddPageStrategy {
|
private static class EmailStrategy extends UserAccountsAddPageStrategy {
|
||||||
public static final String CREATE_PASSWORD_URL = "/userAccounts/createPassword";
|
public static final String CREATE_PASSWORD_URL = "/accounts/createPassword";
|
||||||
|
private static final int DAYS_TO_ACTIVATE_ACCOUNT = 90;
|
||||||
|
|
||||||
private boolean sentEmail;
|
private boolean sentEmail;
|
||||||
|
|
||||||
|
@ -73,9 +76,15 @@ public abstract class UserAccountsAddPageStrategy {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void setAdditionalProperties(UserAccount u) {
|
protected void setAdditionalProperties(UserAccount u) {
|
||||||
u.setPasswordLinkExpires(new Date().getTime());
|
u.setPasswordLinkExpires(figureExpirationDate().getTime());
|
||||||
u.setStatus(Status.INACTIVE);
|
u.setStatus(Status.INACTIVE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Date figureExpirationDate() {
|
||||||
|
Calendar c = Calendar.getInstance();
|
||||||
|
c.add(Calendar.DATE, DAYS_TO_ACTIVATE_ACCOUNT);
|
||||||
|
return c.getTime();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void addMoreBodyValues(Map<String, Object> body) {
|
protected void addMoreBodyValues(Map<String, Object> body) {
|
||||||
|
@ -93,8 +102,8 @@ public abstract class UserAccountsAddPageStrategy {
|
||||||
.createNewMessage(page.vreq);
|
.createNewMessage(page.vreq);
|
||||||
email.addRecipient(TO, page.getAddedAccount().getEmailAddress());
|
email.addRecipient(TO, page.getAddedAccount().getEmailAddress());
|
||||||
email.setSubject("Your VIVO account has been created.");
|
email.setSubject("Your VIVO account has been created.");
|
||||||
email.setHtmlTemplate("userAccounts-createdEmail-html.ftl");
|
email.setHtmlTemplate("userAccounts-acctCreatedEmail-html.ftl");
|
||||||
email.setTextTemplate("userAccounts-createdEmail-text.ftl");
|
email.setTextTemplate("userAccounts-acctCreatedEmail-text.ftl");
|
||||||
email.setBodyMap(body);
|
email.setBodyMap(body);
|
||||||
email.send();
|
email.send();
|
||||||
|
|
||||||
|
@ -103,11 +112,11 @@ public abstract class UserAccountsAddPageStrategy {
|
||||||
|
|
||||||
private String buildCreatePasswordLink() {
|
private String buildCreatePasswordLink() {
|
||||||
try {
|
try {
|
||||||
String uri = page.getAddedAccount().getUri();
|
String email = page.getAddedAccount().getEmailAddress();
|
||||||
String hash = page.getAddedAccount()
|
String hash = page.getAddedAccount()
|
||||||
.getPasswordLinkExpiresHash();
|
.getPasswordLinkExpiresHash();
|
||||||
String relativeUrl = UrlBuilder.getUrl(CREATE_PASSWORD_URL, "user",
|
String relativeUrl = UrlBuilder.getUrl(CREATE_PASSWORD_URL, "user",
|
||||||
uri, "key", hash);
|
email, "key", hash);
|
||||||
|
|
||||||
URL context = new URL(page.vreq.getRequestURL().toString());
|
URL context = new URL(page.vreq.getRequestURL().toString());
|
||||||
URL url = new URL(context, relativeUrl);
|
URL url = new URL(context, relativeUrl);
|
||||||
|
@ -116,7 +125,7 @@ public abstract class UserAccountsAddPageStrategy {
|
||||||
return "error_creating_password_link";
|
return "error_creating_password_link";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected boolean wasPasswordEmailSent() {
|
protected boolean wasPasswordEmailSent() {
|
||||||
return sentEmail;
|
return sentEmail;
|
||||||
|
|
|
@ -9,8 +9,10 @@ import org.apache.commons.logging.LogFactory;
|
||||||
|
|
||||||
import edu.cornell.mannlib.vitro.webapp.auth.requestedAction.Actions;
|
import edu.cornell.mannlib.vitro.webapp.auth.requestedAction.Actions;
|
||||||
import edu.cornell.mannlib.vitro.webapp.auth.requestedAction.usepages.ManageUserAccounts;
|
import edu.cornell.mannlib.vitro.webapp.auth.requestedAction.usepages.ManageUserAccounts;
|
||||||
|
import edu.cornell.mannlib.vitro.webapp.beans.DisplayMessage;
|
||||||
import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest;
|
import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest;
|
||||||
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.FreemarkerHttpServlet;
|
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.FreemarkerHttpServlet;
|
||||||
|
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.responsevalues.RedirectResponseValues;
|
||||||
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.responsevalues.ResponseValues;
|
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.responsevalues.ResponseValues;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -23,6 +25,7 @@ public class UserAccountsController extends FreemarkerHttpServlet {
|
||||||
private static final String ACTION_ADD = "/add";
|
private static final String ACTION_ADD = "/add";
|
||||||
private static final String ACTION_DELETE = "/delete";
|
private static final String ACTION_DELETE = "/delete";
|
||||||
private static final String ACTION_EDIT = "/edit";
|
private static final String ACTION_EDIT = "/edit";
|
||||||
|
private static final String ACTION_CREATE_PASSWORD = "/createPassword";
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Actions requiredActions(VitroRequest vreq) {
|
protected Actions requiredActions(VitroRequest vreq) {
|
||||||
|
@ -44,6 +47,8 @@ public class UserAccountsController extends FreemarkerHttpServlet {
|
||||||
return handleEditRequest(vreq);
|
return handleEditRequest(vreq);
|
||||||
} else if (ACTION_DELETE.equals(action)) {
|
} else if (ACTION_DELETE.equals(action)) {
|
||||||
return handleDeleteRequest(vreq);
|
return handleDeleteRequest(vreq);
|
||||||
|
} else if (ACTION_CREATE_PASSWORD.equals(action)) {
|
||||||
|
return handleCreatePasswordRequest(vreq);
|
||||||
} else {
|
} else {
|
||||||
return handleListRequest(vreq);
|
return handleListRequest(vreq);
|
||||||
}
|
}
|
||||||
|
@ -64,7 +69,6 @@ public class UserAccountsController extends FreemarkerHttpServlet {
|
||||||
|
|
||||||
private ResponseValues handleEditRequest(VitroRequest vreq) {
|
private ResponseValues handleEditRequest(VitroRequest vreq) {
|
||||||
UserAccountsEditPage page = new UserAccountsEditPage(vreq);
|
UserAccountsEditPage page = new UserAccountsEditPage(vreq);
|
||||||
page.parseParametersAndValidate();
|
|
||||||
if (page.isSubmit() && page.isValid()) {
|
if (page.isSubmit() && page.isValid()) {
|
||||||
page.updateAccount();
|
page.updateAccount();
|
||||||
UserAccountsListPage listPage = new UserAccountsListPage(vreq);
|
UserAccountsListPage listPage = new UserAccountsListPage(vreq);
|
||||||
|
@ -83,8 +87,30 @@ public class UserAccountsController extends FreemarkerHttpServlet {
|
||||||
.showPageWithDeletions(deletedUris);
|
.showPageWithDeletions(deletedUris);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private ResponseValues handleCreatePasswordRequest(VitroRequest vreq) {
|
||||||
|
UserAccountsCreatePasswordPage page = new UserAccountsCreatePasswordPage(
|
||||||
|
vreq);
|
||||||
|
if (page.isBogus()) {
|
||||||
|
return showHomePage(vreq,
|
||||||
|
"Request failed. Please contact your system administrator.");
|
||||||
|
} else if (page.isSubmit() && page.isValid()) {
|
||||||
|
page.createPassword();
|
||||||
|
return showHomePage(vreq,
|
||||||
|
"Your password has been saved. Please log in.");
|
||||||
|
} else {
|
||||||
|
return page.showPage();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
private ResponseValues handleListRequest(VitroRequest vreq) {
|
private ResponseValues handleListRequest(VitroRequest vreq) {
|
||||||
UserAccountsListPage page = new UserAccountsListPage(vreq);
|
UserAccountsListPage page = new UserAccountsListPage(vreq);
|
||||||
return page.showPage();
|
return page.showPage();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private ResponseValues showHomePage(VitroRequest vreq, String message) {
|
||||||
|
DisplayMessage.setMessage(vreq, message);
|
||||||
|
return new RedirectResponseValues("/");
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,165 @@
|
||||||
|
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
|
||||||
|
|
||||||
|
package edu.cornell.mannlib.vitro.webapp.controller.accounts;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.apache.commons.logging.Log;
|
||||||
|
import org.apache.commons.logging.LogFactory;
|
||||||
|
|
||||||
|
import edu.cornell.mannlib.vitro.webapp.beans.UserAccount;
|
||||||
|
import edu.cornell.mannlib.vitro.webapp.beans.UserAccount.Status;
|
||||||
|
import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest;
|
||||||
|
import edu.cornell.mannlib.vitro.webapp.controller.accounts.user.UserAccountsUserController;
|
||||||
|
import edu.cornell.mannlib.vitro.webapp.controller.authenticate.Authenticator;
|
||||||
|
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.responsevalues.ResponseValues;
|
||||||
|
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.responsevalues.TemplateResponseValues;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TODO
|
||||||
|
*/
|
||||||
|
public class UserAccountsCreatePasswordPage extends UserAccountsPage {
|
||||||
|
private static final Log log = LogFactory
|
||||||
|
.getLog(UserAccountsCreatePasswordPage.class);
|
||||||
|
|
||||||
|
private static final String PARAMETER_SUBMIT = "submitCreatePassword";
|
||||||
|
private static final String PARAMETER_USER = "user";
|
||||||
|
private static final String PARAMETER_KEY = "key";
|
||||||
|
private static final String PARAMETER_PASSWORD = "password";
|
||||||
|
private static final String PARAMETER_CONFIRM_PASSWORD = "confirmPassword";
|
||||||
|
|
||||||
|
private static final String TEMPLATE_NAME = "userAccounts-createPassword.ftl";
|
||||||
|
|
||||||
|
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 boolean submit;
|
||||||
|
private String userEmail = "";
|
||||||
|
private String key = "";
|
||||||
|
private String password = "";
|
||||||
|
private String confirmPassword = "";
|
||||||
|
|
||||||
|
private UserAccount userAccount;
|
||||||
|
|
||||||
|
/** The result of checking whether this request is even appropriate. */
|
||||||
|
private String bogusMessage = "";
|
||||||
|
|
||||||
|
/** The result of validating a "submit" request. */
|
||||||
|
private String errorCode = "";
|
||||||
|
|
||||||
|
public UserAccountsCreatePasswordPage(VitroRequest vreq) {
|
||||||
|
super(vreq);
|
||||||
|
|
||||||
|
parseRequestParameters();
|
||||||
|
validateUserAccountInfo();
|
||||||
|
|
||||||
|
if (isSubmit() && !isBogus()) {
|
||||||
|
validateParameters();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void parseRequestParameters() {
|
||||||
|
submit = isFlagOnRequest(PARAMETER_SUBMIT);
|
||||||
|
userEmail = getStringParameter(PARAMETER_USER, "");
|
||||||
|
key = getStringParameter(PARAMETER_KEY, "");
|
||||||
|
password = getStringParameter(PARAMETER_PASSWORD, "");
|
||||||
|
confirmPassword = getStringParameter(PARAMETER_CONFIRM_PASSWORD, "");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void validateUserAccountInfo() {
|
||||||
|
userAccount = userAccountsDao.getUserAccountByEmail(userEmail);
|
||||||
|
if (userAccount == null) {
|
||||||
|
log.warn("Create password for '" + userEmail
|
||||||
|
+ "' is bogus: no such user");
|
||||||
|
bogusMessage = UserAccountsUserController.BOGUS_STANDARD_MESSAGE;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (userAccount.getPasswordLinkExpires() == 0L) {
|
||||||
|
log.warn("Create password for '" + userEmail
|
||||||
|
+ "' is bogus: password change is not pending.");
|
||||||
|
bogusMessage = "The account for " + userEmail
|
||||||
|
+ " has already been activated.";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Date expirationDate = new Date(userAccount.getPasswordLinkExpires());
|
||||||
|
if (expirationDate.before(new Date())) {
|
||||||
|
log.warn("Create password for '" + userEmail
|
||||||
|
+ "' is bogus: expiration date has passed.");
|
||||||
|
bogusMessage = UserAccountsUserController.BOGUS_STANDARD_MESSAGE;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
String expectedKey = userAccount.getPasswordLinkExpiresHash();
|
||||||
|
if (!key.equals(expectedKey)) {
|
||||||
|
log.warn("Create password for '" + userEmail + "' is bogus: key ("
|
||||||
|
+ key + ") doesn't match expected key (" + expectedKey
|
||||||
|
+ ")");
|
||||||
|
bogusMessage = UserAccountsUserController.BOGUS_STANDARD_MESSAGE;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void validateParameters() {
|
||||||
|
if (password.isEmpty()) {
|
||||||
|
errorCode = ERROR_NO_PASSWORD;
|
||||||
|
} else if (!checkPasswordLength(password)) {
|
||||||
|
errorCode = ERROR_WRONG_PASSWORD_LENGTH;
|
||||||
|
} else if (!password.equals(confirmPassword)) {
|
||||||
|
errorCode = ERROR_PASSWORDS_DONT_MATCH;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean checkPasswordLength(String pw) {
|
||||||
|
return pw.length() >= UserAccount.MIN_PASSWORD_LENGTH
|
||||||
|
&& pw.length() <= UserAccount.MAX_PASSWORD_LENGTH;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isBogus() {
|
||||||
|
return bogusMessage.isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getBogusMessage() {
|
||||||
|
return bogusMessage;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isSubmit() {
|
||||||
|
return submit;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isValid() {
|
||||||
|
return errorCode.isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void createPassword() {
|
||||||
|
userAccount.setMd5Password(Authenticator.applyMd5Encoding(password));
|
||||||
|
userAccount.setPasswordLinkExpires(0L);
|
||||||
|
userAccount.setStatus(Status.ACTIVE);
|
||||||
|
userAccountsDao.updateUserAccount(userAccount);
|
||||||
|
log.debug("Set password on '" + userAccount.getEmailAddress()
|
||||||
|
+ "' to '" + password + "'");
|
||||||
|
}
|
||||||
|
|
||||||
|
public final ResponseValues showPage() {
|
||||||
|
Map<String, Object> body = new HashMap<String, Object>();
|
||||||
|
|
||||||
|
body.put("minimumLength", UserAccount.MIN_PASSWORD_LENGTH);
|
||||||
|
body.put("maximumLength", UserAccount.MAX_PASSWORD_LENGTH);
|
||||||
|
body.put("userAccount", userAccount);
|
||||||
|
body.put("key", userAccount.getPasswordLinkExpiresHash());
|
||||||
|
body.put("password", password);
|
||||||
|
body.put("confirmPassword", confirmPassword);
|
||||||
|
body.put("formUrls", buildUrlsMap());
|
||||||
|
|
||||||
|
if (!errorCode.isEmpty()) {
|
||||||
|
body.put(errorCode, Boolean.TRUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new TemplateResponseValues(TEMPLATE_NAME, body);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -21,7 +21,7 @@ public class UserAccountsDeleter extends UserAccountsPage {
|
||||||
/** Might be empty, but never null. */
|
/** Might be empty, but never null. */
|
||||||
private final String[] uris;
|
private final String[] uris;
|
||||||
|
|
||||||
protected UserAccountsDeleter(VitroRequest vreq) {
|
public UserAccountsDeleter(VitroRequest vreq) {
|
||||||
super(vreq);
|
super(vreq);
|
||||||
|
|
||||||
String[] values = vreq.getParameterValues(PARAMETER_DELETE_ACCOUNT);
|
String[] values = vreq.getParameterValues(PARAMETER_DELETE_ACCOUNT);
|
||||||
|
|
|
@ -55,14 +55,6 @@ public class UserAccountsEditPage extends UserAccountsPage {
|
||||||
throw new RuntimeException("UserAccountsEditPage.getUpdatedAccount() not implemented.");
|
throw new RuntimeException("UserAccountsEditPage.getUpdatedAccount() not implemented.");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public void parseParametersAndValidate() {
|
|
||||||
// TODO Auto-generated method stub
|
|
||||||
throw new RuntimeException("UserAccountsEditPage.parseParametersAndValidate() not implemented.");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -20,8 +20,6 @@ import edu.cornell.mannlib.vitro.webapp.beans.UserAccount.Status;
|
||||||
import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest;
|
import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest;
|
||||||
import edu.cornell.mannlib.vitro.webapp.controller.accounts.UserAccountsOrdering.Direction;
|
import edu.cornell.mannlib.vitro.webapp.controller.accounts.UserAccountsOrdering.Direction;
|
||||||
import edu.cornell.mannlib.vitro.webapp.controller.accounts.UserAccountsOrdering.Field;
|
import edu.cornell.mannlib.vitro.webapp.controller.accounts.UserAccountsOrdering.Field;
|
||||||
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.UrlBuilder;
|
|
||||||
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.UrlBuilder.ParamMap;
|
|
||||||
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.responsevalues.ResponseValues;
|
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.responsevalues.ResponseValues;
|
||||||
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.responsevalues.TemplateResponseValues;
|
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.responsevalues.TemplateResponseValues;
|
||||||
|
|
||||||
|
@ -100,7 +98,7 @@ public class UserAccountsListPage extends UserAccountsPage {
|
||||||
userAccountsModel, criteria);
|
userAccountsModel, criteria);
|
||||||
Map<String, Object> body = buildTemplateBodyMap(selection);
|
Map<String, Object> body = buildTemplateBodyMap(selection);
|
||||||
|
|
||||||
body.put("newUserAccount", new UserAccountWrapper(vreq, userAccount,
|
body.put("newUserAccount", new UserAccountWrapper(userAccount,
|
||||||
Collections.<String> emptyList()));
|
Collections.<String> emptyList()));
|
||||||
|
|
||||||
return new TemplateResponseValues(TEMPLATE_NAME, body);
|
return new TemplateResponseValues(TEMPLATE_NAME, body);
|
||||||
|
@ -215,7 +213,7 @@ public class UserAccountsListPage extends UserAccountsPage {
|
||||||
UserAccountsSelection selection) {
|
UserAccountsSelection selection) {
|
||||||
List<UserAccountWrapper> list = new ArrayList<UserAccountWrapper>();
|
List<UserAccountWrapper> list = new ArrayList<UserAccountWrapper>();
|
||||||
for (UserAccount account : selection.getUserAccounts()) {
|
for (UserAccount account : selection.getUserAccounts()) {
|
||||||
list.add(new UserAccountWrapper(vreq, account,
|
list.add(new UserAccountWrapper(account,
|
||||||
findPermissionSetLabels(account)));
|
findPermissionSetLabels(account)));
|
||||||
}
|
}
|
||||||
return list;
|
return list;
|
||||||
|
@ -240,14 +238,11 @@ public class UserAccountsListPage extends UserAccountsPage {
|
||||||
private final List<String> permissionSets;
|
private final List<String> permissionSets;
|
||||||
private final String editUrl;
|
private final String editUrl;
|
||||||
|
|
||||||
public UserAccountWrapper(VitroRequest vreq, UserAccount account,
|
public UserAccountWrapper(UserAccount account,
|
||||||
List<String> permissionSets) {
|
List<String> permissionSets) {
|
||||||
this.account = account;
|
this.account = account;
|
||||||
this.permissionSets = permissionSets;
|
this.permissionSets = permissionSets;
|
||||||
|
this.editUrl = UserAccountsPage.editAccountUrl(account.getUri());
|
||||||
UrlBuilder urlBuilder = new UrlBuilder(vreq.getAppBean());
|
|
||||||
this.editUrl = urlBuilder.getPortalUrl("/userAccounts/edit",
|
|
||||||
new ParamMap("editAccount", account.getUri()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getUri() {
|
public String getUri() {
|
||||||
|
|
|
@ -20,6 +20,7 @@ import com.hp.hpl.jena.ontology.OntModel;
|
||||||
import edu.cornell.mannlib.vitro.webapp.beans.PermissionSet;
|
import edu.cornell.mannlib.vitro.webapp.beans.PermissionSet;
|
||||||
import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest;
|
import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest;
|
||||||
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.UrlBuilder;
|
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.UrlBuilder;
|
||||||
|
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.UrlBuilder.ParamMap;
|
||||||
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;
|
||||||
|
@ -102,11 +103,16 @@ public abstract class UserAccountsPage {
|
||||||
protected Map<String, String> buildUrlsMap() {
|
protected Map<String, String> buildUrlsMap() {
|
||||||
Map<String, String> map = new HashMap<String, String>();
|
Map<String, String> map = new HashMap<String, String>();
|
||||||
|
|
||||||
map.put("list", UrlBuilder.getUrl("/userAccounts/list"));
|
map.put("list", UrlBuilder.getUrl("/accountsAdmin/list"));
|
||||||
map.put("add", UrlBuilder.getUrl("/userAccounts/add"));
|
map.put("add", UrlBuilder.getUrl("/accountsAdmin/add"));
|
||||||
map.put("delete", UrlBuilder.getUrl("/userAccounts/delete"));
|
map.put("delete", UrlBuilder.getUrl("/accountsAdmin/delete"));
|
||||||
|
map.put("createPassword", UrlBuilder.getUrl("/accounts/createPassword"));
|
||||||
|
|
||||||
return map;
|
return map;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected static String editAccountUrl(String uri) {
|
||||||
|
return UrlBuilder.getUrl("/accountsAdmin/edit",
|
||||||
|
new ParamMap("editAccount", uri));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,94 @@
|
||||||
|
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
|
||||||
|
|
||||||
|
package edu.cornell.mannlib.vitro.webapp.controller.accounts.admin;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
|
||||||
|
import org.apache.commons.logging.Log;
|
||||||
|
import org.apache.commons.logging.LogFactory;
|
||||||
|
|
||||||
|
import edu.cornell.mannlib.vitro.webapp.auth.requestedAction.Actions;
|
||||||
|
import edu.cornell.mannlib.vitro.webapp.auth.requestedAction.usepages.ManageUserAccounts;
|
||||||
|
import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest;
|
||||||
|
import edu.cornell.mannlib.vitro.webapp.controller.accounts.UserAccountsAddPage;
|
||||||
|
import edu.cornell.mannlib.vitro.webapp.controller.accounts.UserAccountsDeleter;
|
||||||
|
import edu.cornell.mannlib.vitro.webapp.controller.accounts.UserAccountsEditPage;
|
||||||
|
import edu.cornell.mannlib.vitro.webapp.controller.accounts.UserAccountsListPage;
|
||||||
|
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.FreemarkerHttpServlet;
|
||||||
|
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.responsevalues.ResponseValues;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parcel out the different actions required of the Administrators portion of the UserAccounts GUI.
|
||||||
|
*/
|
||||||
|
public class UserAccountsAdminController extends FreemarkerHttpServlet {
|
||||||
|
private static final Log log = LogFactory
|
||||||
|
.getLog(UserAccountsAdminController.class);
|
||||||
|
|
||||||
|
private static final String ACTION_ADD = "/add";
|
||||||
|
private static final String ACTION_DELETE = "/delete";
|
||||||
|
private static final String ACTION_EDIT = "/edit";
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Actions requiredActions(VitroRequest vreq) {
|
||||||
|
return new Actions(new ManageUserAccounts());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected ResponseValues processRequest(VitroRequest vreq) {
|
||||||
|
if (log.isDebugEnabled()) {
|
||||||
|
dumpRequestParameters(vreq);
|
||||||
|
}
|
||||||
|
|
||||||
|
String action = vreq.getPathInfo();
|
||||||
|
log.debug("action = '" + action + "'");
|
||||||
|
|
||||||
|
if (ACTION_ADD.equals(action)) {
|
||||||
|
return handleAddRequest(vreq);
|
||||||
|
} else if (ACTION_EDIT.equals(action)) {
|
||||||
|
return handleEditRequest(vreq);
|
||||||
|
} else if (ACTION_DELETE.equals(action)) {
|
||||||
|
return handleDeleteRequest(vreq);
|
||||||
|
} else {
|
||||||
|
return handleListRequest(vreq);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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 {
|
||||||
|
return page.showPage();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private ResponseValues handleEditRequest(VitroRequest vreq) {
|
||||||
|
UserAccountsEditPage page = new UserAccountsEditPage(vreq);
|
||||||
|
if (page.isSubmit() && page.isValid()) {
|
||||||
|
page.updateAccount();
|
||||||
|
UserAccountsListPage listPage = new UserAccountsListPage(vreq);
|
||||||
|
return listPage.showPageWithUpdatedAccount(
|
||||||
|
page.getUpdatedAccount(), page.wasPasswordEmailSent());
|
||||||
|
} else {
|
||||||
|
return page.showPage();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private ResponseValues handleDeleteRequest(VitroRequest vreq) {
|
||||||
|
UserAccountsDeleter deleter = new UserAccountsDeleter(vreq);
|
||||||
|
Collection<String> deletedUris = deleter.delete();
|
||||||
|
|
||||||
|
return new UserAccountsListPage(vreq)
|
||||||
|
.showPageWithDeletions(deletedUris);
|
||||||
|
}
|
||||||
|
|
||||||
|
private ResponseValues handleListRequest(VitroRequest vreq) {
|
||||||
|
UserAccountsListPage page = new UserAccountsListPage(vreq);
|
||||||
|
return page.showPage();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,72 @@
|
||||||
|
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
|
||||||
|
|
||||||
|
package edu.cornell.mannlib.vitro.webapp.controller.accounts.user;
|
||||||
|
|
||||||
|
import org.apache.commons.logging.Log;
|
||||||
|
import org.apache.commons.logging.LogFactory;
|
||||||
|
|
||||||
|
import edu.cornell.mannlib.vitro.webapp.auth.requestedAction.Actions;
|
||||||
|
import edu.cornell.mannlib.vitro.webapp.beans.DisplayMessage;
|
||||||
|
import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest;
|
||||||
|
import edu.cornell.mannlib.vitro.webapp.controller.accounts.UserAccountsCreatePasswordPage;
|
||||||
|
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.FreemarkerHttpServlet;
|
||||||
|
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.responsevalues.RedirectResponseValues;
|
||||||
|
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.responsevalues.ResponseValues;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parcel out the different actions required of the UserAccounts GUI.
|
||||||
|
*/
|
||||||
|
public class UserAccountsUserController extends FreemarkerHttpServlet {
|
||||||
|
private static final Log log = LogFactory
|
||||||
|
.getLog(UserAccountsUserController.class);
|
||||||
|
|
||||||
|
public static final String BOGUS_STANDARD_MESSAGE = "Request failed. Please contact your system administrator.";
|
||||||
|
|
||||||
|
private static final String ACTION_CREATE_PASSWORD = "/createPassword";
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Actions requiredActions(VitroRequest vreq) {
|
||||||
|
return Actions.AUTHORIZED;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected ResponseValues processRequest(VitroRequest vreq) {
|
||||||
|
if (log.isDebugEnabled()) {
|
||||||
|
dumpRequestParameters(vreq);
|
||||||
|
}
|
||||||
|
|
||||||
|
String action = vreq.getPathInfo();
|
||||||
|
log.debug("action = '" + action + "'");
|
||||||
|
|
||||||
|
if (ACTION_CREATE_PASSWORD.equals(action)) {
|
||||||
|
return handleCreatePasswordRequest(vreq);
|
||||||
|
} else {
|
||||||
|
return handleInvalidRequest(vreq);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private ResponseValues handleCreatePasswordRequest(VitroRequest vreq) {
|
||||||
|
UserAccountsCreatePasswordPage page = new UserAccountsCreatePasswordPage(
|
||||||
|
vreq);
|
||||||
|
if (page.isBogus()) {
|
||||||
|
return showHomePage(vreq, page.getBogusMessage());
|
||||||
|
} else if (page.isSubmit() && page.isValid()) {
|
||||||
|
page.createPassword();
|
||||||
|
return showHomePage(vreq,
|
||||||
|
"Your password has been saved. Please log in.");
|
||||||
|
} else {
|
||||||
|
return page.showPage();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private ResponseValues handleInvalidRequest(VitroRequest vreq) {
|
||||||
|
return showHomePage(vreq, BOGUS_STANDARD_MESSAGE);
|
||||||
|
}
|
||||||
|
|
||||||
|
private ResponseValues showHomePage(VitroRequest vreq, String message) {
|
||||||
|
DisplayMessage.setMessage(vreq, message);
|
||||||
|
return new RedirectResponseValues("/");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -124,7 +124,7 @@ public class SiteAdminController extends FreemarkerHttpServlet {
|
||||||
urls.put("users", urlBuilder.getPortalUrl("/listUsers"));
|
urls.put("users", urlBuilder.getPortalUrl("/listUsers"));
|
||||||
}
|
}
|
||||||
if (PolicyHelper.isAuthorizedForActions(vreq, new ManageUserAccounts())) {
|
if (PolicyHelper.isAuthorizedForActions(vreq, new ManageUserAccounts())) {
|
||||||
urls.put("userList", urlBuilder.getPortalUrl("/userAccounts"));
|
urls.put("userList", urlBuilder.getPortalUrl("/accountsAdmin"));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (PolicyHelper.isAuthorizedForActions(vreq, new EditSiteInformation())) {
|
if (PolicyHelper.isAuthorizedForActions(vreq, new EditSiteInformation())) {
|
||||||
|
|
|
@ -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 ${minimumLength} and ${maximumLength} 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"/>
|
||||||
|
@ -52,6 +64,14 @@
|
||||||
<br />
|
<br />
|
||||||
</#list>
|
</#list>
|
||||||
|
|
||||||
|
<#if !emailIsEnabled??>
|
||||||
|
<label for="initial-password">Initial password<span class="requiredHint"> *</span></label>
|
||||||
|
<input type="password" name="initialPassword" value="${initialPassword}" id="initial-password" role="input "/>
|
||||||
|
|
||||||
|
<label for="confirm-password">Confirm initial password<span class="requiredHint"> *</span></label>
|
||||||
|
<input type="text" name="confirmPassword" value="${confirmPassword}" id="confirm-password" role="input "/>
|
||||||
|
</#if>
|
||||||
|
|
||||||
<p>Associate a profile with this account</p>
|
<p>Associate a profile with this account</p>
|
||||||
<input type="radio" name="associate" value="yes" role="radio" <#if associate??>checked</#if> id="associate" />
|
<input type="radio" name="associate" value="yes" role="radio" <#if associate??>checked</#if> id="associate" />
|
||||||
<label class="inline" for="associate"> Yes</label>
|
<label class="inline" for="associate"> Yes</label>
|
||||||
|
@ -63,12 +83,14 @@
|
||||||
<input type="checkbox" name="resetPassword" value="" id="reset-password" role="checkbox" />
|
<input type="checkbox" name="resetPassword" value="" id="reset-password" role="checkbox" />
|
||||||
<label class="inline" for="reset-password"> Reset password</label>
|
<label class="inline" for="reset-password"> Reset password</label>
|
||||||
|
|
||||||
<p class="note">
|
<#if emailIsEnabled??>
|
||||||
Note: An email will be sent to the address entered above
|
<p class="note">
|
||||||
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" class="submit"/> or <a href="${formUrls.list}">Cancel</a>
|
<input type="submit" name="submitAdd" value="Add new account" class="submit"/> or <a href="${formUrls.list}">Cancel</a>
|
||||||
|
|
||||||
<p class="requiredHint">* required fields</p>
|
<p class="requiredHint">* required fields</p>
|
||||||
|
|
|
@ -0,0 +1,49 @@
|
||||||
|
<#-- $This file is distributed under the terms of the license in /doc/license.txt$ -->
|
||||||
|
|
||||||
|
<#-- Template for adding a user account -->
|
||||||
|
|
||||||
|
<h3>Add new account</h3>
|
||||||
|
|
||||||
|
<#if errorPasswordIsEmpty??>
|
||||||
|
<#assign errorMessage = "No password supplied." />
|
||||||
|
</#if>
|
||||||
|
|
||||||
|
<#if errorPasswordIsWrongLength??>
|
||||||
|
<#assign errorMessage = "Password must be between ${minimumLength} and ${maximumLength} characters." />
|
||||||
|
</#if>
|
||||||
|
|
||||||
|
<#if errorPasswordsDontMatch??>
|
||||||
|
<#assign errorMessage = "Passwords do not match." />
|
||||||
|
</#if>
|
||||||
|
|
||||||
|
<#if errorMessage?has_content>
|
||||||
|
<section id="error-alert" role="alert">
|
||||||
|
<img src="${urls.images}/iconAlert.png" width="24" height="24" alert="Error alert icon"/>
|
||||||
|
<p>${errorMessage}</p>
|
||||||
|
</section>
|
||||||
|
</#if>
|
||||||
|
|
||||||
|
<section id="add-account" role="region">
|
||||||
|
<fieldset>
|
||||||
|
<legend>Add new account</legend>
|
||||||
|
|
||||||
|
<form method="POST" action="${formUrls.createPassword}" class="customForm" role="create password">
|
||||||
|
<input type="hidden" name="user" value="${userAccount.emailAddress}" />
|
||||||
|
<input type="hidden" name="key" value="${userAccount.passwordLinkExpiresHash}" />
|
||||||
|
|
||||||
|
<label for="password">Password<span class="requiredHint"> *</span></label>
|
||||||
|
<input type="password" name="password" value="${password}" id="password" role="input "/>
|
||||||
|
|
||||||
|
<p>Minimum of ${minimumLength} characters in length.</p>
|
||||||
|
|
||||||
|
<label for="confirm-password">Confirm Password<span class="requiredHint"> *</span></label>
|
||||||
|
<input type="password" name="confirmPassword" value="${confirmPassword}" id="confirm-password" role="input "/>
|
||||||
|
|
||||||
|
<input type="submit" name="submitCreatePassword" value="Save changes" class="submit"/>
|
||||||
|
|
||||||
|
<p class="requiredHint">* required fields</p>
|
||||||
|
</form>
|
||||||
|
</fieldset>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
${stylesheets.add('<link rel="stylesheet" href="${urls.base}/edit/forms/css/customForm.css" />')}
|
|
@ -0,0 +1,26 @@
|
||||||
|
<#-- $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>Password successfully created.</strong>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Yout new password associated with ${userAccount.emailAddress} has been created.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Thank you.
|
||||||
|
</p>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -0,0 +1,12 @@
|
||||||
|
<#-- $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}
|
||||||
|
|
||||||
|
Password successfully created.
|
||||||
|
|
||||||
|
Your new password associated with ${userAccount.emailAddress}
|
||||||
|
has been created.
|
||||||
|
|
||||||
|
Thank you.
|
Loading…
Add table
Add a link
Reference in a new issue