diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/auth/identifier/common/AbstractCommonIdentifier.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/auth/identifier/common/AbstractCommonIdentifier.java index 969131c20..5b7d95948 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/auth/identifier/common/AbstractCommonIdentifier.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/auth/identifier/common/AbstractCommonIdentifier.java @@ -3,6 +3,7 @@ package edu.cornell.mannlib.vitro.webapp.auth.identifier.common; import java.util.Collection; +import java.util.Collections; import java.util.HashSet; import java.util.Set; @@ -14,8 +15,16 @@ import edu.cornell.mannlib.vitro.webapp.auth.identifier.IdentifierBundle; * CommonIdentifierBundleFactory. */ public abstract class AbstractCommonIdentifier { - protected static Collection getIdentifiersForClass( + + /** + * Get all of the instances of this class of Identifier from this bundle. + */ + protected static Collection getIdentifiersForClass( IdentifierBundle ids, Class clazz) { + if ((ids == null) || (clazz == null)) { + return Collections.emptySet(); + } + Set set = new HashSet(); for (Identifier id : ids) { if (clazz.isAssignableFrom(id.getClass())) { diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/auth/policy/DisplayRestrictedDataToSelfPolicy.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/auth/policy/DisplayRestrictedDataToSelfPolicy.java index 4c20c3a84..e1af1c68b 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/auth/policy/DisplayRestrictedDataToSelfPolicy.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/auth/policy/DisplayRestrictedDataToSelfPolicy.java @@ -11,7 +11,6 @@ import org.apache.commons.logging.LogFactory; import edu.cornell.mannlib.vitro.webapp.auth.identifier.IdentifierBundle; import edu.cornell.mannlib.vitro.webapp.auth.identifier.common.HasAssociatedIndividual; -import edu.cornell.mannlib.vitro.webapp.auth.identifier.common.HasRoleLevel; import edu.cornell.mannlib.vitro.webapp.auth.policy.bean.PropertyRestrictionPolicyHelper; import edu.cornell.mannlib.vitro.webapp.auth.policy.ifaces.Authorization; import edu.cornell.mannlib.vitro.webapp.auth.policy.ifaces.PolicyDecision; @@ -57,11 +56,6 @@ public class DisplayRestrictedDataToSelfPolicy implements PolicyIface { return defaultDecision("whatToAuth was null"); } - RoleLevel userRole = HasRoleLevel.getUsersRoleLevel(whoToAuth); - if (userRole != RoleLevel.SELF) { - return defaultDecision("not a self-editor"); - } - Collection associated = HasAssociatedIndividual .getIndividualUris(whoToAuth); if (associated.isEmpty()) { diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/auth/policy/Ids2QueryBindings.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/auth/policy/Ids2QueryBindings.java deleted file mode 100644 index 8cd2767d5..000000000 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/auth/policy/Ids2QueryBindings.java +++ /dev/null @@ -1,18 +0,0 @@ -/* $This file is distributed under the terms of the license in /doc/license.txt$ */ - -package edu.cornell.mannlib.vitro.webapp.auth.policy; - -import java.util.List; - -import com.hp.hpl.jena.query.QuerySolutionMap; - -import edu.cornell.mannlib.vitro.webapp.auth.identifier.IdentifierBundle; -import edu.cornell.mannlib.vitro.webapp.auth.requestedAction.ifaces.RequestedAction; - -public interface Ids2QueryBindings { - /** - * Returns null if no binding can be made. In some implementations this - * might be different than an empty QuerySolutionMap. Must be thread safe. - */ - public List makeScopeBinding(IdentifierBundle ids, RequestedAction action ); -} diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/reasoner/SimpleReasoner.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/reasoner/SimpleReasoner.java index 77dccea48..62e0bec77 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/reasoner/SimpleReasoner.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/reasoner/SimpleReasoner.java @@ -76,6 +76,8 @@ public class SimpleReasoner extends StatementListener { } /** + * This constructor is used for the unit tests only + * * @param tboxModel - input. This model contains both asserted and inferred TBox axioms * @param aboxModel - input. This model contains asserted ABox statements * @param inferenceModel - output. This is the model in which inferred (materialized) ABox statements are maintained (added or retracted). @@ -157,9 +159,28 @@ public class SimpleReasoner extends StatementListener { if (stmt.getSubject().isAnon() || stmt.getObject().isAnon()) { return; } - + + if ( stmt.getObject().isResource() && (stmt.getObject().asResource()).getURI() == null ) { + log.warn("The object of this assertion has a null URI: " + stmtString(stmt)); + return; + } + + if ( stmt.getSubject().getURI() == null ) { + log.warn("The subject of this assertion has a null URI: " + stmtString(stmt)); + return; + } + OntClass subject = tboxModel.getOntClass((stmt.getSubject()).getURI()); + if (subject == null) { + log.debug("didn't find subject class in the tbox: " + (stmt.getSubject()).getURI()); + return; + } + OntClass object = tboxModel.getOntClass(((Resource)stmt.getObject()).getURI()); + if (object == null) { + log.debug("didn't find object class in the tbox: " + ((Resource)stmt.getObject()).getURI()); + return; + } if (stmt.getPredicate().equals(RDFS.subClassOf)) { addedSubClass(subject,object,inferenceModel); @@ -207,9 +228,28 @@ public class SimpleReasoner extends StatementListener { if (stmt.getSubject().isAnon() || stmt.getObject().isAnon()) { return; } - + + if ( stmt.getObject().isResource() && (stmt.getObject().asResource()).getURI() == null ) { + log.warn("The object of this assertion has a null URI: " + stmtString(stmt)); + return; + } + + if ( stmt.getSubject().getURI() == null ) { + log.warn("The subject of this assertion has a null URI: " + stmtString(stmt)); + return; + } + OntClass subject = tboxModel.getOntClass((stmt.getSubject()).getURI()); + if (subject == null) { + log.debug("didn't find subject class in the tbox: " + (stmt.getSubject()).getURI()); + return; + } + OntClass object = tboxModel.getOntClass(((Resource)stmt.getObject()).getURI()); + if (object == null) { + log.debug("didn't find object class in the tbox: " + ((Resource)stmt.getObject()).getURI()); + return; + } if (stmt.getPredicate().equals(RDFS.subClassOf)) { removedSubClass(subject,object,inferenceModel); @@ -253,36 +293,44 @@ public class SimpleReasoner extends StatementListener { tboxModel.enterCriticalSection(Lock.READ); try { - OntClass cls = tboxModel.getOntClass(((Resource)stmt.getObject()).getURI()); + + OntClass cls = null; - if (cls != null) { - - List parents = (cls.listSuperClasses(false)).toList(); - parents.addAll((cls.listEquivalentClasses()).toList()); - Iterator parentIt = parents.iterator(); - - while (parentIt.hasNext()) { - OntClass parentClass = parentIt.next(); + if ( (stmt.getObject().asResource()).getURI() != null ) { + cls = tboxModel.getOntClass(stmt.getObject().asResource().getURI()); + + if (cls != null) { - // VIVO doesn't materialize statements that assert anonymous types - // for individuals. Also, sharing an identical anonymous node is - // not allowed in owl-dl. picklist population code looks at qualities - // of classes not individuals. - if (parentClass.isAnon()) continue; + List parents = (cls.listSuperClasses(false)).toList(); + parents.addAll((cls.listEquivalentClasses()).toList()); + Iterator parentIt = parents.iterator(); - Statement infStmt = ResourceFactory.createStatement(stmt.getSubject(), RDF.type, parentClass); - inferenceModel.enterCriticalSection(Lock.WRITE); - try { - if (!inferenceModel.contains(infStmt) && !infStmt.equals(stmt) ) { - //log.debug("Adding this inferred statement: " + infStmt.toString() ); - inferenceModel.add(infStmt); - } - } finally { - inferenceModel.leaveCriticalSection(); - } + while (parentIt.hasNext()) { + OntClass parentClass = parentIt.next(); + + // VIVO doesn't materialize statements that assert anonymous types + // for individuals. Also, sharing an identical anonymous node is + // not allowed in owl-dl. picklist population code looks at qualities + // of classes not individuals. + if (parentClass.isAnon()) continue; + + Statement infStmt = ResourceFactory.createStatement(stmt.getSubject(), RDF.type, parentClass); + inferenceModel.enterCriticalSection(Lock.WRITE); + try { + if (!inferenceModel.contains(infStmt) && !infStmt.equals(stmt) ) { + //log.debug("Adding this inferred statement: " + infStmt.toString() ); + inferenceModel.add(infStmt); + } + } finally { + inferenceModel.leaveCriticalSection(); + } + } + } else { + log.debug("Didn't find target class (the object of the added rdf:type statement) in the TBox: " + ((Resource)stmt.getObject()).getURI()); } } else { - log.debug("Didn't find target class (the object of the added rdf:type statement) in the TBox: " + ((Resource)stmt.getObject()).getURI()); + log.warn("The object of this rdf:type assertion has a null URI: " + stmtString(stmt)); + return; } } finally { tboxModel.leaveCriticalSection(); @@ -340,7 +388,7 @@ public class SimpleReasoner extends StatementListener { } } } else { - log.warn("Didn't find target property (the predicate of the added statement) in the TBox: " + stmt.getPredicate().getURI()); + log.debug("Didn't find target property (the predicate of the added statement) in the TBox: " + stmt.getPredicate().getURI()); } } finally { tboxModel.leaveCriticalSection(); @@ -359,43 +407,53 @@ public class SimpleReasoner extends StatementListener { tboxModel.enterCriticalSection(Lock.READ); + // convert this method to use generic resources - not get ontclass, not cls.listSuperClasses... + // use model contains if want to log warning about type owl class + try { - OntClass cls = tboxModel.getOntClass(((Resource)stmt.getObject()).getURI()); - if (cls != null) { - - List parents = (cls.listSuperClasses(false)).toList(); - parents.addAll((cls.listEquivalentClasses()).toList()); - Iterator parentIt = parents.iterator(); - - while (parentIt.hasNext()) { - OntClass parentClass = parentIt.next(); + OntClass cls = null; + + if ( (stmt.getObject().asResource()).getURI() != null ) { + cls = tboxModel.getOntClass(stmt.getObject().asResource().getURI()); + + if (cls != null) { - // VIVO doesn't materialize statements that assert anonymous types - // for individuals. Also, sharing an identical anonymous node is - // not allowed in owl-dl. picklist population code looks at qualities - // of classes not individuals. - if (parentClass.isAnon()) continue; + List parents = (cls.listSuperClasses(false)).toList(); + parents.addAll((cls.listEquivalentClasses()).toList()); + Iterator parentIt = parents.iterator(); - if (entailedType(stmt.getSubject(),parentClass)) continue; // if a type is still entailed without the - // removed statement, then don't remove it - // from the inferences - - Statement infStmt = ResourceFactory.createStatement(stmt.getSubject(), RDF.type, parentClass); + while (parentIt.hasNext()) { + OntClass parentClass = parentIt.next(); - inferenceModel.enterCriticalSection(Lock.WRITE); - try { - if (inferenceModel.contains(infStmt)) { - //log.debug("Removing this inferred statement: " + infStmt.toString() + " - " + infStmt.getSubject().toString() + " - " + infStmt.getPredicate().toString() + " - " + infStmt.getObject().toString()); - inferenceModel.remove(infStmt); - } - } finally { - inferenceModel.leaveCriticalSection(); - } + // VIVO doesn't materialize statements that assert anonymous types + // for individuals. Also, sharing an identical anonymous node is + // not allowed in owl-dl. picklist population code looks at qualities + // of classes not individuals. + if (parentClass.isAnon()) continue; + + if (entailedType(stmt.getSubject(),parentClass)) continue; // if a type is still entailed without the + // removed statement, then don't remove it + // from the inferences + + Statement infStmt = ResourceFactory.createStatement(stmt.getSubject(), RDF.type, parentClass); + + inferenceModel.enterCriticalSection(Lock.WRITE); + try { + if (inferenceModel.contains(infStmt)) { + //log.debug("Removing this inferred statement: " + infStmt.toString() + " - " + infStmt.getSubject().toString() + " - " + infStmt.getPredicate().toString() + " - " + infStmt.getObject().toString()); + inferenceModel.remove(infStmt); + } + } finally { + inferenceModel.leaveCriticalSection(); + } + } + } else { + log.debug("Didn't find target class (the object of the removed rdf:type statement) in the TBox: " + ((Resource)stmt.getObject()).getURI()); } } else { - log.debug("Didn't find target class (the object of the removed rdf:type statement) in the TBox: " + ((Resource)stmt.getObject()).getURI()); - } + log.warn("The object of this rdf:type assertion has a null URI: " + stmtString(stmt)); + } } finally { tboxModel.leaveCriticalSection(); } @@ -700,16 +758,23 @@ public class SimpleReasoner extends StatementListener { continue; } - OntClass ontClass = tboxModel.getOntClass(stmt.getObject().asResource().getURI()); + OntClass ontClass = null; + if ( (stmt.getObject().asResource()).getURI() != null ) { + ontClass = tboxModel.getOntClass(stmt.getObject().asResource().getURI()); + } else { + log.warn("The object of this rdf:type assertion has a null URI: " + stmtString(stmt)); + continue; + } + if (ontClass == null) { - log.warn("Didn't find target class (the object of the added rdf:type statement) in the TBox: " + (stmt.getObject().asResource()).getURI()); + log.debug("Didn't find target class (the object of the added rdf:type statement) in the TBox: " + (stmt.getObject().asResource()).getURI()); continue; } if (ontClass.isAnon()) continue; - types.add(ontClass); + types.add(ontClass); } HashSet typeURIs = new HashSet(); diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/utils/TitleCase.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/utils/TitleCase.java index 9a82ef919..16db7e8de 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/utils/TitleCase.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/utils/TitleCase.java @@ -17,8 +17,12 @@ presents some admirably clear rules for capitalizing titles: (1) a, an, and the, (2) two and three letter conjunctions (and, or, nor, for, but, so, yet), (3) prepositions. - Exceptions: The first and last words are always capitalized even - if they are among the above three groups. + Exceptions: The first word is always capitalized even + if it is among the above three groups. For the last word, we can specify the + option to always capitalize it or to treat it like a medial word. The original + method always capitalized the final word, so to support the old method calls + we have defined another method to provide this as default behavior. + But consider the case: "It Waits Underneath the Sea" @@ -34,14 +38,19 @@ The default entries on the exception list are: to of by at for but in with has de von The observant may note that the last row is not composed of English words. The honorary -"de" has been included in honor of "Honoré de Balzac". And "von" was added for the sake +"de" has been included in honor of "Honore' de Balzac". And "von" was added for the sake of equal time. */ public class TitleCase { static String ignore[] = {"a","an","the","and","or","nor","for","but","so","yet", "to","of","by","at","for","but","in","with","has","de","von"}; + + public static String toTitleCase(String in) { + // Support old behavior without modifying method calls + return toTitleCase(in, true); + } - public static String toTitleCase(String in){ + public static String toTitleCase(String in, boolean alwaysCapitalizeLast){ if( in == null || in.length() ==0 ) return in; @@ -55,9 +64,12 @@ public class TitleCase { while(st.hasMoreTokens()){ String token = st.nextToken(); - //always capatize first and last - if( count == 1 || count == last ){ + // always capitalize first + if ( count == 1 || + // always capitalize last, unless we've asked not to + ( alwaysCapitalizeLast && count == last ) ) { out.append(capitalizeWord(token)); + } else { //check if on ignored list diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/web/templatemodels/User.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/web/templatemodels/User.java index 5b9a217d7..80c22699c 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/web/templatemodels/User.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/web/templatemodels/User.java @@ -2,24 +2,47 @@ package edu.cornell.mannlib.vitro.webapp.web.templatemodels; +import java.util.Collection; + import edu.cornell.mannlib.vedit.beans.LoginStatusBean; +import edu.cornell.mannlib.vitro.webapp.auth.identifier.IdentifierBundle; +import edu.cornell.mannlib.vitro.webapp.auth.identifier.RequestIdentifiers; +import edu.cornell.mannlib.vitro.webapp.auth.identifier.common.HasAssociatedIndividual; import edu.cornell.mannlib.vitro.webapp.auth.policy.PolicyHelper; import edu.cornell.mannlib.vitro.webapp.beans.UserAccount; 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; +import edu.cornell.mannlib.vitro.webapp.controller.freemarker.UrlBuilder; public class User extends BaseTemplateModel { private final VitroRequest vreq; - private final UserAccount currentUser; + private final String profileUrl; public User(VitroRequest vreq) { this.vreq = vreq; this.currentUser = LoginStatusBean.getCurrentUser(vreq); + this.profileUrl = figureAssociatedProfileUrl(); } - public boolean isLoggedIn() { + private String figureAssociatedProfileUrl() { + IdentifierBundle ids = RequestIdentifiers.getIdBundleForRequest(vreq); + Collection uris = HasAssociatedIndividual.getIndividualUris(ids); + if (uris.isEmpty()) { + return ""; + } + + String uri = uris.iterator().next(); + String url = UrlBuilder.getIndividualProfileUrl(uri, vreq); + if (url == null) { + return ""; + } + + return url; + } + + public boolean isLoggedIn() { return currentUser != null; } @@ -63,4 +86,11 @@ public class User extends BaseTemplateModel { return PolicyHelper.isAuthorizedForActions(vreq, RevisionInfoController.REQUIRED_ACTIONS); } + public boolean getHasProfile() { + return !profileUrl.isEmpty(); + } + + public String getProfileUrl() { + return profileUrl; + } } diff --git a/webapp/web/css/individual/individual.css b/webapp/web/css/individual/individual.css index 4e890b093..7d76641b4 100644 --- a/webapp/web/css/individual/individual.css +++ b/webapp/web/css/individual/individual.css @@ -4,7 +4,6 @@ #admin { font-size: .8em; padding-top: 0; - padding-right: 40px; } #admin h3 { display: inline-block; @@ -210,7 +209,7 @@ h1.fn .preferred-title { } /* <------ INDIVIDUAL VISUALIZATION */ #visualization { - padding: 0 0 20px 30px; + padding: 0 0 20px 20px; padding-top: 0; float: right; background-color: #fff; diff --git a/webapp/web/css/login.css b/webapp/web/css/login.css index d7d51f07a..04f6e3d42 100644 --- a/webapp/web/css/login.css +++ b/webapp/web/css/login.css @@ -22,6 +22,9 @@ margin-top: 13px; margin-left: 20px; } +#newPassword { + margin-bottom: 0; +} #login-form .label-remember-me { display: block; float: left; @@ -71,10 +74,9 @@ h3.internal-auth { p.password-note { margin: 0; padding: 0; - margin-top: -8px; font-size: 0.8em; color: #615e5e; - padding-top: 15px; + padding-top: 3px; } .or { display: inline; diff --git a/webapp/web/images/iconConfirmation.png b/webapp/web/images/iconConfirmation.png index a3993988a..1f17fb10b 100644 Binary files a/webapp/web/images/iconConfirmation.png and b/webapp/web/images/iconConfirmation.png differ diff --git a/webapp/web/templates/freemarker/body/accounts/userAccounts-myAccount.ftl b/webapp/web/templates/freemarker/body/accounts/userAccounts-myAccount.ftl index 3067e43f6..cbee71553 100644 --- a/webapp/web/templates/freemarker/body/accounts/userAccounts-myAccount.ftl +++ b/webapp/web/templates/freemarker/body/accounts/userAccounts-myAccount.ftl @@ -52,9 +52,8 @@ <#if confirmMessage?has_content> -