From 89a91757c0a76dff0738e36eb82bd7505b75d513 Mon Sep 17 00:00:00 2001 From: j2blake Date: Fri, 1 Jul 2011 16:19:53 +0000 Subject: [PATCH] NIHVIVO-2279 Flesh out the UI for editing UserAccount, and associating with Individual Profiles --- .../controller/accounts/UserAccountsPage.java | 45 +++++++++++++++-- .../accounts/admin/UserAccountsAddPage.java | 32 +++++++++---- .../accounts/admin/UserAccountsEditPage.java | 22 +++++++-- .../web/js/account/accountAssociateProfile.js | 48 +++++++++++++++++-- .../body/accounts/userAccounts-add.ftl | 35 +++++++------- .../userAccounts-associateProfilePanel.ftl | 20 ++++++-- .../body/accounts/userAccounts-edit.ftl | 18 ++++--- 7 files changed, 172 insertions(+), 48 deletions(-) diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/accounts/UserAccountsPage.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/accounts/UserAccountsPage.java index 905c52953..fe3ed3ea4 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/accounts/UserAccountsPage.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/accounts/UserAccountsPage.java @@ -10,9 +10,10 @@ import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.SortedMap; +import java.util.TreeMap; import javax.servlet.ServletContext; -import javax.servlet.http.HttpServletRequest; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -21,10 +22,14 @@ import com.hp.hpl.jena.ontology.OntModel; import edu.cornell.mannlib.vitro.webapp.beans.PermissionSet; import edu.cornell.mannlib.vitro.webapp.beans.UserAccount; +import edu.cornell.mannlib.vitro.webapp.beans.VClass; 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.ParamMap; +import edu.cornell.mannlib.vitro.webapp.dao.DataPropertyStatementDao; +import edu.cornell.mannlib.vitro.webapp.dao.IndividualDao; import edu.cornell.mannlib.vitro.webapp.dao.UserAccountsDao; +import edu.cornell.mannlib.vitro.webapp.dao.VClassDao; import edu.cornell.mannlib.vitro.webapp.dao.WebappDaoFactory; import edu.cornell.mannlib.vitro.webapp.dao.jena.OntModelSelector; import edu.cornell.mannlib.vitro.webapp.email.FreemarkerEmailFactory; @@ -35,6 +40,8 @@ import edu.cornell.mannlib.vitro.webapp.email.FreemarkerEmailFactory; public abstract class UserAccountsPage { private static final Log log = LogFactory.getLog(UserAccountsPage.class); + private static final String PERSON_CLASS_URI = "http://xmlns.com/foaf/0.1/Person"; + /** * After the account is created, or the password is reset, the user has this * many days to repond to the email. @@ -45,6 +52,9 @@ public abstract class UserAccountsPage { protected final ServletContext ctx; protected final OntModel userAccountsModel; protected final UserAccountsDao userAccountsDao; + protected final VClassDao vclassDao; + protected final IndividualDao indDao; + protected final DataPropertyStatementDao dpsDao; protected UserAccountsPage(VitroRequest vreq) { this.vreq = vreq; @@ -57,6 +67,9 @@ public abstract class UserAccountsPage { WebappDaoFactory wdf = (WebappDaoFactory) this.ctx .getAttribute("webappDaoFactory"); userAccountsDao = wdf.getUserAccountsDao(); + vclassDao = wdf.getVClassDao(); + indDao = wdf.getIndividualDao(); + dpsDao = wdf.getDataPropertyStatementDao(); } protected boolean isEmailEnabled() { @@ -93,10 +106,10 @@ public abstract class UserAccountsPage { /** * Treat the presence of a certain parameter, with a desired value, as a - * boolean flag. + * boolean flag. * - * An example would be radio buttons with values of "yes" and - * "no". The expected value would be "yes". + * An example would be radio buttons with values of "yes" and "no". The + * expected value would be "yes". */ protected boolean isParameterAsExpected(String key, String expected) { return expected.equals(getStringParameter(key, "")); @@ -117,6 +130,27 @@ public abstract class UserAccountsPage { return list; } + /** + * Create a list of possible profile types. + * + * TODO Right now, these are foaf:Person and it's sub-classes. What will it + * be for Vitro? + */ + protected SortedMap buildProfileTypesList() { + String seedClassUri = PERSON_CLASS_URI; + List classUris = vclassDao.getAllSubClassURIs(seedClassUri); + classUris.add(seedClassUri); + + SortedMap types = new TreeMap(); + for (String classUri: classUris) { + VClass vclass = vclassDao.getVClassByURI(classUri); + if (vclass != null) { + types.put(classUri, vclass.getName()); + } + } + return types; + } + /** * Make these URLs available to all of the pages. */ @@ -129,7 +163,8 @@ public abstract class UserAccountsPage { map.put("myAccount", UrlBuilder.getUrl("/accounts/myAccount")); map.put("createPassword", UrlBuilder.getUrl("/accounts/createPassword")); map.put("resetPassword", UrlBuilder.getUrl("/accounts/resetPassword")); - map.put("firstTimeExternal", UrlBuilder.getUrl("/accounts/firstTimeExternal")); + map.put("firstTimeExternal", + UrlBuilder.getUrl("/accounts/firstTimeExternal")); map.put("accountsAjax", UrlBuilder.getUrl("/accountsAjax")); return map; diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/accounts/admin/UserAccountsAddPage.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/accounts/admin/UserAccountsAddPage.java index 2add74003..54221cda3 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/accounts/admin/UserAccountsAddPage.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/accounts/admin/UserAccountsAddPage.java @@ -6,6 +6,7 @@ import java.util.Collections; import java.util.HashMap; import java.util.Map; +import edu.cornell.mannlib.vitro.webapp.beans.SelfEditingConfiguration; 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; @@ -26,7 +27,7 @@ public class UserAccountsAddPage 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"; @@ -39,6 +40,7 @@ public class UserAccountsAddPage extends UserAccountsPage { private static final String TEMPLATE_NAME = "userAccounts-add.ftl"; private final UserAccountsAddPageStrategy strategy; + private final boolean matchingIsEnabled; /* The request parameters */ private boolean submit; @@ -47,7 +49,7 @@ public class UserAccountsAddPage extends UserAccountsPage { private String firstName = ""; private String lastName = ""; private String selectedRoleUri = ""; - private boolean associateWithProfile; + private String associatedProfileUri = ""; /** The result of validating a "submit" request. */ private String errorCode = ""; @@ -61,6 +63,9 @@ public class UserAccountsAddPage extends UserAccountsPage { this.strategy = UserAccountsAddPageStrategy.getInstance(vreq, this, isEmailEnabled()); + this.matchingIsEnabled = SelfEditingConfiguration.getBean(vreq) + .isConfigured(); + parseRequestParameters(); if (submit) { @@ -75,8 +80,8 @@ public class UserAccountsAddPage 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(); } @@ -125,26 +130,33 @@ public class UserAccountsAddPage extends UserAccountsPage { } public void createNewAccount() { + // Assemble the fields into a new UserAccount UserAccount u = new UserAccount(); u.setEmailAddress(emailAddress); u.setFirstName(firstName); u.setLastName(lastName); u.setExternalAuthId(externalAuthId); - u.setMd5Password(""); u.setOldPassword(""); u.setPasswordChangeRequired(false); u.setPasswordLinkExpires(0); u.setLoginCount(0); u.setStatus(Status.INACTIVE); - u.setPermissionSetUris(Collections.singleton(selectedRoleUri)); strategy.setAdditionalProperties(u); + // Create the account. String uri = userAccountsDao.insertUserAccount(u); this.addedAccount = userAccountsDao.getUserAccountByUri(uri); + // Associate the profile, as appropriate. + if (matchingIsEnabled) { + SelfEditingConfiguration.getBean(vreq) + .associateIndividualWithUserAccount(indDao, dpsDao, + this.addedAccount, associatedProfileUri); + } + strategy.notifyUser(); } @@ -156,15 +168,17 @@ public class UserAccountsAddPage extends UserAccountsPage { body.put("firstName", firstName); body.put("lastName", lastName); body.put("selectedRole", selectedRoleUri); - if (associateWithProfile) { - body.put("associate", Boolean.TRUE); - } body.put("roles", buildRolesList()); + body.put("profileTypes", buildProfileTypesList()); body.put("formUrls", buildUrlsMap()); if (!errorCode.isEmpty()) { body.put(errorCode, Boolean.TRUE); } + + if (matchingIsEnabled) { + body.put("showAssociation", Boolean.TRUE); + } strategy.addMoreBodyValues(body); diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/accounts/admin/UserAccountsEditPage.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/accounts/admin/UserAccountsEditPage.java index 7c64cfbb2..b8a53b76a 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/accounts/admin/UserAccountsEditPage.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/accounts/admin/UserAccountsEditPage.java @@ -10,6 +10,7 @@ import java.util.Set; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import edu.cornell.mannlib.vitro.webapp.beans.SelfEditingConfiguration; import edu.cornell.mannlib.vitro.webapp.beans.UserAccount; import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest; import edu.cornell.mannlib.vitro.webapp.controller.accounts.UserAccountsPage; @@ -45,6 +46,7 @@ public class UserAccountsEditPage extends UserAccountsPage { private static final String TEMPLATE_NAME = "userAccounts-edit.ftl"; private final UserAccountsEditPageStrategy strategy; + private final boolean matchingIsEnabled; /* The request parameters */ private boolean submit; @@ -70,6 +72,9 @@ public class UserAccountsEditPage extends UserAccountsPage { this.strategy = UserAccountsEditPageStrategy.getInstance(vreq, this, isEmailEnabled()); + this.matchingIsEnabled = SelfEditingConfiguration.getBean(vreq) + .isConfigured(); + parseRequestParameters(); validateUserAccountInfo(); @@ -168,6 +173,8 @@ public class UserAccountsEditPage extends UserAccountsPage { public final ResponseValues showPage() { Map body = new HashMap(); + body.put("userUri", userUri); + if (isSubmit()) { body.put("emailAddress", emailAddress); body.put("externalAuthId", externalAuthId); @@ -185,13 +192,18 @@ public class UserAccountsEditPage extends UserAccountsPage { if (!isRootUser()) { body.put("roles", buildRolesList()); } - + + body.put("profileTypes", buildProfileTypesList()); body.put("formUrls", buildUrlsMapWithEditUrl()); if (!errorCode.isEmpty()) { body.put(errorCode, Boolean.TRUE); } + if (matchingIsEnabled) { + body.put("showAssociation", Boolean.TRUE); + } + strategy.addMoreBodyValues(body); return new TemplateResponseValues(TEMPLATE_NAME, body); @@ -229,9 +241,13 @@ public class UserAccountsEditPage extends UserAccountsPage { // Update the account. userAccountsDao.updateUserAccount(userAccount); - + // Associate the profile, as appropriate. - UserAccountsAssociatedProfileHelper.reconcile(userAccount, associatedProfileUri); + if (matchingIsEnabled) { + SelfEditingConfiguration.getBean(vreq) + .associateIndividualWithUserAccount(indDao, dpsDao, + userAccount, associatedProfileUri); + } // Tell the user. strategy.notifyUser(); diff --git a/webapp/web/js/account/accountAssociateProfile.js b/webapp/web/js/account/accountAssociateProfile.js index 27f9ff6d6..9ff87f05f 100644 --- a/webapp/web/js/account/accountAssociateProfile.js +++ b/webapp/web/js/account/accountAssociateProfile.js @@ -9,6 +9,7 @@ var associateProfileFields = { if (this.disableFormInUnsupportedBrowsers()) { return; } + this.mixIn(); this.initObjects(); this.initPage(); @@ -44,17 +45,19 @@ var associateProfileFields = { this.associatedArea = $('#associated'); this.associatedProfileNameSpan = $('#associatedProfileName'); this.verifyAssociatedProfileLink = $('#verifyProfileLink'); + this.changeAssociatedProfileLink = $('#changeProfileLink'); this.associatedProfileUriField = $('#associatedProfileUri') // We want to associate a profile this.associationOptionsArea = $('#associationOptions'); + this.associateProfileNameField = $('#associateProfileName'); }, // Initial page setup. Called only at page load. initPage: function() { this.checkForAssociatedProfile(); - this.bindEventListeners(); + this.initAutocomplete(); }, bindEventListeners: function() { @@ -72,15 +75,48 @@ var associateProfileFields = { return false; }); + this.changeAssociatedProfileLink.click(function() { + associateProfileFields.associatedProfileUriField.val(''); + associateProfileFields.associateProfileNameField.val(''); + associateProfileFields.showExternalAuthIdNotRecognized(); + return false; + }); + }, + initAutocomplete: function() { + this.associateProfileNameField.autocomplete({ + minLength: 3, + source: function(request, response) { + $.ajax({ + url: associateProfileFields.ajaxUrl, + dataType: 'json', + data: { + function: "autoCompleteProfile", + term: request.term, + externalAuthId: associateProfileFields.externalAuthIdField.val() + }, + complete: function(xhr, status) { + console.log('response text' + xhr.responseText); + var results = jQuery.parseJSON(xhr.responseText); + response(results); + } + }); + }, + select: function(event, ui) { + associateProfileFields.showSelectedProfile(ui.item); + } + }); + + }, + checkForAssociatedProfile: function() { $.ajax({ url: associateProfileFields.ajaxUrl, dataType: "json", data: { function: "checkExternalAuth", - userAccountUri: "", + userAccountUri: associateProfileFields.userUri, externalAuthId: associateProfileFields.externalAuthIdField.val() }, complete: function(xhr, status) { @@ -88,7 +124,7 @@ var associateProfileFields = { if (results.idInUse) { associateProfileFields.showExternalAuthIdInUse() } else if (results.matchesProfile) { - associateProfileFields.showExternalAuthIdMatchesProfile(results.profileUri, results.profileUri, results.profileLabel) + associateProfileFields.showExternalAuthIdMatchesProfile(results.profileUri, results.profileUrl, results.profileLabel) } else { associateProfileFields.showExternalAuthIdNotRecognized() } @@ -122,13 +158,17 @@ var associateProfileFields = { this.externalAuthIdInUseMessage.hide(); this.associatedArea.hide(); - if (this.externalAuthIdField.val().length > 0) { + if (this.associationEnabled && this.externalAuthIdField.val().length > 0) { this.associationOptionsArea.show(); } else { this.associationOptionsArea.hide(); } }, + showSelectedProfile: function(item) { + this.showExternalAuthIdMatchesProfile(item.uri, item.url, item.label); + }, + } $(document).ready(function() { diff --git a/webapp/web/templates/freemarker/body/accounts/userAccounts-add.ftl b/webapp/web/templates/freemarker/body/accounts/userAccounts-add.ftl index 13ccc3009..c53165350 100644 --- a/webapp/web/templates/freemarker/body/accounts/userAccounts-add.ftl +++ b/webapp/web/templates/freemarker/body/accounts/userAccounts-add.ftl @@ -68,6 +68,8 @@ + <#include "userAccounts-associateProfilePanel.ftl"> +

Roles *

<#list roles as role> checked /> @@ -75,31 +77,28 @@
- <#if !emailIsEnabled??> - - - -

Minimum of ${minimumLength} characters in length.

- - - - - -

Associate a profile with this account

- checked id="associate" /> - - - checked id="no-associate" /> - - <#if emailIsEnabled??>

Note: An email will be sent to the address entered above notifying that an account has been created. It will include instructions for activating the account and creating a password.

+ <#else> + + + + + +
+ + + + + +
+

Minimum of ${minimumLength} characters in length.

- + or Cancel

* required fields

diff --git a/webapp/web/templates/freemarker/body/accounts/userAccounts-associateProfilePanel.ftl b/webapp/web/templates/freemarker/body/accounts/userAccounts-associateProfilePanel.ftl index 4249fafe4..e02d41756 100644 --- a/webapp/web/templates/freemarker/body/accounts/userAccounts-associateProfilePanel.ftl +++ b/webapp/web/templates/freemarker/body/accounts/userAccounts-associateProfilePanel.ftl @@ -21,6 +21,7 @@ (verify this match) + (change profile)

@@ -36,7 +37,9 @@

@@ -47,9 +50,20 @@ -${scripts.add('')} +${scripts.add('', + '', + '')} diff --git a/webapp/web/templates/freemarker/body/accounts/userAccounts-edit.ftl b/webapp/web/templates/freemarker/body/accounts/userAccounts-edit.ftl index 863124d5b..6b6749ffb 100644 --- a/webapp/web/templates/freemarker/body/accounts/userAccounts-edit.ftl +++ b/webapp/web/templates/freemarker/body/accounts/userAccounts-edit.ftl @@ -86,14 +86,20 @@ be reset until the user follows the link provided in this email.

<#else> - - - + + + + + +
+ + + + + +

Minimum of ${minimumLength} characters in length.

Leaving this blank means that the password will not be changed.

- - - or Cancel