NIHVIVO-2279 first steps toward associating a UserAccount with a Profile.
This commit is contained in:
parent
239256187d
commit
87dc7698e1
8 changed files with 380 additions and 33 deletions
|
@ -747,6 +747,15 @@
|
|||
<url-pattern>/accountsAdmin/*</url-pattern>
|
||||
</servlet-mapping>
|
||||
|
||||
<servlet>
|
||||
<servlet-name>AccountsAjax</servlet-name>
|
||||
<servlet-class>edu.cornell.mannlib.vitro.webapp.controller.accounts.admin.ajax.UserAccountsAjaxController</servlet-class>
|
||||
</servlet>
|
||||
<servlet-mapping>
|
||||
<servlet-name>AccountsAjax</servlet-name>
|
||||
<url-pattern>/accountsAjax/*</url-pattern>
|
||||
</servlet-mapping>
|
||||
|
||||
<servlet>
|
||||
<servlet-name>AccountsUser</servlet-name>
|
||||
<servlet-class>edu.cornell.mannlib.vitro.webapp.controller.accounts.user.UserAccountsUserController</servlet-class>
|
||||
|
|
|
@ -130,6 +130,7 @@ public abstract class UserAccountsPage {
|
|||
map.put("createPassword", UrlBuilder.getUrl("/accounts/createPassword"));
|
||||
map.put("resetPassword", UrlBuilder.getUrl("/accounts/resetPassword"));
|
||||
map.put("firstTimeExternal", UrlBuilder.getUrl("/accounts/firstTimeExternal"));
|
||||
map.put("accountsAjax", UrlBuilder.getUrl("/accountsAjax"));
|
||||
|
||||
return map;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
|
||||
|
||||
package edu.cornell.mannlib.vitro.webapp.controller.accounts.admin;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import edu.cornell.mannlib.vitro.webapp.beans.UserAccount;
|
||||
|
||||
/**
|
||||
* TODO
|
||||
*/
|
||||
public class UserAccountsAssociatedProfileHelper {
|
||||
private static final Log log = LogFactory
|
||||
.getLog(UserAccountsAssociatedProfileHelper.class);
|
||||
|
||||
/**
|
||||
* This profile (if it exists) should be associated with this UserAccount.
|
||||
* No other profile should be associated with this UserAccount. Make it so.
|
||||
*/
|
||||
public static void reconcile(UserAccount userAccount,
|
||||
String associatedProfileUri) {
|
||||
log.error("UserAccountsAssociatedProfileHelper.reconcile() not implemented.");
|
||||
}
|
||||
|
||||
}
|
|
@ -32,7 +32,7 @@ public class UserAccountsEditPage extends UserAccountsPage {
|
|||
private static final String PARAMETER_FIRST_NAME = "firstName";
|
||||
private static final String PARAMETER_LAST_NAME = "lastName";
|
||||
private static final String PARAMETER_ROLE = "role";
|
||||
private static final String PARAMETER_ASSOCIATE_WITH_PROFILE = "associate";
|
||||
private static final String PARAMETER_ASSOCIATED_PROFILE_URI = "associatedProfileUri";
|
||||
|
||||
private static final String ERROR_NO_EMAIL = "errorEmailIsEmpty";
|
||||
private static final String ERROR_EMAIL_IN_USE = "errorEmailInUse";
|
||||
|
@ -54,7 +54,7 @@ public class UserAccountsEditPage extends UserAccountsPage {
|
|||
private String firstName = "";
|
||||
private String lastName = "";
|
||||
private String selectedRoleUri = "";
|
||||
private boolean associateWithProfile;
|
||||
private String associatedProfileUri = "";
|
||||
|
||||
private UserAccount userAccount;
|
||||
|
||||
|
@ -86,8 +86,8 @@ public class UserAccountsEditPage extends UserAccountsPage {
|
|||
firstName = getStringParameter(PARAMETER_FIRST_NAME, "");
|
||||
lastName = getStringParameter(PARAMETER_LAST_NAME, "");
|
||||
selectedRoleUri = getStringParameter(PARAMETER_ROLE, "");
|
||||
associateWithProfile = isParameterAsExpected(
|
||||
PARAMETER_ASSOCIATE_WITH_PROFILE, "yes");
|
||||
associatedProfileUri = getStringParameter(
|
||||
PARAMETER_ASSOCIATED_PROFILE_URI, "");
|
||||
|
||||
strategy.parseAdditionalParameters();
|
||||
}
|
||||
|
@ -186,9 +186,6 @@ public class UserAccountsEditPage extends UserAccountsPage {
|
|||
body.put("roles", buildRolesList());
|
||||
}
|
||||
|
||||
if (associateWithProfile) {
|
||||
body.put("associate", Boolean.TRUE);
|
||||
}
|
||||
body.put("formUrls", buildUrlsMapWithEditUrl());
|
||||
|
||||
if (!errorCode.isEmpty()) {
|
||||
|
@ -216,6 +213,7 @@ public class UserAccountsEditPage extends UserAccountsPage {
|
|||
}
|
||||
|
||||
public void updateAccount() {
|
||||
// Assemble the fields of the account.
|
||||
userAccount.setEmailAddress(emailAddress);
|
||||
userAccount.setFirstName(firstName);
|
||||
userAccount.setLastName(lastName);
|
||||
|
@ -227,11 +225,15 @@ public class UserAccountsEditPage extends UserAccountsPage {
|
|||
userAccount.setPermissionSetUris(Collections
|
||||
.singleton(selectedRoleUri));
|
||||
}
|
||||
|
||||
strategy.setAdditionalProperties(userAccount);
|
||||
|
||||
// Update the account.
|
||||
userAccountsDao.updateUserAccount(userAccount);
|
||||
|
||||
// Associate the profile, as appropriate.
|
||||
UserAccountsAssociatedProfileHelper.reconcile(userAccount, associatedProfileUri);
|
||||
|
||||
// Tell the user.
|
||||
strategy.notifyUser();
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,128 @@
|
|||
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
|
||||
|
||||
package edu.cornell.mannlib.vitro.webapp.controller.accounts.admin.ajax;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServlet;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
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.ajax.VitroAjaxController;
|
||||
|
||||
/**
|
||||
* Handle the AJAX functions that are specific to the UserAccounts pages.
|
||||
*/
|
||||
public class UserAccountsAjaxController extends VitroAjaxController {
|
||||
private static final String PARAMETER_FUNCTION = "function";
|
||||
|
||||
@Override
|
||||
protected Actions requiredActions(VitroRequest vreq) {
|
||||
return new Actions(new ManageUserAccounts());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doRequest(VitroRequest vreq, HttpServletResponse resp)
|
||||
throws ServletException, IOException {
|
||||
String function = vreq.getParameter(PARAMETER_FUNCTION);
|
||||
if ("checkExternalAuth".equals(function)) {
|
||||
new ExternalAuthChecker(this, vreq, resp).processRequest();
|
||||
} else {
|
||||
new ErrorResponder(this, vreq, resp).processRequest();
|
||||
}
|
||||
}
|
||||
|
||||
static abstract class AjaxResponder {
|
||||
protected final HttpServlet parent;
|
||||
protected final VitroRequest vreq;
|
||||
protected final HttpServletResponse resp;
|
||||
|
||||
public AjaxResponder(HttpServlet parent, VitroRequest vreq,
|
||||
HttpServletResponse resp) {
|
||||
this.parent = parent;
|
||||
this.vreq = vreq;
|
||||
this.resp = resp;
|
||||
}
|
||||
|
||||
public abstract void processRequest() throws IOException;
|
||||
|
||||
protected String getStringParameter(String key, String defaultValue) {
|
||||
String value = vreq.getParameter(key);
|
||||
return (value == null) ? defaultValue : value;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* What is our reaction to this possible External Auth ID?
|
||||
*
|
||||
* Is somebody already using it (other than ourselves)? Does it match an
|
||||
* existing Profile? Neither?
|
||||
*/
|
||||
private static class ExternalAuthChecker extends AjaxResponder {
|
||||
private static final String PARAMETER_USER_ACCOUNT_URI = "userAccountUri";
|
||||
private static final String PARAMETER_ETERNAL_AUTH_ID = "externalAuthId";
|
||||
private static final String RESPONSE_ID_IN_USE = "idInUse";
|
||||
private static final String RESPONSE_MATCHES_PROFILE = "matchesProfile";
|
||||
private static final String RESPONSE_PROFILE_URI = "profileUri";
|
||||
private static final String RESPONSE_PROFILE_URL = "profileUrl";
|
||||
private static final String RESPONSE_PROFILE_LABEL = "profileLabel";
|
||||
|
||||
private final String userAccountUri;
|
||||
private final String externalAuthId;
|
||||
|
||||
public ExternalAuthChecker(HttpServlet parent, VitroRequest vreq,
|
||||
HttpServletResponse resp) {
|
||||
super(parent, vreq, resp);
|
||||
userAccountUri = getStringParameter(PARAMETER_USER_ACCOUNT_URI, "");
|
||||
externalAuthId = getStringParameter(PARAMETER_ETERNAL_AUTH_ID, "");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void processRequest() throws IOException {
|
||||
// TODO For now, a totally bogus response:
|
||||
// If "A", somebody else is already using the externalAuthId
|
||||
// If "B", matches "Joe Blow"
|
||||
// Anything else, no match.
|
||||
try {
|
||||
if ("A".equals(externalAuthId)) {
|
||||
JSONObject jsonObject = new JSONObject();
|
||||
jsonObject.put(RESPONSE_ID_IN_USE, true);
|
||||
resp.getWriter().write(jsonObject.toString());
|
||||
} else if ("B".equals(externalAuthId)) {
|
||||
JSONObject jsonObject = new JSONObject();
|
||||
jsonObject.put(RESPONSE_MATCHES_PROFILE, true);
|
||||
jsonObject.put(RESPONSE_PROFILE_URI,
|
||||
"http://some.bogus.profile");
|
||||
jsonObject.put(RESPONSE_PROFILE_URL,
|
||||
"http://some.bogus.profileUrl");
|
||||
jsonObject.put(RESPONSE_PROFILE_LABEL, "bogus label");
|
||||
resp.getWriter().write(jsonObject.toString());
|
||||
} else {
|
||||
resp.getWriter().write("[]");
|
||||
}
|
||||
} catch (JSONException e) {
|
||||
resp.getWriter().write("[]");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static class ErrorResponder extends AjaxResponder {
|
||||
public ErrorResponder(HttpServlet parent, VitroRequest vreq,
|
||||
HttpServletResponse resp) {
|
||||
super(parent, vreq, resp);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void processRequest() throws IOException {
|
||||
resp.getWriter().write("[]");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
137
webapp/web/js/account/accountAssociateProfile.js
Normal file
137
webapp/web/js/account/accountAssociateProfile.js
Normal file
|
@ -0,0 +1,137 @@
|
|||
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
|
||||
|
||||
var associateProfileFields = {
|
||||
|
||||
/* *** Initial page setup *** */
|
||||
|
||||
onLoad: function() {
|
||||
console.log('Here we are');
|
||||
if (this.disableFormInUnsupportedBrowsers()) {
|
||||
return;
|
||||
}
|
||||
this.mixIn();
|
||||
this.initObjects();
|
||||
this.initPage();
|
||||
},
|
||||
|
||||
disableFormInUnsupportedBrowsers: function() {
|
||||
var disableWrapper = $('#ie67DisableWrapper');
|
||||
|
||||
// Check for unsupported browsers only if the element exists on the page
|
||||
if (disableWrapper.length) {
|
||||
if (vitro.browserUtils.isIELessThan8()) {
|
||||
disableWrapper.show();
|
||||
$('.noIE67').hide();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
},
|
||||
|
||||
mixIn: function() {
|
||||
$.extend(this, associateProfileFieldsData);
|
||||
},
|
||||
|
||||
// On page load, create references for easy access to form elements.
|
||||
initObjects: function() {
|
||||
this.form = $('#userAccountForm');
|
||||
|
||||
// The external auth ID field and messages
|
||||
this.externalAuthIdField = $('#externalAuthId');
|
||||
this.externalAuthIdInUseMessage = $('#externalAuthIdInUse');
|
||||
|
||||
// We have an associated profile
|
||||
this.associatedArea = $('#associated');
|
||||
this.associatedProfileNameSpan = $('#associatedProfileName');
|
||||
this.verifyAssociatedProfileLink = $('#verifyProfileLink');
|
||||
this.associatedProfileUriField = $('#associatedProfileUri')
|
||||
|
||||
// We want to associate a profile
|
||||
this.associationOptionsArea = $('#associationOptions');
|
||||
},
|
||||
|
||||
// Initial page setup. Called only at page load.
|
||||
initPage: function() {
|
||||
this.checkForAssociatedProfile();
|
||||
|
||||
this.bindEventListeners();
|
||||
},
|
||||
|
||||
bindEventListeners: function() {
|
||||
console.log('bindEventListeners');
|
||||
|
||||
this.externalAuthIdField.change(function() {
|
||||
associateProfileFields.checkForAssociatedProfile();
|
||||
});
|
||||
this.externalAuthIdField.keyup(function() {
|
||||
associateProfileFields.checkForAssociatedProfile();
|
||||
});
|
||||
|
||||
this.verifyAssociatedProfileLink.click(function() {
|
||||
associateProfileFields.openVerifyWindow();
|
||||
return false;
|
||||
});
|
||||
|
||||
},
|
||||
|
||||
checkForAssociatedProfile: function() {
|
||||
$.ajax({
|
||||
url: associateProfileFields.ajaxUrl,
|
||||
dataType: "json",
|
||||
data: {
|
||||
function: "checkExternalAuth",
|
||||
userAccountUri: "",
|
||||
externalAuthId: associateProfileFields.externalAuthIdField.val()
|
||||
},
|
||||
complete: function(xhr, status) {
|
||||
var results = $.parseJSON(xhr.responseText);
|
||||
if (results.idInUse) {
|
||||
associateProfileFields.showExternalAuthIdInUse()
|
||||
} else if (results.matchesProfile) {
|
||||
associateProfileFields.showExternalAuthIdMatchesProfile(results.profileUri, results.profileUri, results.profileLabel)
|
||||
} else {
|
||||
associateProfileFields.showExternalAuthIdNotRecognized()
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
openVerifyWindow: function() {
|
||||
window.open(this.verifyUrl, 'verifyMatchWindow', 'width=640,height=640,scrollbars=yes,resizable=yes,status=yes,toolbar=no,menubar=no,location=no');
|
||||
},
|
||||
|
||||
showExternalAuthIdInUse: function() {
|
||||
this.externalAuthIdInUseMessage.show();
|
||||
this.associatedArea.hide();
|
||||
this.associationOptionsArea.hide();
|
||||
},
|
||||
|
||||
showExternalAuthIdMatchesProfile: function(profileUri, profileUrl, profileLabel) {
|
||||
console.log('showExternalAuthIdMatchesProfile: profileUri=' + profileUri + ', profileUrl=' + profileUrl + ', profileLabel='+ profileLabel);
|
||||
|
||||
this.externalAuthIdInUseMessage.hide();
|
||||
this.associatedArea.show();
|
||||
this.associationOptionsArea.hide();
|
||||
|
||||
this.associatedProfileNameSpan.html(profileLabel);
|
||||
this.associatedProfileUriField.val(profileUri);
|
||||
this.verifyUrl = profileUrl;
|
||||
},
|
||||
|
||||
showExternalAuthIdNotRecognized: function() {
|
||||
this.externalAuthIdInUseMessage.hide();
|
||||
this.associatedArea.hide();
|
||||
|
||||
if (this.externalAuthIdField.val().length > 0) {
|
||||
this.associationOptionsArea.show();
|
||||
} else {
|
||||
this.associationOptionsArea.hide();
|
||||
}
|
||||
},
|
||||
|
||||
}
|
||||
|
||||
$(document).ready(function() {
|
||||
associateProfileFields.onLoad();
|
||||
});
|
||||
|
|
@ -0,0 +1,55 @@
|
|||
<#-- $This file is distributed under the terms of the license in /doc/license.txt$ -->
|
||||
|
||||
<#-- Template for setting the account reference field, which can also associate a profile with the user account -->
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<td>
|
||||
<label for="externalAuthId">Account Reference</label>
|
||||
<input type="text" name="externalAuthId" value="${externalAuthId}" id="externalAuthId" role="input "/>
|
||||
<p>
|
||||
External Auth. ID or other unique ID. Can associate the account to the user's profile.
|
||||
</p>
|
||||
<p id="externalAuthIdInUse">
|
||||
That Account Reference is already in use.
|
||||
</p>
|
||||
</td>
|
||||
<td>
|
||||
<#-- If there is an associated profile, show these -->
|
||||
<div id="associated">
|
||||
<p>
|
||||
<label for="associatedProfileName">Associated profile:</label>
|
||||
<span class="acSelectionInfo" id="associatedProfileName"></span>
|
||||
<a href="" id="verifyProfileLink">(verify this match)</a>
|
||||
</p>
|
||||
<input type="hidden" id="associatedProfileUri" name="associatedProfileUri" value="" />
|
||||
</div>
|
||||
|
||||
<#-- If we haven't selected one, show these instead -->
|
||||
<div id="associationOptions">
|
||||
<p>
|
||||
<label for="associateProfileName">Select an existing profile</label>
|
||||
<input type="text" id="associateProfileName" name="associateProfileName" class="acSelector" size="35">
|
||||
</p>
|
||||
<p> - or - </p>
|
||||
<p>
|
||||
<label for="">Create an associated profile</label>
|
||||
<select name="degreeUri" id="degreeUri" >
|
||||
<option value="" selected="selected">Select one</option>
|
||||
<option value="" disabled>Bogus</option>
|
||||
</select>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<script type="text/javascript">
|
||||
var associateProfileFieldsData = {
|
||||
ajaxUrl: '${formUrls.accountsAjax}'
|
||||
};
|
||||
</script>
|
||||
|
||||
${scripts.add('<script type="text/javascript" src="${urls.base}/js/account/accountAssociateProfile.js"></script>')}
|
||||
|
|
@ -55,7 +55,7 @@
|
|||
<fieldset>
|
||||
<legend>Edit new account</legend>
|
||||
|
||||
<form method="POST" action="${formUrls.edit}" class="customForm" role="edit account">
|
||||
<form method="POST" action="${formUrls.edit}" id="userAccountForm" class="customForm" role="edit account">
|
||||
<label for="email-address">Email address<span class="requiredHint"> *</span></label>
|
||||
<input type="text" name="emailAddress" value="${emailAddress}" id="email-address" role="input" />
|
||||
|
||||
|
@ -65,8 +65,7 @@
|
|||
<label for="last-name">Last name<span class="requiredHint"> *</span></label>
|
||||
<input type="text" name="lastName" value="${lastName}" id="last-name" role="input" />
|
||||
|
||||
<label for="external-auth-id">External authorization ID</label>
|
||||
<input type="text" name="externalAuthId" value="${externalAuthId}" id="external-auth-id" role="input "/>
|
||||
<#include "userAccounts-associateProfilePanel.ftl">
|
||||
|
||||
<#if roles?has_content>
|
||||
<p>Roles<span class="requiredHint"> *</span> </p>
|
||||
|
@ -77,7 +76,16 @@
|
|||
</#list>
|
||||
</#if>
|
||||
|
||||
<#if !emailIsEnabled??>
|
||||
<#if emailIsEnabled??>
|
||||
<input type="checkbox" name="resetPassword" value="" id="reset-password" role="checkbox" <#if resetPassword??>checked</#if> />
|
||||
<label class="inline" for="reset-password"> Reset password</label>
|
||||
|
||||
<p class="note">
|
||||
Note: Instructions for resetting the password will
|
||||
be emailed to the address entered above. The password will not
|
||||
be reset until the user follows the link provided in this email.
|
||||
</p>
|
||||
<#else>
|
||||
<label for="new-password">New password<span class="requiredHint"> *</span></label>
|
||||
<input type="password" name="newPassword" value="${newPassword}" id="new-password" role="input" />
|
||||
|
||||
|
@ -85,28 +93,9 @@
|
|||
<p>Leaving this blank means that the password will not be changed.</p>
|
||||
|
||||
<label for="confirm-password">Confirm initial password<span class="requiredHint"> *</span></label>
|
||||
<input type="text" name="confirmPassword" value="${confirmPassword}" id="confirm-password" role="input" />
|
||||
<input type="password" name="confirmPassword" value="${confirmPassword}" id="confirm-password" role="input" />
|
||||
</#if>
|
||||
|
||||
<p>Associate a profile with this account</p>
|
||||
<input type="radio" name="associate" value="yes" role="radio" <#if associate??>checked</#if> id="associate" />
|
||||
<label class="inline" for="associate"> Yes</label>
|
||||
|
||||
<input type="radio" name="associate" value="no" role="radio" <#if !associate??>checked</#if> id="no-associate" />
|
||||
<label class="inline" for="no-associate"> No</label>
|
||||
|
||||
<br />
|
||||
<input type="checkbox" name="resetPassword" value="" id="reset-password" role="checkbox" <#if resetPassword??>checked</#if> />
|
||||
<label class="inline" for="reset-password"> Reset password</label>
|
||||
|
||||
<#if emailIsEnabled??>
|
||||
<p class="note">
|
||||
Note: Instructions for resetting the password will
|
||||
be emailed to the address entered above. The password will not
|
||||
be reset until the user follows the link provided in this email.
|
||||
</p>
|
||||
</#if>
|
||||
|
||||
<input type="submit" name="submitEdit" value="Save changes" class="submit" /> or <a class="cancel" href="${formUrls.list}">Cancel</a>
|
||||
|
||||
<p class="requiredHint">* required fields</p>
|
||||
|
@ -115,4 +104,4 @@
|
|||
</section>
|
||||
|
||||
${stylesheets.add('<link rel="stylesheet" href="${urls.base}/css/account/account.css" />')}
|
||||
${stylesheets.add('<link rel="stylesheet" href="${urls.base}/edit/forms/css/customForm.css" />')}
|
||||
${stylesheets.add('<link rel="stylesheet" href="${urls.base}/edit/forms/css/customForm.css" />')}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue