NIHVIVO-1296 Integrate login functionality into login widget.

This commit is contained in:
rjy7 2010-11-15 22:17:20 +00:00
parent 73b881a805
commit 2973ceebf2
14 changed files with 237 additions and 148 deletions

View file

@ -233,6 +233,9 @@ public class FreemarkerHttpServlet extends VitroHttpServlet {
// We can't use shared variables in the Freemarker configuration to store anything
// except theme-specific data, because multiple portals or apps might share the same theme. So instead
// we'll get all the shared variables here, and put them in both root and body maps.
// If we can eliminate this use case and use shared variables, it would simplify the implementation greatly.
// See also directives, where since there are no shared variables we have to manually put elements
// of the data model into the directive template model.
public Map<String, Object> getSharedVariables(VitroRequest vreq, Map<String, Object> bodyMap) {
Map<String, Object> map = new HashMap<String, Object>();

View file

@ -2,7 +2,7 @@
package edu.cornell.mannlib.vitro.webapp.web.widgets;
import java.util.HashMap;
import java.io.IOException;
import java.util.Map;
import javax.servlet.ServletContext;
@ -11,18 +11,159 @@ import javax.servlet.http.HttpServletRequest;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import edu.cornell.mannlib.vedit.beans.LoginStatusBean;
import edu.cornell.mannlib.vitro.webapp.controller.login.LoginProcessBean;
import edu.cornell.mannlib.vitro.webapp.controller.login.LoginProcessBean.State;
import freemarker.core.Environment;
import freemarker.template.TemplateModel;
public class LoginWidget extends Widget {
private static final Log log = LogFactory.getLog(LoginWidget.class);
private static enum Macro {
LOGIN("loginForm"),
FORCE_PASSWORD_CHANGE("forcePasswordChange"),
SERVER_ERROR("error");
private final String macroName;
Macro(String macroName) {
this.macroName = macroName;
}
public String toString() {
return macroName;
}
}
private static enum TemplateVariable {
LOGIN_NAME("loginName"),
FORM_ACTION("formAction"),
INFO_MESSAGE("infoMessage"),
ERROR_MESSAGE("errorMessage"),
CANCEL_URL("cancelUrl");
private final String variableName;
TemplateVariable(String variableName) {
this.variableName = variableName;
}
public String toString() {
return variableName;
}
}
@Override
protected WidgetTemplateValues process(Environment env, Map params,
HttpServletRequest request, ServletContext context) {
Map<String, Object> map = new HashMap<String, Object>();
map.put("fruit", "bananas");
return new WidgetTemplateValues (getMarkupMacroName(), map);
WidgetTemplateValues values = null;
TemplateModel urls = null;
try {
urls = env.getDataModel().get("urls");
State state = getCurrentLoginState(request);
log.debug("State on exit: " + state);
switch (state) {
case LOGGED_IN:
return null;
case FORCED_PASSWORD_CHANGE:
values = showPasswordChangeScreen(request);
break;
default:
values = showLoginScreen(request);
}
} catch (Exception e) {
log.error(e);
values = showError(e);
}
values.put("urls", urls);
return values;
}
/**
* User is just starting the login process. Be sure that we have a
* {@link LoginProcessBean} with the correct status. Show them the login
* screen.
*/
private WidgetTemplateValues showLoginScreen(HttpServletRequest request)
throws IOException {
LoginProcessBean bean = LoginProcessBean.getBean(request);
bean.setState(State.LOGGING_IN);
log.trace("Going to login screen: " + bean);
WidgetTemplateValues values = new WidgetTemplateValues(Macro.LOGIN.toString());
values.put(TemplateVariable.FORM_ACTION.toString(), getAuthenticateUrl(request));
values.put(TemplateVariable.LOGIN_NAME.toString(), bean.getUsername());
String infoMessage = bean.getInfoMessage();
if (!infoMessage.isEmpty()) {
values.put(TemplateVariable.INFO_MESSAGE.toString(), infoMessage);
}
String errorMessage = bean.getErrorMessage();
if (!errorMessage.isEmpty()) {
values.put(TemplateVariable.ERROR_MESSAGE.toString(), errorMessage);
}
return values;
}
/**
* The user has given the correct password, but now they are required to
* change it (unless they cancel out).
*/
private WidgetTemplateValues showPasswordChangeScreen(HttpServletRequest request) {
LoginProcessBean bean = LoginProcessBean.getBean(request);
bean.setState(State.FORCED_PASSWORD_CHANGE);
log.trace("Going to password change screen: " + bean);
WidgetTemplateValues values = new WidgetTemplateValues(
Macro.FORCE_PASSWORD_CHANGE.toString());
values.put(TemplateVariable.FORM_ACTION.toString(), getAuthenticateUrl(request));
values.put(TemplateVariable.CANCEL_URL.toString(), getCancelUrl(request));
String errorMessage = bean.getErrorMessage();
if (!errorMessage.isEmpty()) {
values.put(TemplateVariable.ERROR_MESSAGE.toString(), errorMessage);
}
return values;
}
private WidgetTemplateValues showError(Exception e) {
WidgetTemplateValues values = new WidgetTemplateValues(
Macro.SERVER_ERROR.toString());
values.put(TemplateVariable.ERROR_MESSAGE.toString(), "Internal server error:<br /> " + e);
return values;
}
/**
* Where are we in the process? Logged in? Not? Somewhere in between?
*/
private State getCurrentLoginState(HttpServletRequest request) {
if (LoginStatusBean.getBean(request).isLoggedIn()) {
return State.LOGGED_IN;
} else {
return LoginProcessBean.getBean(request).getState();
}
}
/** What's the URL for this servlet? */
private String getAuthenticateUrl(HttpServletRequest request) {
String contextPath = request.getContextPath();
return contextPath + "/authenticate";
}
/** What's the URL for this servlet, with the cancel parameter added? */
private String getCancelUrl(HttpServletRequest request) {
String contextPath = request.getContextPath();
String urlParams = "?cancel=true";
return contextPath + "/authenticate" + urlParams;
}
}

View file

@ -56,6 +56,11 @@ public abstract class Widget {
ServletContext context = (ServletContext) env.getCustomAttribute("context");
WidgetTemplateValues values = process(env, params, request, context);
// The widget process() method may determine that nothing should display for the widget:
// for example, the login widget doesn't display if the user is already logged in.
if (values == null) {
return "";
}
String widgetName = params.get("name").toString(); // getWidgetName();
return processMacroToString(env, widgetName, values);
}
@ -106,7 +111,9 @@ public abstract class Widget {
} catch (Throwable th) {
log.error("Could not process widget " + widgetName, th);
}
return out.toString();
String output = out.toString();
log.debug("Macro output: " + output);
return output;
}
private String processMacroToString(Environment env, String widgetName, String macroName, Map<String, Object> map) {
@ -134,9 +141,14 @@ public abstract class Widget {
protected static class WidgetTemplateValues {
private final String macroName;
private final Map<String, Object> map;
public WidgetTemplateValues(String macroName) {
this.macroName = macroName;
this.map = new HashMap<String, Object>();
}
public WidgetTemplateValues(String templateName, Map<String, Object> map) {
this.macroName = templateName;
public WidgetTemplateValues(String macroName, Map<String, Object> map) {
this.macroName = macroName;
this.map = map;
}

View file

@ -133,12 +133,8 @@
color:#900;
}
/* In IE6/7, .hidden defined in screen.css doesn't override
* display: inline-block defined for #adminDashboard .pageBodyGroup,
* so define again with context selector here.
*/
#adminDashboard .pageBodyGroup.hidden {
display: none !important;
#loginFormAndLinks {
display: none;
}
p.passwordNote {

View file

@ -3,7 +3,7 @@
$(document).ready(function(){
// login form is hidden by default; use JavaScript to reveal
$("#formLogin").removeClass("hidden");
$("#loginFormAndLinks").show();
// focus on email or newpassword field
$('.focus').focus();

View file

@ -1,11 +0,0 @@
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
$(document).ready(function(){
// login form is hidden by default; use JavaScript to reveal
$("#formLogin").removeClass("hidden");
// focus on email or newpassword field
$('.focus').focus();
});

View file

@ -1,28 +0,0 @@
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
$(document).ready(function(){
// login form is hidden by default; use JavaScript to reveal
$("#formLogin").removeClass("hidden");
// focus on email or newpassword field
$('.focus').focus();
});
//The above code for revealing the login form doesn't work IE 6 or 7. The code below fix the problem
var Browser = {
Version: function() {
var version;
if (navigator.appVersion.indexOf("MSIE") != -1)
version = parseFloat(navigator.appVersion.split("MSIE")[1]);
return version;
}
}
if (Browser.Version() <= 7) {
document.getElementById('formLogin').style.display = 'block';
}

View file

@ -1,12 +0,0 @@
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
$(document).ready(function(){
// login form is hidden by default; use JavaScript to reveal
$("#formLogin").removeClass("hidden");
// focus on email or newpassword field
$('.focus').focus();
});

View file

@ -1,22 +0,0 @@
<#-- $This file is distributed under the terms of the license in /doc/license.txt$ -->
<#-- Log in template for accessing site admin -->
<div id="formLogin">
<h2>Create Your New Password</h2>
<#if errorMessage??>
<div id="errorAlert"><img src="${urls.siteIcons}/iconAlert.png" width="24" height="24" alert="Error alert icon"/>
<p>${errorMessage}</p>
</div>
</#if>
<form action="${formAction}" method="post">
<label for="newPassword">New Password</label>
<input id="newPassword" class="focus" type="password" name="newPassword" />
<p class="passwordNote">Minimum of 6 characters in length.</p>
<label for="confirmPassword">Confirm Password</label>
<input id="confirmPassword" type="password" name="confirmPassword" />
<input name="passwordChangeForm" type="submit" class="submit" value="Save Changes"/> <span class="or">or <a class="cancel" href="${cancelUrl}">Cancel</a></span>
</form>
</div>

View file

@ -1,35 +0,0 @@
<#-- $This file is distributed under the terms of the license in /doc/license.txt$ -->
<#-- Template for login form -->
<noscript>
<div id="javascriptDisableWrapper">
<div id="javascriptDisableContent">
<img src="${urls.siteIcons}/iconAlertBig.png" alt="Alert Icon"/>
<p>In order to edit VIVO content, you'll need to enable JavaScript.</p>
</div>
</div>
</noscript>
<div id="formLogin" class="hidden" >
<h2>Log in</h2>
<#if infoMessage??>
<h3>${infoMessage}</h3>
</#if>
<#if errorMessage??>
<div id="errorAlert"><img src="${urls.siteIcons}/iconAlert.png" alert="Error alert icon"/>
<p>${errorMessage}</p>
</div>
</#if>
<form action="${formAction}" method="post">
<label for="loginName">Email or Username</label>
<input id="loginName" class="focus" name="loginName" type="text" value="${loginName}" />
<label for="loginPassword">Password</label>
<input id="loginPassword" type="password" name="loginPassword" />
<input name="loginForm" type="submit" class="submit" value="Log in"/>
</form>
</div>

View file

@ -1,10 +0,0 @@
<#-- $This file is distributed under the terms of the license in /doc/license.txt$ -->
<#-- Main template for the login panel -->
<#if loginTemplate??>
<#include loginTemplate>
${stylesheets.add("/css/login.css")}
${scripts.add("/js/jquery.js", "/js/login/loginUtils.js")}
</#if>

View file

@ -0,0 +1,8 @@
<#-- $This file is distributed under the terms of the license in /doc/license.txt$ -->
<#-- Main template for the login page -->
<#-- Use this container to define styles that apply to the login widget only on the dedicated login page. -->
<section id="login-full-page">
<@widget name="login" />
</section>

View file

@ -7,7 +7,7 @@
</div>
<div id="adminDashboard">
<#include "login-main.ftl">
<#include "siteAdmin-login.ftl">
<#include "siteAdmin-dataInput.ftl">
<#include "siteAdmin-siteConfiguration.ftl">
<#include "siteAdmin-ontologyEditor.ftl">

View file

@ -3,25 +3,47 @@
<#-- Login widget -->
<#macro assets>
<#if ! loginName??>
<#-- RY This test should be replaced by controller logic which doesn't display any assets if the user is logged in.
See NIHVIVO-1357. This test does nothing, since loginName has not been put into the data model.
<#if ! loginName?has_content> -->
${stylesheets.add("/css/login.css")}
<#-- define any js files needed for the login widget
${scripts.add("")}
${headScripts.add("")} -->
</#if>
${scripts.add("/js/jquery.js", "/js/login/loginUtils.js")}
<#-- ${headScripts.add("")} -->
<#-- </#if> -->
</#macro>
<#macro markup>
<#if ! loginName??>
<section id="log-in">
<h2>Log in</h2>
<#macro loginForm>
<form id="log-in-form" action="${urls.home}/authenticate?login=block" method="post" name="log-in-form" />
<section id="log-in">
<h2>Log in</h2>
<noscript>
<section id="javascriptDisableWrapper">
<section id="javascriptDisableContent">
<img src="${urls.siteIcons}/iconAlertBig.png" alt="Alert Icon"/>
<p>In order to edit VIVO content, you'll need to enable JavaScript.</p>
</section>
</section>
</noscript>
<#if infoMessage??>
<h3>${infoMessage}</h3>
</#if>
<#if errorMessage??>
<section id="errorAlert"><img src="${urls.siteIcons}/iconAlert.png" alert="Error alert icon"/>
<p>${errorMessage}</p>
</section>
</#if>
<section id="loginFormAndLinks">
<form id="log-in-form" action="${formAction}" method="post" name="log-in-form" />
<label for="email">Email</label>
<input class="text-field" name="loginName" id="loginName" type="text" required />
<label for="password">Password</label>
<input class="text-field" name="loginPassword" id="password" type="loginPassword" required />
<input class="text-field" name="loginPassword" id="password" type="password" required />
<p class="submit"><input name="loginForm" type="submit" class="green button" value="Log in"/></p>
@ -31,6 +53,31 @@
<p class="forgot-password"><a href="#">Forgot your password?</a></p>
<p class="request-account"><a class=" blue button" href="#">Request an account</a> </p>
</section><!-- #log-in -->
</#if>
</#macro> -->
</section>
</section><!-- #log-in -->
</#macro>
<#macro forcePasswordChange>
<section id="log-in">
<h2>Log in</h2>
<#if errorMessage??>
<div id="errorAlert"><img src="${urls.siteIcons}/iconAlert.png" width="24" height="24" alert="Error alert icon"/>
<p>${errorMessage}</p>
</div>
</#if>
<form id="log-in-form" action="${formAction}" method="post" name="log-in-form" />
<label for="newPassword">New Password</label>
<input id="newPassword" class="focus" type="password" name="newPassword" />
<p class="passwordNote">Minimum of 6 characters in length.</p>
<label for="confirmPassword">Confirm Password</label>
<input id="confirmPassword" type="password" name="confirmPassword" />
<input name="passwordChangeForm" type="submit" class="submit" value="Save Changes"/> <span class="or">or <a class="cancel" href="${cancelUrl}">Cancel</a></span>
</form>
</section>
</#macro>
<#macro error>
<p>There was an error in the system.</p>
</#macro>