Skip to content

Commit b542811

Browse files
committed
Merge branch 'develop' into 2579-DDI-export
2 parents 0d8f741 + 313317a commit b542811

28 files changed

Lines changed: 685 additions & 347 deletions

src/main/java/Bundle.properties

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -185,8 +185,8 @@ user.updatePassword.password=Create a password that is minimum six characters lo
185185
authenticationProvidersAvailable.tip={0}There are no active authentication providers{1}If you are a system administrator, please enable one using the API.{2}If you are not a system administrator, please contact the one for your institution.
186186
login.System=Login System
187187
login.forgot.text=Forgot your password?
188-
login.builtin=Dataverse Account Log In
189-
login.institution=Institutional Log In
188+
login.builtin=Dataverse Account
189+
login.institution=Institutional Account
190190
login.institution.blurb=Use Dataverse with your institutional log in instead of creating an account. <a href="{0}/{1}/user/account.html" target="_blank">Learn More</a>.
191191
login.institution.support.beforeLink=Leaving your institution? Please contact
192192
login.institution.support.afterLink=for assistance.
@@ -748,6 +748,10 @@ dataset.manageGuestbooks.guestbook.name.tip=Enter a unique name for this Guestbo
748748
dataset.manageGuestbooks.guestbook.dataCollected=Data Collected
749749
dataset.manageGuestbooks.guestbook.dataCollected.description=Dataverse account information that will be collected when a user downloads a file. Check the ones that will be required.
750750
dataset.manageGuestbooks.guestbook.customQuestions=Custom Questions
751+
dataset.manageGuestbooks.guestbook.requiredCustomQuestions=Required Custom Questions
752+
dataset.manageGuestbooks.guestbook.optionalCustomQuestions=Optional Custom Questions
753+
dataset.manageGuestbooks.guestbook.requiredAccountInformation=Required Account Information
754+
dataset.manageGuestbooks.guestbook.optionalAccountInformation=Optional Account Information
751755
dataset.manageGuestbooks.guestbook.customQuestions.description=Create your own questions to have users provide more than their account information when they download a file. Questions can be required or optional and answers can be text or multiple choice.
752756
dataset.manageGuestbooks.guestbook.customQuestions.questionType=Question Type
753757
dataset.manageGuestbooks.guestbook.customQuestions.questionText=Question Text

src/main/java/edu/harvard/iq/dataverse/DataverseHeaderFragment.java

Lines changed: 27 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -106,12 +106,12 @@ public void initBreadcrumbs(DvObject dvObject, String subPage) {
106106
breadcrumbs.clear();
107107

108108
while (dvObject != null) {
109-
breadcrumbs.add(0, new Breadcrumb(dvObject.getDisplayName(), dvObject));
109+
breadcrumbs.add(0, new Breadcrumb(dvObject, dvObject.getDisplayName()));
110110
dvObject = dvObject.getOwner();
111111
}
112112

113113
if (subPage != null) {
114-
breadcrumbs.add(new Breadcrumb(subPage, null));
114+
breadcrumbs.add(new Breadcrumb(subPage));
115115
}
116116
}
117117

@@ -243,17 +243,34 @@ private static String getPageFromContext() {
243243
}
244244
return "";
245245
}
246+
247+
public void addBreadcrumb (String url, String linkString){
248+
breadcrumbs.add(new Breadcrumb(url, linkString));
249+
}
250+
251+
public void addBreadcrumb (String linkString){
252+
breadcrumbs.add(new Breadcrumb(linkString));
253+
}
246254

247255
// inner class used for breadcrumbs
248256
public static class Breadcrumb {
249257

250258
private final String breadcrumbText;
251-
private final DvObject dvObject;
259+
private DvObject dvObject = null;
260+
private String url = null;
252261

253-
public Breadcrumb(String breadcrumbText, DvObject dvObject) {
254-
this.breadcrumbText = breadcrumbText;
255-
this.dvObject = dvObject;
262+
public Breadcrumb( DvObject dvObject, String breadcrumbText) {
263+
this.breadcrumbText = breadcrumbText;
264+
this.dvObject = dvObject;
265+
}
256266

267+
public Breadcrumb( String url, String breadcrumbText) {
268+
this.breadcrumbText = breadcrumbText;
269+
this.url = url;
270+
}
271+
272+
public Breadcrumb(String breadcrumbText){
273+
this.breadcrumbText = breadcrumbText;
257274
}
258275

259276
public String getBreadcrumbText() {
@@ -264,6 +281,9 @@ public DvObject getDvObject() {
264281
return dvObject;
265282
}
266283

267-
284+
public String getUrl() {
285+
return url;
286+
}
287+
268288
}
269289
}

src/main/java/edu/harvard/iq/dataverse/EMailValidator.java

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -33,14 +33,7 @@ public static boolean isEmailValid(String value, ConstraintValidatorContext cont
3333
//we'll let someone else decide if it's required
3434
return true;
3535
}
36-
/**
37-
* @todo Why are we validating the trimmed value rather than the value
38-
* itself? Which are we persisting to the database, the trimmed value or
39-
* the non-trimmed value? See also
40-
* https://github.com/IQSS/dataverse/issues/2945 and
41-
* https://github.com/IQSS/dataverse/issues/3044
42-
*/
43-
boolean isValid = EmailValidator.getInstance().isValid(value.trim());
36+
boolean isValid = EmailValidator.getInstance().isValid(value);
4437
if (!isValid) {
4538
if (context != null) {
4639
context.buildConstraintViolationWithTemplate(value + " is not a valid email address.").addConstraintViolation();

src/main/java/edu/harvard/iq/dataverse/Guestbook.java

Lines changed: 42 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11

22
package edu.harvard.iq.dataverse;
33

4+
import edu.harvard.iq.dataverse.util.BundleUtil;
45
import java.io.Serializable;
56
import java.text.SimpleDateFormat;
67
import java.util.ArrayList;
@@ -19,6 +20,7 @@
1920
import javax.persistence.Temporal;
2021
import javax.persistence.TemporalType;
2122
import javax.persistence.Transient;
23+
import org.apache.commons.lang.StringEscapeUtils;
2224
import org.hibernate.validator.constraints.NotBlank;
2325

2426
/**
@@ -186,94 +188,63 @@ public boolean isDeletable() {
186188

187189
public void setDeletable(boolean deletable) {
188190
this.deletable = deletable;
189-
}
190-
191-
public String getRequiredCustomQuestionsString(){
192-
String retVal = "";
193-
for (CustomQuestion cq : this.getCustomQuestions()){
194-
if(cq.isRequired()){
195-
if(retVal.isEmpty()){
196-
retVal = "Required Custom Questions<br/>&#160; &#8226; " + cq.getQuestionString();
197-
} else {
198-
retVal += "<br/>&#160; &#8226; " + cq.getQuestionString();
199-
}
200-
}
201-
}
202-
return retVal;
203-
}
204-
205-
public String getOptionalCustomQuestionsString(){
206-
String retVal = "";
207-
for (CustomQuestion cq : this.getCustomQuestions()){
208-
if(!cq.isRequired()){
209-
if(retVal.isEmpty()){
210-
retVal = "Optional Custom Questions<br/>&#160; &#8226; " + cq.getQuestionString();
211-
} else {
212-
retVal += "<br/>&#160; &#8226; " + cq.getQuestionString();
213-
}
214-
}
215-
}
216-
return retVal;
217-
}
191+
}
218192

219-
public String getRequiredAccountInformationString(){
220-
String retVal = "";
221-
if(nameRequired){
222-
retVal = "Required Account Information<br/>&#160; &#8226; Name";
193+
public List<String> getRequiredAccountInformation() {
194+
List<String> retList = new ArrayList();
195+
if (nameRequired) {
196+
retList.add(BundleUtil.getStringFromBundle("name"));
223197
}
224-
if(emailRequired){
225-
if(retVal.isEmpty()){
226-
retVal = "Required Account Information<br/>&#160; &#8226; Email";
227-
} else {
228-
retVal += "<br/>&#160; &#8226; Email";
229-
}
198+
if (emailRequired) {
199+
retList.add(BundleUtil.getStringFromBundle("email"));
230200
}
231-
if(institutionRequired){
232-
if(retVal.isEmpty()){
233-
retVal = "Required Account Information<br/>&#160; &#8226; Institution";
234-
} else {
235-
retVal += "<br/>&#160; &#8226; Institution";
236-
}
201+
if (institutionRequired) {
202+
retList.add(BundleUtil.getStringFromBundle("institution"));
237203
}
238-
if(positionRequired){
239-
if(retVal.isEmpty()){
240-
retVal = "Required Account Information<br/>&#160; &#8226; Position";
241-
} else {
242-
retVal += "<br/>&#160; &#8226; Position";
243-
}
204+
if (positionRequired) {
205+
retList.add(BundleUtil.getStringFromBundle("position"));
244206
}
245-
return retVal;
207+
return retList;
246208
}
247209

248-
public String getOptionalAccountInformationString(){
249-
String retVal = "";
210+
public List<String> getOptionalAccountInformation(){
211+
List <String> retList = new ArrayList();
250212
if(!nameRequired){
251-
retVal = "Optional Account Information<br/>&#160; &#8226; Name";
213+
retList.add(BundleUtil.getStringFromBundle("name"));
252214
}
253215
if(!emailRequired){
254-
if(retVal.isEmpty()){
255-
retVal = "Optional Account Information<br/>&#160; &#8226; Email";
256-
} else {
257-
retVal += "<br/>&#160; &#8226; Email";
258-
}
216+
retList.add(BundleUtil.getStringFromBundle("email"));
259217
}
260218
if(!institutionRequired){
261-
if(retVal.isEmpty()){
262-
retVal = "Optional Account Information<br/>&#160; &#8226; Institution";
263-
} else {
264-
retVal += "<br/>&#160; &#8226; Institution";
265-
}
219+
retList.add(BundleUtil.getStringFromBundle("institution"));
266220
}
267221
if(!positionRequired){
268-
if(retVal.isEmpty()){
269-
retVal = "Optional Account Information<br/>&#160; &#8226; Position";
270-
} else {
271-
retVal += "<br/>&#160; &#8226; Position";
272-
}
222+
retList.add(BundleUtil.getStringFromBundle("position"));
273223
}
274-
return retVal;
224+
return retList;
225+
226+
}
227+
228+
public List<String> getRequiredQuestionsList(){
229+
List <String> retList = new ArrayList();
230+
for (CustomQuestion cq : this.getCustomQuestions()){
231+
if(cq.isRequired()){
232+
retList.add(cq.getQuestionString());
233+
}
234+
}
235+
return retList;
275236
}
276237

238+
public List<String> getOptionalQuestionsList(){
239+
List <String> retList = new ArrayList();
240+
for (CustomQuestion cq : this.getCustomQuestions()){
241+
if(!cq.isRequired()){
242+
retList.add(cq.getQuestionString());
243+
}
244+
}
245+
return retList;
246+
}
247+
277248
public void removeCustomQuestion(int index){
278249
customQuestions.remove(index);
279250
}

src/main/java/edu/harvard/iq/dataverse/RoleAssigneeServiceBean.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -274,7 +274,11 @@ private String getDvObjectIdListClause(List<Long> dvObjectIdList) {
274274
return " AND r.definitionpoint_id IN (" + StringUtils.join(outputList, ",") + ")";
275275
}
276276

277-
private List<String> getUserExplicitGroups(String roleAssigneeIdentifier) {
277+
/**
278+
* @todo Support groups within groups:
279+
* https://github.com/IQSS/dataverse/issues/3056
280+
*/
281+
public List<String> getUserExplicitGroups(String roleAssigneeIdentifier) {
278282

279283
String qstr = "select groupalias from explicitgroup";
280284
qstr += " where id in ";

src/main/java/edu/harvard/iq/dataverse/Shib.java

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -357,21 +357,34 @@ public String cancel() {
357357
}
358358

359359
/**
360-
* @return The value of a Shib attribute (if non-empty) or null.
360+
* @return The trimmed value of a Shib attribute (if non-empty) or null.
361+
*
362+
* @todo Move this to ShibUtil
361363
*/
362364
private String getValueFromAssertion(String key) {
363365
Object attribute = request.getAttribute(key);
364366
if (attribute != null) {
365367
String attributeValue = attribute.toString();
366-
logger.fine("The SAML assertion for \"" + key + "\" (optional) was \"" + attributeValue + "\".");
367-
if (!attributeValue.isEmpty()) {
368-
return attributeValue;
368+
String trimmedValue = attributeValue.trim();
369+
if (!trimmedValue.isEmpty()) {
370+
logger.fine("The SAML assertion for \"" + key + "\" (optional) was \"" + attributeValue + "\" and was trimmed to \"" + trimmedValue + "\".");
371+
return trimmedValue;
372+
} else {
373+
logger.fine("The SAML assertion for \"" + key + "\" (optional) was \"" + attributeValue + "\" and was trimmed to \"" + trimmedValue + "\" (empty string). Returing null.");
374+
return null;
369375
}
376+
} else {
377+
logger.fine("The SAML assertion for \"" + key + "\" (optional) was null.");
378+
return null;
370379
}
371-
logger.info("The SAML assertion for \"" + key + "\" (optional) was null.");
372-
return null;
373380
}
374381

382+
/**
383+
* @return The trimmed value of a Shib attribute (if non-empty) or null.
384+
*
385+
* @todo Move this to ShibUtil. More objects might be required since
386+
* sometimes we want to show messages, etc.
387+
*/
375388
private String getRequiredValueFromAssertion(String key) throws Exception {
376389
Object attribute = request.getAttribute(key);
377390
if (attribute == null) {
@@ -390,8 +403,9 @@ private String getRequiredValueFromAssertion(String key) throws Exception {
390403
if (attributeValue.isEmpty()) {
391404
throw new Exception(key + " was empty");
392405
}
393-
logger.fine("The SAML assertion for \"" + key + "\" (required) was \"" + attributeValue + "\".");
394-
return attributeValue;
406+
String trimmedValue = attributeValue.trim();
407+
logger.fine("The SAML assertion for \"" + key + "\" (required) was \"" + attributeValue + "\" and was trimmed to \"" + trimmedValue + "\".");
408+
return trimmedValue;
395409
}
396410

397411
public String getRootDataverseAlias() {

src/main/java/edu/harvard/iq/dataverse/api/BuiltinUsers.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
import edu.harvard.iq.dataverse.authorization.providers.builtin.PasswordEncryption;
99
import edu.harvard.iq.dataverse.authorization.users.ApiToken;
1010
import edu.harvard.iq.dataverse.authorization.users.AuthenticatedUser;
11+
import edu.harvard.iq.dataverse.util.json.JsonPrinter;
1112
import java.sql.Timestamp;
1213
import java.util.Calendar;
1314
import java.util.logging.Level;
@@ -24,6 +25,7 @@
2425
import javax.ws.rs.core.Response;
2526
import javax.ws.rs.core.Response.Status;
2627
import static edu.harvard.iq.dataverse.util.json.JsonPrinter.json;
28+
import static edu.harvard.iq.dataverse.util.json.JsonPrinter.jsonForAuthUser;
2729

2830
/**
2931
* REST API bean for managing {@link BuiltinUser}s.
@@ -134,6 +136,7 @@ private Response internalSave(BuiltinUser user, String password, String key) {
134136

135137
JsonObjectBuilder resp = Json.createObjectBuilder();
136138
resp.add("user", json(user));
139+
resp.add("authenticatedUser", jsonForAuthUser(au));
137140
resp.add("apiToken", token.getTokenString());
138141

139142
alr.setInfo("builtinUser:" + user.getUserName() + " authenticatedUser:" + au.getIdentifier() );

src/main/java/edu/harvard/iq/dataverse/authorization/AuthenticationServiceBean.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -269,6 +269,11 @@ public AuthenticatedUser authenticate( String authenticationProviderId, Authenti
269269
// yay! see if we already have this user.
270270
AuthenticatedUser user = lookupUser(authenticationProviderId, resp.getUserId());
271271

272+
/**
273+
* @todo Why does a method called "authenticate" have the potential
274+
* to call "createAuthenticatedUser"? Isn't the creation of a user a
275+
* different action than authenticating?
276+
*/
272277
return ( user == null ) ?
273278
AuthenticationServiceBean.this.createAuthenticatedUser(
274279
new UserRecordIdentifier(authenticationProviderId, resp.getUserId()), resp.getUserId(), resp.getUserDisplayInfo(), true )
@@ -391,6 +396,7 @@ public ApiToken save( ApiToken aToken ) {
391396
* @param userDisplayInfo
392397
* @param generateUniqueIdentifier if {@code true}, create a new, unique user identifier for the created user, if the suggested one exists.
393398
* @return the newly created user, or {@code null} if the proposed identifier exists and {@code generateUniqueIdentifier} was {@code false}.
399+
* @throws EJBException which may wrap an ConstraintViolationException if the proposed user does not pass bean validation.
394400
*/
395401
public AuthenticatedUser createAuthenticatedUser(UserRecordIdentifier userRecordId,
396402
String proposedAuthenticatedUserIdentifier,
@@ -399,6 +405,10 @@ public AuthenticatedUser createAuthenticatedUser(UserRecordIdentifier userRecord
399405
AuthenticatedUser authenticatedUser = new AuthenticatedUser();
400406
authenticatedUser.applyDisplayInfo(userDisplayInfo);
401407

408+
// we have no desire for leading or trailing whitespace in identifiers
409+
if (proposedAuthenticatedUserIdentifier != null) {
410+
proposedAuthenticatedUserIdentifier = proposedAuthenticatedUserIdentifier.trim();
411+
}
402412
// we now select a username for the generated AuthenticatedUser, or give up
403413
String internalUserIdentifer = proposedAuthenticatedUserIdentifier;
404414
// TODO should lock table authenticated users for write here

0 commit comments

Comments
 (0)