NIHVIVO-1386 Self-editors don't get SiteAdmin link in top nav. They also don't get revision info link in footer. Implemented with new User template model class. Changed tests for loginName, showFlag1Status in templates to use this object.

This commit is contained in:
rjy7 2010-11-23 01:28:39 +00:00
parent 130b641081
commit ca6ab8288e
18 changed files with 225 additions and 77 deletions

View file

@ -40,7 +40,7 @@ public class PrimitiveRdfEdit extends FreemarkerHttpServlet{
}
@Override
protected int requiresLoginLevel() {
protected int requiredLoginLevel() {
return LoginStatusBean.EDITOR;
}

View file

@ -43,6 +43,8 @@ public class FreemarkerComponentGenerator extends FreemarkerHttpServlet {
request.setAttribute("ftl_search", get("search", root, config, vreq));
request.setAttribute("ftl_footer", get("footer", root, config, vreq));
request.setAttribute("ftl_googleAnalytics", get("googleAnalytics", root, config, vreq));
request.setAttribute("freemarkerComponentsDone", true);
}
private String get(String templateName, Map<String, Object> root, Configuration config, HttpServletRequest request) {

View file

@ -32,6 +32,7 @@ import edu.cornell.mannlib.vitro.webapp.utils.StringUtils;
import edu.cornell.mannlib.vitro.webapp.web.BreadCrumbsUtil;
import edu.cornell.mannlib.vitro.webapp.web.ContentType;
import edu.cornell.mannlib.vitro.webapp.web.PortalWebUtil;
import edu.cornell.mannlib.vitro.webapp.web.templatemodels.User;
import edu.cornell.mannlib.vitro.webapp.web.templatemodels.files.Scripts;
import edu.cornell.mannlib.vitro.webapp.web.templatemodels.files.Stylesheets;
import edu.cornell.mannlib.vitro.webapp.web.templatemodels.menu.TabMenu;
@ -45,7 +46,7 @@ public class FreemarkerHttpServlet extends VitroHttpServlet {
private static final long serialVersionUID = 1L;
private static final Log log = LogFactory.getLog(FreemarkerHttpServlet.class);
private static final int FILTER_SECURITY_LEVEL = LoginStatusBean.EDITOR;
public static final String PAGE_TEMPLATE_TYPE = "page";
public static final String BODY_TEMPLATE_TYPE = "body";
@ -108,7 +109,7 @@ public class FreemarkerHttpServlet extends VitroHttpServlet {
}
private boolean requiredLoginLevelNotFound(HttpServletRequest request, HttpServletResponse response) {
int requiredLoginLevel = requiresLoginLevel();
int requiredLoginLevel = requiredLoginLevel();
// checkLoginStatus() does a redirect if the user is not logged in.
if (requiredLoginLevel > LoginStatusBean.ANYBODY && !checkLoginStatus(request, response, requiredLoginLevel)) {
return true;
@ -116,11 +117,7 @@ public class FreemarkerHttpServlet extends VitroHttpServlet {
return false;
}
protected boolean requiresLogin() {
return false;
}
protected int requiresLoginLevel() {
protected int requiredLoginLevel() {
// By default, user does not need to be logged in to view pages.
// Subclasses that require login to process their page will override to return the required login level.
// NB This method can't be static, because then the superclass method gets called rather than
@ -382,7 +379,7 @@ public class FreemarkerHttpServlet extends VitroHttpServlet {
PortalWebUtil.populateSearchOptions(portal, appBean, vreq.getWebappDaoFactory().getPortalDao());
PortalWebUtil.populateNavigationChoices(portal, vreq, appBean, vreq.getWebappDaoFactory().getPortalDao());
map.putAll(getLoginValues(vreq));
map.put("user", new User(vreq));
UrlBuilder urlBuilder = new UrlBuilder(portal);
map.put("version", getRevisionInfo(urlBuilder));
@ -409,30 +406,11 @@ public class FreemarkerHttpServlet extends VitroHttpServlet {
return map;
}
private TabMenu getTabMenu(VitroRequest vreq) {
int portalId = vreq.getPortal().getPortalId();
return new TabMenu(vreq, portalId);
}
private final Map<String, Object> getLoginValues(VitroRequest vreq) {
Map<String, Object> map = new HashMap<String, Object>();
LoginStatusBean loginBean = LoginStatusBean.getBean(vreq);
if (loginBean.isLoggedIn()) {
map.put("loginName", loginBean.getUsername());
if (loginBean.isLoggedInAtLeast(FILTER_SECURITY_LEVEL)) {
ApplicationBean appBean = vreq.getAppBean();
if (appBean.isFlag1Active()) {
map.put("showFlag1SearchField", true);
}
}
}
return map;
}
private final Map<String, Object> getCopyrightInfo(Portal portal) {
Map<String, Object> copyright = null;

View file

@ -52,7 +52,7 @@ import edu.cornell.mannlib.vitro.webapp.utils.NamespaceMapper;
import edu.cornell.mannlib.vitro.webapp.utils.NamespaceMapperFactory;
import edu.cornell.mannlib.vitro.webapp.web.ContentType;
import edu.cornell.mannlib.vitro.webapp.web.jsptags.StringProcessorTag;
import edu.cornell.mannlib.vitro.webapp.web.templatemodels.IndividualTemplateModel;
import edu.cornell.mannlib.vitro.webapp.web.templatemodels.individual.IndividualTemplateModel;
/**
* Handles requests for entity information.

View file

@ -16,7 +16,7 @@ import edu.cornell.mannlib.vitro.webapp.beans.VClassGroup;
import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest;
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.FreemarkerHttpServlet.ResponseValues;
import edu.cornell.mannlib.vitro.webapp.utils.StringUtils;
import edu.cornell.mannlib.vitro.webapp.web.templatemodels.IndividualTemplateModel;
import edu.cornell.mannlib.vitro.webapp.web.templatemodels.individual.IndividualTemplateModel;
import freemarker.template.Configuration;
/**

View file

@ -19,10 +19,20 @@ public class RevisionInfoController extends FreemarkerHttpServlet {
private static final long serialVersionUID = 1L;
private static final Log log = LogFactory.getLog(RevisionInfoController.class);
private static final String TEMPLATE_DEFAULT = "revisionInfo.ftl";
private static final int REQUIRED_LOGIN_LEVEL = LoginStatusBean.EDITOR;
/* requiredLoginLevel() must be an instance method, else, due to the way sublcass
* hiding works, when called from FreemarkerHttpServlet we will get its own method,
* rather than the subclass method. To figure out whether to display links at the
* page level, we need another, static method.
*/
public static int staticRequiredLoginLevel() {
return REQUIRED_LOGIN_LEVEL;
}
@Override
protected int requiresLoginLevel() {
return LoginStatusBean.EDITOR;
protected int requiredLoginLevel() {
return REQUIRED_LOGIN_LEVEL;
}
@Override

View file

@ -28,16 +28,25 @@ public class SiteAdminController extends FreemarkerHttpServlet {
private static final long serialVersionUID = 1L;
private static final Log log = LogFactory.getLog(SiteAdminController.class);
private static final String TEMPLATE_DEFAULT = "siteAdmin-main.ftl";
private static final int REQUIRED_LOGIN_LEVEL = LoginStatusBean.EDITOR;
@Override
public String getTitle(String siteName) {
return siteName + " Site Administration";
}
/* requiredLoginLevel() must be an instance method, else, due to the way sublcass
* hiding works, when called from FreemarkerHttpServlet we will get its own method,
* rather than the subclass method. To figure out whether to display links at the
* page level, we need another, static method.
*/
public static int staticRequiredLoginLevel() {
return REQUIRED_LOGIN_LEVEL;
}
@Override
protected int requiresLoginLevel() {
// User must be logged in to view this page.
return LoginStatusBean.EDITOR;
protected int requiredLoginLevel() {
return REQUIRED_LOGIN_LEVEL;
}
@Override

View file

@ -38,6 +38,7 @@ public class TestController extends FreemarkerHttpServlet {
body.put("title", "Freemarker Test");
return new TemplateResponseValues(TEMPLATE_DEFAULT, body);
}
@Override

View file

@ -72,8 +72,8 @@ import edu.cornell.mannlib.vitro.webapp.search.lucene.SimpleLuceneHighlighter;
import edu.cornell.mannlib.vitro.webapp.utils.FlagMathUtils;
import edu.cornell.mannlib.vitro.webapp.utils.Html2Text;
import edu.cornell.mannlib.vitro.webapp.utils.StringUtils;
import edu.cornell.mannlib.vitro.webapp.web.templatemodels.IndividualTemplateModel;
import edu.cornell.mannlib.vitro.webapp.web.templatemodels.LinkTemplateModel;
import edu.cornell.mannlib.vitro.webapp.web.templatemodels.individual.IndividualTemplateModel;
/**
* PagedSearchController is the new search controller that interacts

View file

@ -0,0 +1,71 @@
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
package edu.cornell.mannlib.vitro.webapp.web.templatemodels;
import java.util.HashMap;
import java.util.Map;
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.beans.ApplicationBean;
import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest;
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.RevisionInfoController;
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.SiteAdminController;
public class User extends BaseTemplateModel {
private static final Log log = LogFactory.getLog(User.class);
private enum Access {
SITE_ADMIN(SiteAdminController.staticRequiredLoginLevel()),
REVISION_INFO(RevisionInfoController.staticRequiredLoginLevel()),
FILTER_SECURITY(LoginStatusBean.EDITOR);
private final int requiredLoginLevel;
Access(int requiredLoginLevel) {
this.requiredLoginLevel = requiredLoginLevel;
}
int requiredLoginLevel() {
return this.requiredLoginLevel;
}
}
private LoginStatusBean loginBean = null;
private VitroRequest vreq = null;
public User(VitroRequest vreq) {
this.vreq = vreq;
loginBean = LoginStatusBean.getBean(vreq);
}
public boolean isLoggedIn() {
return loginBean.isLoggedIn();
}
public String getLoginName() {
return loginBean.getUsername();
}
public boolean getHasSiteAdminAccess() {
return loginBean.isLoggedInAtLeast(Access.SITE_ADMIN.requiredLoginLevel());
}
public boolean getHasRevisionInfoAccess() {
return loginBean.isLoggedInAtLeast(Access.REVISION_INFO.requiredLoginLevel());
}
public boolean getShowFlag1SearchField() {
boolean showFlag1SearchField = false;
if (loginBean.isLoggedInAtLeast(Access.FILTER_SECURITY.requiredLoginLevel)) {
ApplicationBean appBean = vreq.getAppBean();
if (appBean.isFlag1Active()) {
showFlag1SearchField = true;
}
}
return showFlag1SearchField;
}
}

View file

@ -1,6 +1,6 @@
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
package edu.cornell.mannlib.vitro.webapp.web.templatemodels;
package edu.cornell.mannlib.vitro.webapp.web.templatemodels.individual;
import java.util.ArrayList;
import java.util.List;
@ -19,6 +19,7 @@ import edu.cornell.mannlib.vitro.webapp.controller.freemarker.UrlBuilder.Route;
import edu.cornell.mannlib.vitro.webapp.dao.WebappDaoFactory;
import edu.cornell.mannlib.vitro.webapp.web.ViewFinder;
import edu.cornell.mannlib.vitro.webapp.web.ViewFinder.ClassView;
import edu.cornell.mannlib.vitro.webapp.web.templatemodels.BaseTemplateModel;
public class IndividualTemplateModel extends BaseTemplateModel {
@ -30,13 +31,6 @@ public class IndividualTemplateModel extends BaseTemplateModel {
protected VitroRequest vreq;
protected UrlBuilder urlBuilder;
// private PropertyListTemplateModel propertyList;
// RY The IndividualTemplateModel object needs access to the request object.
// The only other template model that does is MainMenu. We could provide an
// interface for RequestAware template models, but they still wouldn't share any code.
// If they both derive from a common RequestAwareTemplateModel class, we might be
// locking ourselves in too tightly to that class hierarchy.
public IndividualTemplateModel(Individual individual, VitroRequest vreq) {
this.individual = individual;
this.vreq = vreq;
@ -150,6 +144,19 @@ public class IndividualTemplateModel extends BaseTemplateModel {
return links;
}
public static List<IndividualTemplateModel> getIndividualTemplateModelList(List<Individual> individuals, VitroRequest vreq) {
List<IndividualTemplateModel> models = new ArrayList<IndividualTemplateModel>(individuals.size());
for (Individual individual : individuals) {
models.add(new IndividualTemplateModel(individual, vreq));
}
return models;
}
public List<Object> getPropertyList() {
PropertyListBuilder propListBuilder = new PropertyListBuilder(individual, vreq);
return propListBuilder.getPropertyList();
}
/* These methods simply forward to the Individual methods. It would be desirable to implement a scheme
for proxying or delegation so that the methods don't need to be simply listed here.
A Ruby-style method missing method would be ideal.
@ -189,19 +196,6 @@ public class IndividualTemplateModel extends BaseTemplateModel {
return individual.getLocalName();
}
public static List<IndividualTemplateModel> getIndividualTemplateModelList(List<Individual> individuals, VitroRequest vreq) {
List<IndividualTemplateModel> models = new ArrayList<IndividualTemplateModel>(individuals.size());
for (Individual individual : individuals) {
models.add(new IndividualTemplateModel(individual, vreq));
}
return models;
}
private boolean isExternallyLinkedNamespace(String namespace,List<String> externallyLinkedNamespaces) {
return externallyLinkedNamespaces.contains(namespace);
}
// public Map< > getPropertyList
// public Map< > getPropertyGroupList
}

View file

@ -0,0 +1,83 @@
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
package edu.cornell.mannlib.vitro.webapp.web.templatemodels.individual;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
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.beans.Individual;
import edu.cornell.mannlib.vitro.webapp.beans.ObjectProperty;
import edu.cornell.mannlib.vitro.webapp.beans.Property;
import edu.cornell.mannlib.vitro.webapp.beans.PropertyGroup;
import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest;
import edu.cornell.mannlib.vitro.webapp.dao.PropertyGroupDao;
import edu.cornell.mannlib.vitro.webapp.dao.VitroVocabulary;
import edu.cornell.mannlib.vitro.webapp.dao.WebappDaoFactory;
import edu.cornell.mannlib.vitro.webapp.filters.VitroRequestPrep;
public class PropertyListBuilder {
private static final Log log = LogFactory.getLog(PropertyListBuilder.class);
private static final int MAX_GROUP_DISPLAY_RANK = 99;
// Don't include these properties in the list.
private static final Collection<String> SUPPRESSED_OBJECT_PROPERTIES = Collections
.unmodifiableCollection(Arrays
.asList(new String[] { VitroVocabulary.IND_MAIN_IMAGE }));
protected Individual subject;
protected VitroRequest vreq;
PropertyListBuilder(Individual individual, VitroRequest vreq) {
this.subject = individual;
this.vreq = vreq;
}
protected List<Object> getPropertyList() {
// Determine whether we're editing or not.
// These tests may change once self-editing issues are straightened out.
boolean isSelfEditing = VitroRequestPrep.isSelfEditing(vreq);
boolean isCurator = LoginStatusBean.getBean(vreq).isLoggedInAtLeast(LoginStatusBean.CURATOR);
boolean isEditing = isSelfEditing || isCurator;
// Determine whether to return a grouped or ungrouped property list.
// If the call specified ungrouped, use ungrouped.
// If the call specified grouped:
WebappDaoFactory wdf = vreq.getWebappDaoFactory();
PropertyGroupDao pgDao = wdf.getPropertyGroupDao();
List <PropertyGroup> groupsList = pgDao.getPublicGroups(false); // may be returned empty but not null
// Use ungrouped if no property groups are defined
// If < 2 property groups are populated, we also want ungrouped, but we won't know that until we
// get the property list.
// Assemble the property list
List<Property> mergedPropertyList = new ArrayList<Property>();
// First get the properties this entity actually has, presumably populated with statements
List<ObjectProperty> objectPropertyList = subject.getObjectPropertyList();
for (ObjectProperty op : objectPropertyList) {
if (!SUPPRESSED_OBJECT_PROPERTIES.contains(op)) {
op.setEditLabel(op.getDomainPublic());
mergedPropertyList.add(op);
}else{
log.debug("suppressed " + op.getURI());
}
}
// If < 2 property groups populated, we want ungrouped.
// This can just be handled by not including a group, or using an "empty" group with no name.
return null;
}
}

View file

@ -2,8 +2,6 @@
<#-- Template for property listing on individual profile page -->
<#if individual.propertyGroups??>
<#elseif individual.properties??>
</#if>
<#--
<#assign properties = individual.propertyList>
-->

View file

@ -12,11 +12,13 @@
<ul id="otherMenu">
<@l.firstLastList>
<#if loginName??>
<#if user.loggedIn>
<li>
Logged in as <strong>${loginName}</strong> (<a href="${urls.logout}">Log out</a>)
Logged in as <strong>${user.loginName}</strong> (<a href="${urls.logout}">Log out</a>)
</li>
<li><a href="${urls.siteAdmin}">Site Admin</a></li>
<#if user.hasSiteAdminAccess>
<li><a href="${urls.siteAdmin}">Site Admin</a></li>
</#if>
<#else>
<li><a title="log in to manage this site" href="${urls.login}">Log in</a></li>
</#if>

View file

@ -4,9 +4,9 @@
<form id="searchForm" action="${urls.search}" >
<label for="search">Search </label>
<#if showFlag1SearchField??>
<#if user.showFlag1SearchField>
<select id="search-form-modifier" name="flag1" class="form-item" >
<option value="nofiltering" selected="selected">entire database (${loginName})</option>
<option value="nofiltering" selected="selected">entire database (${user.loginName})</option>
<option value="${portalId}">${siteTagline!}</option>
</select>
<#else>

View file

@ -2,9 +2,9 @@
<#-- Template for version/revision information -->
<#-- Only show version info if user is logged in -->
<#if loginName??>
<div id="version">
<#-- Only show version info if user has access -->
<#if user.hasRevisionInfoAccess>
<div id="revision">
Version <a href="${version.moreInfoUrl}">${version.label}</a>
</div>
</#if>

View file

@ -3,9 +3,9 @@
<#-- Login widget -->
<#macro assets>
<#-- 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> -->
<#-- RY This test should be replaced by widget controller logic which doesn't display any assets if the user is logged in.
See NIHVIVO-1357. This test does nothing, since user has not been put into the data model.
<#if ! user.loggedIn> -->
${stylesheets.add("/css/login.css")}
${scripts.add("/js/jquery.js", "/js/login/loginUtils.js")}
<#-- ${headScripts.add("")} -->