From 908f4c761aeecf6ccde03230551bd548f98da8b3 Mon Sep 17 00:00:00 2001 From: Mykhaylo Date: Thu, 16 Apr 2020 12:52:19 +0200 Subject: [PATCH 01/33] added initial implementantions for languages support --- .../AbstractDSpaceRestRepository.java | 30 ++++++++++++- .../SubmissionFormRestRepository.java | 42 ++++++++++++++----- 2 files changed, 61 insertions(+), 11 deletions(-) diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/AbstractDSpaceRestRepository.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/AbstractDSpaceRestRepository.java index a64f8af5df14..7f815ea8f2cc 100644 --- a/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/AbstractDSpaceRestRepository.java +++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/AbstractDSpaceRestRepository.java @@ -7,10 +7,14 @@ */ package org.dspace.app.rest.repository; +import java.util.Locale; + +import org.apache.commons.lang3.StringUtils; import org.dspace.app.rest.converter.ConverterService; import org.dspace.app.rest.utils.ContextUtil; import org.dspace.app.rest.utils.Utils; import org.dspace.core.Context; +import org.dspace.core.I18nUtil; import org.dspace.services.RequestService; import org.dspace.services.model.Request; import org.dspace.utils.DSpace; @@ -33,11 +37,35 @@ public abstract class AbstractDSpaceRestRepository { protected RequestService requestService = new DSpace().getRequestService(); protected Context obtainContext() { + Context context = null; Request currentRequest = requestService.getCurrentRequest(); - return ContextUtil.obtainContext(currentRequest.getServletRequest()); + context = ContextUtil.obtainContext(currentRequest.getServletRequest()); + Locale currentLocale = getLocal(context, currentRequest); + context.setCurrentLocale(currentLocale); + return context; } public RequestService getRequestService() { return requestService; } + + private Locale getLocal(Context context, Request request) { + Locale userLocale = null; + Locale supportedLocale = null; + if (context.getCurrentUser() != null) { + String userLanguage = context.getCurrentUser().getLanguage(); + if (userLanguage != null) { + userLocale = new Locale(userLanguage); + } + } + String locale = request.getHttpServletRequest().getHeader("Accept-Language"); + if (StringUtils.isNotBlank(locale)) { + userLocale = new Locale(locale); + } + if (userLocale == null) { + return I18nUtil.getDefaultLocale(); + } + supportedLocale = I18nUtil.getSupportedLocale(userLocale); + return supportedLocale; + } } diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/SubmissionFormRestRepository.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/SubmissionFormRestRepository.java index 48856aa16322..4552d7ddd51a 100644 --- a/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/SubmissionFormRestRepository.java +++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/SubmissionFormRestRepository.java @@ -7,13 +7,17 @@ */ package org.dspace.app.rest.repository; +import java.util.HashMap; import java.util.List; +import java.util.Locale; +import java.util.Map; import org.dspace.app.rest.model.SubmissionFormRest; import org.dspace.app.util.DCInputSet; import org.dspace.app.util.DCInputsReader; import org.dspace.app.util.DCInputsReaderException; import org.dspace.core.Context; +import org.dspace.core.I18nUtil; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; import org.springframework.security.access.prepost.PreAuthorize; @@ -26,32 +30,50 @@ */ @Component(SubmissionFormRest.CATEGORY + "." + SubmissionFormRest.NAME) public class SubmissionFormRestRepository extends DSpaceRestRepository { - - private DCInputsReader inputReader; + private Map inputReaders; + private DCInputsReader defaultInputReader; public SubmissionFormRestRepository() throws DCInputsReaderException { - inputReader = new DCInputsReader(); + defaultInputReader = new DCInputsReader(); + Locale[] locales = I18nUtil.getSupportedLocales(); + inputReaders = new HashMap(); + for (Locale locale : locales) { + inputReaders.put(locale, new DCInputsReader(I18nUtil.getInputFormsFileName(locale))); + } } @PreAuthorize("hasAuthority('AUTHENTICATED')") @Override - public SubmissionFormRest findOne(Context context, String submitName) { - DCInputSet inputConfig; + public SubmissionFormRest findOne(Context context, String submitName) { try { - inputConfig = inputReader.getInputsByFormName(submitName); + Locale currentLocale = context.getCurrentLocale(); + DCInputsReader inputReader; + if (currentLocale != null) { + inputReader = inputReaders.get(currentLocale); + } else { + inputReader = defaultInputReader; + } + DCInputSet subConfs = inputReader.getInputsByFormName(submitName); + if (subConfs == null) { + return null; + } + return converter.toRest(subConfs, utils.obtainProjection()); } catch (DCInputsReaderException e) { throw new IllegalStateException(e.getMessage(), e); } - if (inputConfig == null) { - return null; - } - return converter.toRest(inputConfig, utils.obtainProjection()); } @PreAuthorize("hasAuthority('AUTHENTICATED')") @Override public Page findAll(Context context, Pageable pageable) { try { + Locale currentLocale = context.getCurrentLocale(); + DCInputsReader inputReader; + if (currentLocale != null) { + inputReader = inputReaders.get(currentLocale); + } else { + inputReader = defaultInputReader; + } long total = inputReader.countInputs(); List subConfs = inputReader.getAllInputs(pageable.getPageSize(), Math.toIntExact(pageable.getOffset())); From 36ef4224cd5cf8c5233dca4c15642e0d43caaee2 Mon Sep 17 00:00:00 2001 From: Mykhaylo Date: Thu, 16 Apr 2020 12:57:17 +0200 Subject: [PATCH 02/33] added configurations and submissions forms in italian and --- .../dspaceFolder/config/item-submission.xml | 11 ++ .../config/submission-forms_it.xml | 171 ++++++++++++++++++ .../config/submission-forms_uk.xml | 169 +++++++++++++++++ 3 files changed, 351 insertions(+) create mode 100644 dspace-api/src/test/data/dspaceFolder/config/submission-forms_it.xml create mode 100644 dspace-api/src/test/data/dspaceFolder/config/submission-forms_uk.xml diff --git a/dspace-api/src/test/data/dspaceFolder/config/item-submission.xml b/dspace-api/src/test/data/dspaceFolder/config/item-submission.xml index de19ef728705..a01cdc1cbc9f 100644 --- a/dspace-api/src/test/data/dspaceFolder/config/item-submission.xml +++ b/dspace-api/src/test/data/dspaceFolder/config/item-submission.xml @@ -18,6 +18,7 @@ + @@ -108,6 +109,12 @@ org.dspace.submit.step.SampleStep sample + + + submit.progressbar.describe.stepone + org.dspace.app.rest.submit.step.DescribeStep + submission-form + @@ -149,6 +156,10 @@ + + + + diff --git a/dspace-api/src/test/data/dspaceFolder/config/submission-forms_it.xml b/dspace-api/src/test/data/dspaceFolder/config/submission-forms_it.xml new file mode 100644 index 000000000000..151482479663 --- /dev/null +++ b/dspace-api/src/test/data/dspaceFolder/config/submission-forms_it.xml @@ -0,0 +1,171 @@ + + + + + + + + + + + + + + + + + + + + + + + +
+ + + dc + title + + false + + onebox + Inserisci nome del file + È necessario inserire un titolo principale per questo item + + + + + dc + description + true + + textarea + Inserisci descrizione per questo file + + + +
+ +
+ + + isAuthorOfPublication + person + true + + Aggiungi un autore + + dc + contributor + author + name + + È richiesto almeno un autore + + + + + dc + title + + false + + onebox + Inserisci titolo principale di questo item + È necessario inserire un titolo principale per questo item + + + + + + + + dc + language + iso + false + + dropdown + Selezionare la lingua del contenuto principale dell'item. Se la lingua non compare + nell'elenco, selezionare "Altro". Se il contenuto non ha davvero una lingua (ad esempio, + se è un set di dati o un'immagine) selezionare "N/A". + + + + +
+
+ + + + + + + + + + + + + + + + + + + + + N/A + + + + Inglese (USA) + en_US + + + Inglese + en + + + Spagnolo + es + + + Tedesco + de + + + Francese + fr + + + Italiano + it + + + Giapponese + ja + + + Cinese + zh + + + Portogallo + pt + + + Ucraino + uk + + + (Altro) + other + + + + +
\ No newline at end of file diff --git a/dspace-api/src/test/data/dspaceFolder/config/submission-forms_uk.xml b/dspace-api/src/test/data/dspaceFolder/config/submission-forms_uk.xml new file mode 100644 index 000000000000..88941c34ac27 --- /dev/null +++ b/dspace-api/src/test/data/dspaceFolder/config/submission-forms_uk.xml @@ -0,0 +1,169 @@ + + + + + + + + + + + + + + + + + + + + + + + +
+ + + dc + title + + false + + onebox + Ввести основний заголовок файла. + Заговолок файла обов'язковий ! + + + + + dc + description + true + + textarea + Ввести опис для цього файла + + + +
+ +
+ + + isAuthorOfPublication + person + true + + Додати автора + + dc + contributor + author + name + + Потрібно ввести хочаб одного автора! + + + + + dc + title + + false + + onebox + Ввести основний заголовок файла + Заговолок файла обов'язковий ! + + + + + + + dc + language + iso + false + + dropdown + Виберiть мову головного змiсту файлу, як що мови немає у списку, + вибрати "Iнша". Як що вмiст вайлу не є текстовим, наприклад + є фотографiєю, тодi вибрати "N/A" + + + + +
+
+ + + + + + + + + + + + + + + + + + + + N/A + + + + Американська (USA) + en_US + + + Англiйська + en + + + Iспанська + es + + + Нiмецька + de + + + Французька + fr + + + Iталiйська + it + + + Японська + ja + + + Китайська + zh + + + Португальська + pt + + + Турецька + tr + + + (Iнша) + other + + + + +
\ No newline at end of file From ec59b7d45e98c6031abe89d82f3aed6eb0ecf14a Mon Sep 17 00:00:00 2001 From: Mykhaylo Date: Sat, 18 Apr 2020 18:17:25 +0200 Subject: [PATCH 03/33] added Filter for set Content-Language Header of the response --- .../ContentLanguageHeaderResponseFilter.java | 52 +++++++++++++++++++ 1 file changed, 52 insertions(+) create mode 100644 dspace-server-webapp/src/main/java/org/dspace/app/rest/filter/ContentLanguageHeaderResponseFilter.java diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/filter/ContentLanguageHeaderResponseFilter.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/filter/ContentLanguageHeaderResponseFilter.java new file mode 100644 index 000000000000..e5bda29c8442 --- /dev/null +++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/filter/ContentLanguageHeaderResponseFilter.java @@ -0,0 +1,52 @@ +package org.dspace.app.rest.filter; + +import java.io.IOException; +import java.util.Locale; +import javax.servlet.Filter; +import javax.servlet.FilterChain; +import javax.servlet.FilterConfig; +import javax.servlet.ServletException; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.http.HttpServletResponse; + +import org.dspace.core.I18nUtil; +import org.springframework.stereotype.Component; + +/** + * This filter assures that when the dspace instance supports multiple languages + * they are noted in the Content-Language Header of the response + * + * @author Mykhaylo Boychuk (at 4science.it) + */ +@Component +public class ContentLanguageHeaderResponseFilter implements Filter { + + @Override + public void init(FilterConfig filterConfig) throws ServletException { + } + + @Override + public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) + throws IOException, ServletException { + chain.doFilter(request, response); + + HttpServletResponse httpServletResponse = (HttpServletResponse) response; + if (!httpServletResponse.containsHeader("Content-Language")) { + Locale[] locales = I18nUtil.getSupportedLocales(); + StringBuilder locsStr = new StringBuilder(); + for (Locale locale : locales) { + if (locsStr.length() > 0) { + locsStr.append(","); + } + locsStr.append(locale.getLanguage()); + } + httpServletResponse.setHeader("Content-Language", locsStr.toString()); + } + } + + @Override + public void destroy() { + } + +} From 0a37c5906a200b08d53d2584d403b74dae297280 Mon Sep 17 00:00:00 2001 From: Mykhaylo Date: Sat, 18 Apr 2020 18:24:16 +0200 Subject: [PATCH 04/33] refactoring --- .../org/dspace/administer/CreateAdministrator.java | 2 +- .../src/main/java/org/dspace/core/Context.java | 2 +- .../src/main/java/org/dspace/core/I18nUtil.java | 13 +++++-------- .../src/test/java/org/dspace/core/ContextTest.java | 2 +- 4 files changed, 8 insertions(+), 11 deletions(-) diff --git a/dspace-api/src/main/java/org/dspace/administer/CreateAdministrator.java b/dspace-api/src/main/java/org/dspace/administer/CreateAdministrator.java index a58691e2515d..983038c81200 100644 --- a/dspace-api/src/main/java/org/dspace/administer/CreateAdministrator.java +++ b/dspace-api/src/main/java/org/dspace/administer/CreateAdministrator.java @@ -115,7 +115,7 @@ protected void negotiateAdministratorDetails() String lastName = null; char[] password1 = null; char[] password2 = null; - String language = I18nUtil.DEFAULTLOCALE.getLanguage(); + String language = I18nUtil.getDefaultLocale().getLanguage(); while (!dataOK) { System.out.print("E-mail address: "); diff --git a/dspace-api/src/main/java/org/dspace/core/Context.java b/dspace-api/src/main/java/org/dspace/core/Context.java index ecfc29d29d6e..11e388c727ff 100644 --- a/dspace-api/src/main/java/org/dspace/core/Context.java +++ b/dspace-api/src/main/java/org/dspace/core/Context.java @@ -179,7 +179,7 @@ protected void init() { } currentUser = null; - currentLocale = I18nUtil.DEFAULTLOCALE; + currentLocale = I18nUtil.getDefaultLocale(); extraLogInfo = ""; ignoreAuth = false; diff --git a/dspace-api/src/main/java/org/dspace/core/I18nUtil.java b/dspace-api/src/main/java/org/dspace/core/I18nUtil.java index 37e48c4a4f5e..0d5e95d04820 100644 --- a/dspace-api/src/main/java/org/dspace/core/I18nUtil.java +++ b/dspace-api/src/main/java/org/dspace/core/I18nUtil.java @@ -37,9 +37,6 @@ public class I18nUtil { private static final Logger log = org.apache.logging.log4j.LogManager.getLogger(I18nUtil.class); - // the default Locale of this DSpace Instance - public static final Locale DEFAULTLOCALE = getDefaultLocale(); - // delimiters between elements of UNIX/POSIX locale spec, e.g. en_US.UTF-8 private static final String LOCALE_DELIMITERS = " _."; @@ -127,7 +124,7 @@ public static Locale[] getSupportedLocales() { return parseLocales(locales); } else { Locale[] availableLocales = new Locale[1]; - availableLocales[0] = DEFAULTLOCALE; + availableLocales[0] = getDefaultLocale(); return availableLocales; } } @@ -148,7 +145,7 @@ public static Locale getSupportedLocale(Locale locale) { Locale supportedLocale = null; String testLocale = ""; if (availableLocales == null) { - supportedLocale = DEFAULTLOCALE; + supportedLocale = getDefaultLocale(); } else { if (!locale.getVariant().equals("")) { testLocale = locale.toString(); @@ -188,7 +185,7 @@ public static Locale getSupportedLocale(Locale locale) { } } if (!isSupported) { - supportedLocale = DEFAULTLOCALE; + supportedLocale = getDefaultLocale(); } } return supportedLocale; @@ -220,7 +217,7 @@ public static String getInputFormsFileName(Locale locale) { * String of the message */ public static String getMessage(String key) { - return getMessage(key.trim(), DEFAULTLOCALE); + return getMessage(key.trim(), getDefaultLocale()); } /** @@ -233,7 +230,7 @@ public static String getMessage(String key) { */ public static String getMessage(String key, Locale locale) { if (locale == null) { - locale = DEFAULTLOCALE; + locale = getDefaultLocale(); } ResourceBundle.Control control = ResourceBundle.Control.getNoFallbackControl( diff --git a/dspace-api/src/test/java/org/dspace/core/ContextTest.java b/dspace-api/src/test/java/org/dspace/core/ContextTest.java index f5697a72dcfc..0c29e053ece6 100644 --- a/dspace-api/src/test/java/org/dspace/core/ContextTest.java +++ b/dspace-api/src/test/java/org/dspace/core/ContextTest.java @@ -130,7 +130,7 @@ public void testGetCurrentUser() { public void testGetCurrentLocale() { //NOTE: CurrentLocale is not initialized in AbstractUnitTest. So it should be DEFAULTLOCALE assertThat("testGetCurrentLocale 0", context.getCurrentLocale(), notNullValue()); - assertThat("testGetCurrentLocale 1", context.getCurrentLocale(), equalTo(I18nUtil.DEFAULTLOCALE)); + assertThat("testGetCurrentLocale 1", context.getCurrentLocale(), equalTo(I18nUtil.getDefaultLocale())); } /** From efcefef914c20684bdf229f609d4bcf8544267a3 Mon Sep 17 00:00:00 2001 From: Mykhaylo Date: Sat, 18 Apr 2020 18:43:06 +0200 Subject: [PATCH 05/33] added ITs for language support --- .../config/submission-forms_uk.xml | 7 +- .../SubmissionFormRestRepository.java | 9 + .../app/rest/SubmissionFormsControllerIT.java | 230 ++++++++++++++++++ 3 files changed, 241 insertions(+), 5 deletions(-) diff --git a/dspace-api/src/test/data/dspaceFolder/config/submission-forms_uk.xml b/dspace-api/src/test/data/dspaceFolder/config/submission-forms_uk.xml index 88941c34ac27..49a2ccc1a903 100644 --- a/dspace-api/src/test/data/dspaceFolder/config/submission-forms_uk.xml +++ b/dspace-api/src/test/data/dspaceFolder/config/submission-forms_uk.xml @@ -47,7 +47,7 @@ -
+ isAuthorOfPublication @@ -86,10 +86,7 @@ false dropdown - Виберiть мову головного змiсту файлу, як що мови немає у списку, - вибрати "Iнша". Як що вмiст вайлу не є текстовим, наприклад - є фотографiєю, тодi вибрати "N/A" - + Виберiть мову головного змiсту файлу, як що мови немає у списку, вибрати (Iнша). Як що вмiст вайлу не є текстовим, наприклад є фотографiєю, тодi вибрати (N/A) diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/SubmissionFormRestRepository.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/SubmissionFormRestRepository.java index 4552d7ddd51a..434a8dc0fd3d 100644 --- a/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/SubmissionFormRestRepository.java +++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/SubmissionFormRestRepository.java @@ -87,4 +87,13 @@ public Page findAll(Context context, Pageable pageable) { public Class getDomainClass() { return SubmissionFormRest.class; } + + public void reload() throws DCInputsReaderException { + this.defaultInputReader = new DCInputsReader(); + Locale[] locales = I18nUtil.getSupportedLocales(); + this.inputReaders = new HashMap(); + for (Locale locale : locales) { + inputReaders.put(locale, new DCInputsReader(I18nUtil.getInputFormsFileName(locale))); + } + } } diff --git a/dspace-server-webapp/src/test/java/org/dspace/app/rest/SubmissionFormsControllerIT.java b/dspace-server-webapp/src/test/java/org/dspace/app/rest/SubmissionFormsControllerIT.java index b17ea47c2d65..235764eccdc2 100644 --- a/dspace-server-webapp/src/test/java/org/dspace/app/rest/SubmissionFormsControllerIT.java +++ b/dspace-server-webapp/src/test/java/org/dspace/app/rest/SubmissionFormsControllerIT.java @@ -16,10 +16,18 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +import java.util.Locale; + +import org.dspace.app.rest.builder.EPersonBuilder; import org.dspace.app.rest.matcher.SubmissionFormFieldMatcher; +import org.dspace.app.rest.repository.SubmissionFormRestRepository; import org.dspace.app.rest.test.AbstractControllerIntegrationTest; +import org.dspace.app.util.DCInputsReaderException; +import org.dspace.eperson.EPerson; +import org.dspace.services.ConfigurationService; import org.hamcrest.Matchers; import org.junit.Test; +import org.springframework.beans.factory.annotation.Autowired; /** * Integration test to test the /api/config/submissionforms endpoint @@ -27,6 +35,11 @@ */ public class SubmissionFormsControllerIT extends AbstractControllerIntegrationTest { + @Autowired + private ConfigurationService configurationService; + @Autowired + private SubmissionFormRestRepository submissionFormRestRepository; + @Test public void findAll() throws Exception { //When we call the root endpoint as anonymous user @@ -185,4 +198,221 @@ public void findClosedRelationshipConfig() throws Exception { "creativework.publisher:somepublishername", "periodical", false)))) ; } + + @Test + public void languageSupportTest() throws Exception { + context.turnOffAuthorisationSystem(); + String[] supportedLanguage = {"it","uk"}; + configurationService.setProperty("webui.supported.locales",supportedLanguage); + submissionFormRestRepository.reload(); + + Locale uk = new Locale("uk"); + Locale it = new Locale("it"); + + context.restoreAuthSystemState(); + + String tokenEperson = getAuthToken(eperson.getEmail(), password); + + // user select italian language + getClient(tokenEperson).perform(get("/api/config/submissionforms/languagetest").locale(it)) + .andExpect(status().isOk()) + .andExpect(content().contentType(contentType)) + .andExpect(jsonPath("$.id", is("languagetest"))) + .andExpect(jsonPath("$.name", is("languagetest"))) + .andExpect(jsonPath("$.type", is("submissionform"))) + .andExpect(jsonPath("$._links.self.href", Matchers + .startsWith(REST_SERVER_URL + "config/submissionforms/languagetest"))) + .andExpect(jsonPath("$.rows[0].fields", contains(SubmissionFormFieldMatcher + .matchFormFieldDefinition("name", "Autore", "\u00C8" + " richiesto almeno un autore", true, + "Aggiungi un autore", "dc.contributor.author")))) + .andExpect(jsonPath("$.rows[1].fields", contains(SubmissionFormFieldMatcher + .matchFormFieldDefinition("onebox", "Titolo", + "\u00C8" + " necessario inserire un titolo principale per questo item", false, + "Inserisci titolo principale di questo item", "dc.title")))) + .andExpect(jsonPath("$.rows[2].fields", contains(SubmissionFormFieldMatcher + .matchFormFieldDefinition("dropdown", "Lingua", null, false, + "Selezionare la lingua del contenuto principale dell'item." + + " Se la lingua non compare nell'elenco, selezionare (Altro)." + + " Se il contenuto non ha davvero una lingua" + + " (ad esempio, se è un set di dati o un'immagine) selezionare (N/A)", "dc.language.iso")))); + + // user select ukranian language + getClient(tokenEperson).perform(get("/api/config/submissionforms/languagetest").locale(uk)) + .andExpect(status().isOk()) + .andExpect(content().contentType(contentType)) + .andExpect(jsonPath("$.id", is("languagetest"))) + .andExpect(jsonPath("$.name", is("languagetest"))) + .andExpect(jsonPath("$.type", is("submissionform"))) + .andExpect(jsonPath("$._links.self.href", Matchers + .startsWith(REST_SERVER_URL + "config/submissionforms/languagetest"))) + .andExpect(jsonPath("$.rows[0].fields", contains(SubmissionFormFieldMatcher + .matchFormFieldDefinition("name", "Автор", "Потрібно ввести хочаб одного автора!", + true, "Додати автора", "dc.contributor.author")))) + .andExpect(jsonPath("$.rows[1].fields", contains(SubmissionFormFieldMatcher + .matchFormFieldDefinition("onebox", "Заголовок", + "Заговолок файла обов'язковий !", false, + "Ввести основний заголовок файла", "dc.title")))) + .andExpect(jsonPath("$.rows[2].fields", contains(SubmissionFormFieldMatcher + .matchFormFieldDefinition("dropdown", "Мова", null, false, + "Виберiть мову головного змiсту файлу, як що мови немає у списку, вибрати (Iнша)." + + " Як що вмiст вайлу не є текстовим, наприклад є фотографiєю, тодi вибрати (N/A)", + "dc.language.iso")))); + + resetPropertyFile(); + } + + @Test + public void preferLanguageTest() throws Exception { + context.turnOffAuthorisationSystem(); + + String[] supportedLanguage = {"it","uk"}; + configurationService.setProperty("webui.supported.locales",supportedLanguage); + submissionFormRestRepository.reload(); + + EPerson epersonIT = EPersonBuilder.createEPerson(context) + .withEmail("epersonIT@example.com") + .withPassword(password) + .withLanguage("it") + .build(); + + EPerson epersonUK = EPersonBuilder.createEPerson(context) + .withEmail("epersonUK@example.com") + .withPassword(password) + .withLanguage("uk") + .build(); + + context.restoreAuthSystemState(); + + String tokenEpersonIT = getAuthToken(epersonIT.getEmail(), password); + String tokenEpersonUK = getAuthToken(epersonUK.getEmail(), password); + + // user with italian prefer language + getClient(tokenEpersonIT).perform(get("/api/config/submissionforms/languagetest")) + .andExpect(status().isOk()) + .andExpect(content().contentType(contentType)) + .andExpect(jsonPath("$.id", is("languagetest"))) + .andExpect(jsonPath("$.name", is("languagetest"))) + .andExpect(jsonPath("$.type", is("submissionform"))) + .andExpect(jsonPath("$._links.self.href", Matchers + .startsWith(REST_SERVER_URL + "config/submissionforms/languagetest"))) + .andExpect(jsonPath("$.rows[0].fields", contains(SubmissionFormFieldMatcher + .matchFormFieldDefinition("name", "Autore", "\u00C8" + " richiesto almeno un autore", true, + "Aggiungi un autore", "dc.contributor.author")))) + .andExpect(jsonPath("$.rows[1].fields", contains(SubmissionFormFieldMatcher + .matchFormFieldDefinition("onebox", "Titolo", + "\u00C8" + " necessario inserire un titolo principale per questo item", false, + "Inserisci titolo principale di questo item", "dc.title")))) + .andExpect(jsonPath("$.rows[2].fields", contains(SubmissionFormFieldMatcher + .matchFormFieldDefinition("dropdown", "Lingua", null, false, + "Selezionare la lingua del contenuto principale dell'item." + + " Se la lingua non compare nell'elenco, selezionare (Altro)." + + " Se il contenuto non ha davvero una lingua" + + " (ad esempio, se è un set di dati o un'immagine) selezionare (N/A)", "dc.language.iso")))); + + // user with ukranian prefer language + getClient(tokenEpersonUK).perform(get("/api/config/submissionforms/languagetest")) + .andExpect(status().isOk()) + .andExpect(content().contentType(contentType)) + .andExpect(jsonPath("$.id", is("languagetest"))) + .andExpect(jsonPath("$.name", is("languagetest"))) + .andExpect(jsonPath("$.type", is("submissionform"))) + .andExpect(jsonPath("$._links.self.href", Matchers + .startsWith(REST_SERVER_URL + "config/submissionforms/languagetest"))) + .andExpect(jsonPath("$.rows[0].fields", contains(SubmissionFormFieldMatcher + .matchFormFieldDefinition("name", "Автор", "Потрібно ввести хочаб одного автора!", + true, "Додати автора", "dc.contributor.author")))) + .andExpect(jsonPath("$.rows[1].fields", contains(SubmissionFormFieldMatcher + .matchFormFieldDefinition("onebox", "Заголовок", + "Заговолок файла обов'язковий !", false, + "Ввести основний заголовок файла", "dc.title")))) + .andExpect(jsonPath("$.rows[2].fields", contains(SubmissionFormFieldMatcher + .matchFormFieldDefinition("dropdown", "Мова", null, false, + "Виберiть мову головного змiсту файлу, як що мови немає у списку, вибрати (Iнша)." + + " Як що вмiст вайлу не є текстовим, наприклад є фотографiєю, тодi вибрати (N/A)", + "dc.language.iso")))); + + resetPropertyFile(); + } + + @Test + public void userChoiceAnotherLanguageTest() throws Exception { + context.turnOffAuthorisationSystem(); + + String[] supportedLanguage = {"it","uk"}; + configurationService.setProperty("webui.supported.locales",supportedLanguage); + submissionFormRestRepository.reload(); + + Locale it = new Locale("it"); + + EPerson epersonUK = EPersonBuilder.createEPerson(context) + .withEmail("epersonUK@example.com") + .withPassword(password) + .withLanguage("uk") + .build(); + + context.restoreAuthSystemState(); + + String tokenEpersonUK = getAuthToken(epersonUK.getEmail(), password); + + // user prefer ukranian but choice italian language + getClient(tokenEpersonUK).perform(get("/api/config/submissionforms/languagetest").locale(it)) + .andExpect(status().isOk()) + .andExpect(content().contentType(contentType)) + .andExpect(jsonPath("$.id", is("languagetest"))) + .andExpect(jsonPath("$.name", is("languagetest"))) + .andExpect(jsonPath("$.type", is("submissionform"))) + .andExpect(jsonPath("$._links.self.href", Matchers + .startsWith(REST_SERVER_URL + "config/submissionforms/languagetest"))) + .andExpect(jsonPath("$.rows[0].fields", contains(SubmissionFormFieldMatcher + .matchFormFieldDefinition("name", "Autore", "\u00C8" + " richiesto almeno un autore", true, + "Aggiungi un autore", "dc.contributor.author")))) + .andExpect(jsonPath("$.rows[1].fields", contains(SubmissionFormFieldMatcher + .matchFormFieldDefinition("onebox", "Titolo", + "\u00C8" + " necessario inserire un titolo principale per questo item", false, + "Inserisci titolo principale di questo item", "dc.title")))) + .andExpect(jsonPath("$.rows[2].fields", contains(SubmissionFormFieldMatcher + .matchFormFieldDefinition("dropdown", "Lingua", null, false, + "Selezionare la lingua del contenuto principale dell'item." + + " Se la lingua non compare nell'elenco, selezionare (Altro)." + + " Se il contenuto non ha davvero una lingua" + + " (ad esempio, se è un set di dati o un'immagine) selezionare (N/A)", "dc.language.iso")))); + + resetPropertyFile(); + } + + @Test + public void defaultLanguageTest() throws Exception { + context.turnOffAuthorisationSystem(); + + String[] supportedLanguage = {"it","uk"}; + configurationService.setProperty("default.locale","it"); + configurationService.setProperty("webui.supported.locales",supportedLanguage); + submissionFormRestRepository.reload(); + + context.restoreAuthSystemState(); + + String tokenEperson = getAuthToken(eperson.getEmail(), password); + getClient(tokenEperson).perform(get("/api/config/submissionforms/languagetest")) + .andExpect(status().isOk()) + .andExpect(content().contentType(contentType)) + .andExpect(jsonPath("$.id", is("languagetest"))) + .andExpect(jsonPath("$.name", is("languagetest"))) + .andExpect(jsonPath("$.type", is("submissionform"))) + .andExpect(jsonPath("$._links.self.href", Matchers + .startsWith(REST_SERVER_URL + "config/submissionforms/languagetest"))) + .andExpect(jsonPath("$.rows[0].fields", contains(SubmissionFormFieldMatcher + .matchFormFieldDefinition("name", "Autore", "\u00C8 richiesto almeno un autore", true, + "Aggiungi un autore", "dc.contributor.author")))) + .andExpect(jsonPath("$.rows[1].fields", contains(SubmissionFormFieldMatcher + .matchFormFieldDefinition("onebox", "Titolo", + "\u00C8 necessario inserire un titolo principale per questo item", false, + "Inserisci titolo principale di questo item", "dc.title")))); + + resetPropertyFile(); + } + + private void resetPropertyFile() throws DCInputsReaderException { + configurationService.setProperty("webui.supported.locales",null); + submissionFormRestRepository.reload(); + } } From e2cf32dea33ab26b1f33224400a3b13bf081f972 Mon Sep 17 00:00:00 2001 From: Mykhaylo Date: Sun, 19 Apr 2020 13:27:16 +0200 Subject: [PATCH 06/33] added license --- .../test/data/dspaceFolder/config/submission-forms_it.xml | 4 +--- .../rest/filter/ContentLanguageHeaderResponseFilter.java | 7 +++++++ 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/dspace-api/src/test/data/dspaceFolder/config/submission-forms_it.xml b/dspace-api/src/test/data/dspaceFolder/config/submission-forms_it.xml index 151482479663..66ed4a926c17 100644 --- a/dspace-api/src/test/data/dspaceFolder/config/submission-forms_it.xml +++ b/dspace-api/src/test/data/dspaceFolder/config/submission-forms_it.xml @@ -87,9 +87,7 @@ false dropdown - Selezionare la lingua del contenuto principale dell'item. Se la lingua non compare - nell'elenco, selezionare "Altro". Se il contenuto non ha davvero una lingua (ad esempio, - se è un set di dati o un'immagine) selezionare "N/A". + Selezionare la lingua del contenuto principale dell'item. Se la lingua non compare nell'elenco, selezionare (Altro). Se il contenuto non ha davvero una lingua (ad esempio, se è un set di dati o un'immagine) selezionare (N/A). diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/filter/ContentLanguageHeaderResponseFilter.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/filter/ContentLanguageHeaderResponseFilter.java index e5bda29c8442..6552ae4f7f6d 100644 --- a/dspace-server-webapp/src/main/java/org/dspace/app/rest/filter/ContentLanguageHeaderResponseFilter.java +++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/filter/ContentLanguageHeaderResponseFilter.java @@ -1,3 +1,10 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ package org.dspace.app.rest.filter; import java.io.IOException; From 60240b19ca4b5b495c5ff26ab06403380c219570 Mon Sep 17 00:00:00 2001 From: Mykhaylo Date: Wed, 22 Apr 2020 12:43:13 +0200 Subject: [PATCH 07/33] added ITs for check Content-Language header --- .../dspace/app/rest/LanguageSupportIT.java | 84 +++++++++++++++++++ 1 file changed, 84 insertions(+) create mode 100644 dspace-server-webapp/src/test/java/org/dspace/app/rest/LanguageSupportIT.java diff --git a/dspace-server-webapp/src/test/java/org/dspace/app/rest/LanguageSupportIT.java b/dspace-server-webapp/src/test/java/org/dspace/app/rest/LanguageSupportIT.java new file mode 100644 index 000000000000..2dc06eca8b73 --- /dev/null +++ b/dspace-server-webapp/src/test/java/org/dspace/app/rest/LanguageSupportIT.java @@ -0,0 +1,84 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ +package org.dspace.app.rest; + +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.header; + +import java.util.Locale; + +import org.dspace.app.rest.builder.EPersonBuilder; +import org.dspace.app.rest.test.AbstractControllerIntegrationTest; +import org.dspace.content.authority.ChoiceAuthorityServiceImpl; +import org.dspace.core.LegacyPluginServiceImpl; +import org.dspace.eperson.EPerson; +import org.dspace.services.ConfigurationService; +import org.junit.Test; +import org.springframework.beans.factory.annotation.Autowired; + +/** + * Integration test class for supported languages + * + * @author Mykhaylo Boychuk (at 4science) + */ +public class LanguageSupportIT extends AbstractControllerIntegrationTest { + + @Autowired + private ConfigurationService configurationService; + @Autowired + private LegacyPluginServiceImpl legacyPluginService; + @Autowired + private ChoiceAuthorityServiceImpl choiceAuthorityServiceImpl; + + @Test + public void checkDefaultLanguageAnonymousTest() throws Exception { + getClient().perform(get("/api")) + .andExpect(header().stringValues("Content-Language","en")); + } + + @Test + public void checkEnabledMultipleLanguageSupportTest() throws Exception { + context.turnOffAuthorisationSystem(); + String[] supportedLanguage = {"uk","it"}; + configurationService.setProperty("webui.supported.locales",supportedLanguage); + legacyPluginService.clearNamedPluginClasses(); + choiceAuthorityServiceImpl.clearCache(); + + Locale it = new Locale("it"); + + EPerson epersonUK = EPersonBuilder.createEPerson(context) + .withEmail("epersonUK@example.com") + .withPassword(password) + .withLanguage("uk") + .build(); + + EPerson epersonFR = EPersonBuilder.createEPerson(context) + .withEmail("epersonFR@example.com") + .withPassword(password) + .withLanguage("fr") + .build(); + + context.restoreAuthSystemState(); + + String tokenEPersonUK = getAuthToken(epersonUK.getEmail(), password); + String tokenEPersonFR = getAuthToken(epersonFR.getEmail(), password); + + getClient(tokenEPersonUK).perform(get("/api")) + .andExpect(header().stringValues("Content-Language","uk, it")); + + getClient(tokenEPersonUK).perform(get("/api").locale(it)) + .andExpect(header().stringValues("Content-Language","uk, it")); + + getClient(tokenEPersonFR).perform(get("/api").locale(it)) + .andExpect(header().stringValues("Content-Language","en")); + + configurationService.setProperty("webui.supported.locales",null); + legacyPluginService.clearNamedPluginClasses(); + choiceAuthorityServiceImpl.clearCache(); + } +} From 9b2451754676740535841001593b6be431e8c969 Mon Sep 17 00:00:00 2001 From: Andrea Bollini Date: Thu, 18 Jun 2020 23:49:25 +0200 Subject: [PATCH 08/33] Fix obviously wrong implementation --- .../SubmissionUploadRestRepository.java | 38 ++++++------------- 1 file changed, 11 insertions(+), 27 deletions(-) diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/SubmissionUploadRestRepository.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/SubmissionUploadRestRepository.java index 3ea5989f5ab2..a359a7ec4f73 100644 --- a/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/SubmissionUploadRestRepository.java +++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/SubmissionUploadRestRepository.java @@ -8,6 +8,7 @@ package org.dspace.app.rest.repository; import java.util.ArrayList; +import java.util.Collection; import java.util.List; import org.apache.commons.lang3.StringUtils; @@ -16,10 +17,6 @@ import org.dspace.app.rest.model.SubmissionUploadRest; import org.dspace.app.rest.projection.Projection; import org.dspace.app.rest.utils.DateMathParser; -import org.dspace.app.util.SubmissionConfig; -import org.dspace.app.util.SubmissionConfigReader; -import org.dspace.app.util.SubmissionConfigReaderException; -import org.dspace.app.util.SubmissionStepConfig; import org.dspace.core.Context; import org.dspace.eperson.Group; import org.dspace.eperson.service.GroupService; @@ -28,7 +25,6 @@ import org.dspace.submit.model.UploadConfigurationService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.domain.Page; -import org.springframework.data.domain.PageImpl; import org.springframework.data.domain.Pageable; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.stereotype.Component; @@ -45,8 +41,6 @@ public class SubmissionUploadRestRepository extends DSpaceRestRepository findAll(Context context, Pageable pageable) { - List subConfs = new ArrayList(); - subConfs = submissionConfigReader.getAllSubmissionConfigs(pageable.getPageSize(), - Math.toIntExact(pageable.getOffset())); + Collection uploadConfigs = uploadConfigurationService.getMap().values(); Projection projection = utils.obtainProjection(); List results = new ArrayList<>(); - for (SubmissionConfig config : subConfs) { - for (int i = 0; i < config.getNumberOfSteps(); i++) { - SubmissionStepConfig step = config.getStep(i); - if (SubmissionStepConfig.UPLOAD_STEP_NAME.equals(step.getType())) { - UploadConfiguration uploadConfig = uploadConfigurationService.getMap().get(step.getId()); - if (uploadConfig != null) { - try { - results.add(convert(context, uploadConfig, projection)); - } catch (Exception e) { - log.error(e.getMessage(), e); - } - } + List configNames = new ArrayList(); + for (UploadConfiguration uploadConfig : uploadConfigs) { + if (!configNames.contains(uploadConfig.getName())) { + configNames.add(uploadConfig.getName()); + try { + results.add(convert(context, uploadConfig, projection)); + } catch (Exception e) { + log.error(e.getMessage(), e); } } } - return new PageImpl(results, pageable, results.size()); + return utils.getPage(results, pageable); } @Override From e4d61191e61ddf7f994c6fea4c4b699ead688488 Mon Sep 17 00:00:00 2001 From: Andrea Bollini Date: Thu, 18 Jun 2020 23:52:49 +0200 Subject: [PATCH 09/33] Disable test failing due to bug in the Mock library --- .../ContentLanguageHeaderResponseFilter.java | 23 +++++++++---------- .../dspace/app/rest/LanguageSupportIT.java | 5 +++- 2 files changed, 15 insertions(+), 13 deletions(-) diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/filter/ContentLanguageHeaderResponseFilter.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/filter/ContentLanguageHeaderResponseFilter.java index 6552ae4f7f6d..74ffd73ad463 100644 --- a/dspace-server-webapp/src/main/java/org/dspace/app/rest/filter/ContentLanguageHeaderResponseFilter.java +++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/filter/ContentLanguageHeaderResponseFilter.java @@ -22,7 +22,9 @@ /** * This filter assures that when the dspace instance supports multiple languages - * they are noted in the Content-Language Header of the response + * they are noted in the Content-Language Header of the response. Where + * appropriate the single endpoint can set the Content-Language header directly + * to note that the response is specific for a language * * @author Mykhaylo Boychuk (at 4science.it) */ @@ -36,20 +38,17 @@ public void init(FilterConfig filterConfig) throws ServletException { @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { - chain.doFilter(request, response); - HttpServletResponse httpServletResponse = (HttpServletResponse) response; - if (!httpServletResponse.containsHeader("Content-Language")) { - Locale[] locales = I18nUtil.getSupportedLocales(); - StringBuilder locsStr = new StringBuilder(); - for (Locale locale : locales) { - if (locsStr.length() > 0) { - locsStr.append(","); - } - locsStr.append(locale.getLanguage()); + Locale[] locales = I18nUtil.getSupportedLocales(); + StringBuilder locsStr = new StringBuilder(); + for (Locale locale : locales) { + if (locsStr.length() > 0) { + locsStr.append(","); } - httpServletResponse.setHeader("Content-Language", locsStr.toString()); + locsStr.append(locale.getLanguage()); } + httpServletResponse.setHeader("Content-Language", locsStr.toString()); + chain.doFilter(request, response); } @Override diff --git a/dspace-server-webapp/src/test/java/org/dspace/app/rest/LanguageSupportIT.java b/dspace-server-webapp/src/test/java/org/dspace/app/rest/LanguageSupportIT.java index 2dc06eca8b73..cc8af92e2b54 100644 --- a/dspace-server-webapp/src/test/java/org/dspace/app/rest/LanguageSupportIT.java +++ b/dspace-server-webapp/src/test/java/org/dspace/app/rest/LanguageSupportIT.java @@ -18,6 +18,7 @@ import org.dspace.core.LegacyPluginServiceImpl; import org.dspace.eperson.EPerson; import org.dspace.services.ConfigurationService; +import org.junit.Ignore; import org.junit.Test; import org.springframework.beans.factory.annotation.Autowired; @@ -42,6 +43,8 @@ public void checkDefaultLanguageAnonymousTest() throws Exception { } @Test + @Ignore("This test fails due to a bug in the MockHttpResponseServlet," + + " see https://github.com/spring-projects/spring-framework/issues/25281") public void checkEnabledMultipleLanguageSupportTest() throws Exception { context.turnOffAuthorisationSystem(); String[] supportedLanguage = {"uk","it"}; @@ -75,7 +78,7 @@ public void checkEnabledMultipleLanguageSupportTest() throws Exception { .andExpect(header().stringValues("Content-Language","uk, it")); getClient(tokenEPersonFR).perform(get("/api").locale(it)) - .andExpect(header().stringValues("Content-Language","en")); + .andExpect(header().stringValues("Content-Language","uk, it")); configurationService.setProperty("webui.supported.locales",null); legacyPluginService.clearNamedPluginClasses(); From c23a5b64de597dc78212522b775289e530470ea2 Mon Sep 17 00:00:00 2001 From: Andrea Bollini Date: Fri, 19 Jun 2020 09:35:40 +0200 Subject: [PATCH 10/33] Improve error handling and test env clenaup --- .../SubmissionUploadRestRepository.java | 35 +++++++++++++++---- .../app/rest/SubmissionFormsControllerIT.java | 11 +++--- 2 files changed, 35 insertions(+), 11 deletions(-) diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/SubmissionUploadRestRepository.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/SubmissionUploadRestRepository.java index a359a7ec4f73..25ac640d49cd 100644 --- a/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/SubmissionUploadRestRepository.java +++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/SubmissionUploadRestRepository.java @@ -7,6 +7,8 @@ */ package org.dspace.app.rest.repository; +import java.sql.SQLException; +import java.text.ParseException; import java.util.ArrayList; import java.util.Collection; import java.util.List; @@ -89,20 +91,31 @@ public Class getDomainClass() { return SubmissionUploadRest.class; } - private SubmissionUploadRest convert(Context context, UploadConfiguration config, Projection projection) - throws Exception { + private SubmissionUploadRest convert(Context context, UploadConfiguration config, Projection projection) { SubmissionUploadRest result = new SubmissionUploadRest(); result.setProjection(projection); for (AccessConditionOption option : config.getOptions()) { AccessConditionOptionRest optionRest = new AccessConditionOptionRest(); if (option.getGroupName() != null) { - Group group = groupService.findByName(context, option.getGroupName()); + Group group; + try { + group = groupService.findByName(context, option.getGroupName()); + } catch (SQLException e) { + throw new IllegalStateException("Wrong group name configuration for the access condition " + + "option named " + option.getName()); + } if (group != null) { optionRest.setGroupUUID(group.getID()); } } if (option.getSelectGroupName() != null) { - Group group = groupService.findByName(context, option.getSelectGroupName()); + Group group; + try { + group = groupService.findByName(context, option.getSelectGroupName()); + } catch (SQLException e) { + throw new IllegalStateException("Wrong select group name configuration for the access condition " + + "option named " + option.getName()); + } if (group != null) { optionRest.setSelectGroupUUID(group.getID()); } @@ -110,10 +123,20 @@ private SubmissionUploadRest convert(Context context, UploadConfiguration config optionRest.setHasStartDate(option.getHasStartDate()); optionRest.setHasEndDate(option.getHasEndDate()); if (StringUtils.isNotBlank(option.getStartDateLimit())) { - optionRest.setMaxStartDate(dateMathParser.parseMath(option.getStartDateLimit())); + try { + optionRest.setMaxStartDate(dateMathParser.parseMath(option.getStartDateLimit())); + } catch (ParseException e) { + throw new IllegalStateException("Wrong start date limit configuration for the access condition " + + "option named " + option.getName()); + } } if (StringUtils.isNotBlank(option.getEndDateLimit())) { - optionRest.setMaxEndDate(dateMathParser.parseMath(option.getEndDateLimit())); + try { + optionRest.setMaxEndDate(dateMathParser.parseMath(option.getEndDateLimit())); + } catch (ParseException e) { + throw new IllegalStateException("Wrong end date limit configuration for the access condition " + + "option named " + option.getName()); + } } optionRest.setName(option.getName()); result.getAccessConditionOptions().add(optionRest); diff --git a/dspace-server-webapp/src/test/java/org/dspace/app/rest/SubmissionFormsControllerIT.java b/dspace-server-webapp/src/test/java/org/dspace/app/rest/SubmissionFormsControllerIT.java index 235764eccdc2..53c41c62d434 100644 --- a/dspace-server-webapp/src/test/java/org/dspace/app/rest/SubmissionFormsControllerIT.java +++ b/dspace-server-webapp/src/test/java/org/dspace/app/rest/SubmissionFormsControllerIT.java @@ -258,7 +258,7 @@ public void languageSupportTest() throws Exception { + " Як що вмiст вайлу не є текстовим, наприклад є фотографiєю, тодi вибрати (N/A)", "dc.language.iso")))); - resetPropertyFile(); + resetLocalesConfiguration(); } @Test @@ -331,7 +331,7 @@ public void preferLanguageTest() throws Exception { + " Як що вмiст вайлу не є текстовим, наприклад є фотографiєю, тодi вибрати (N/A)", "dc.language.iso")))); - resetPropertyFile(); + resetLocalesConfiguration(); } @Test @@ -377,7 +377,7 @@ public void userChoiceAnotherLanguageTest() throws Exception { + " Se il contenuto non ha davvero una lingua" + " (ad esempio, se è un set di dati o un'immagine) selezionare (N/A)", "dc.language.iso")))); - resetPropertyFile(); + resetLocalesConfiguration(); } @Test @@ -408,10 +408,11 @@ public void defaultLanguageTest() throws Exception { "\u00C8 necessario inserire un titolo principale per questo item", false, "Inserisci titolo principale di questo item", "dc.title")))); - resetPropertyFile(); + resetLocalesConfiguration(); } - private void resetPropertyFile() throws DCInputsReaderException { + private void resetLocalesConfiguration() throws DCInputsReaderException { + configurationService.setProperty("default.locale","en"); configurationService.setProperty("webui.supported.locales",null); submissionFormRestRepository.reload(); } From ffad77b43bbd07699c25e48ce1d39e3971c4bd5d Mon Sep 17 00:00:00 2001 From: Danilo Di Nuzzo Date: Mon, 22 Jun 2020 17:20:22 +0200 Subject: [PATCH 11/33] [CST-2877] fix submission multi-lang --- .../main/java/org/dspace/core/Context.java | 23 +++++++++++++++++++ .../AbstractDSpaceRestRepository.java | 22 ++++++++++++++---- .../SubmissionFormRestRepository.java | 14 +++++++---- 3 files changed, 50 insertions(+), 9 deletions(-) diff --git a/dspace-api/src/main/java/org/dspace/core/Context.java b/dspace-api/src/main/java/org/dspace/core/Context.java index 11e388c727ff..3ede4ab5a04f 100644 --- a/dspace-api/src/main/java/org/dspace/core/Context.java +++ b/dspace-api/src/main/java/org/dspace/core/Context.java @@ -68,6 +68,13 @@ public class Context implements AutoCloseable { */ private Locale currentLocale; + /** + * List of locale object indicating the locales that are + * acceptable to the client based on the Accept-Language header. + * The Locales are in decreasing order starting with the preferred locale. + */ + private List clientLocales; + /** * Extra log info */ @@ -876,4 +883,20 @@ public Set getCachedAllMemberGroupsSet(EPerson ePerson) { private void reloadContextBoundEntities() throws SQLException { currentUser = reloadEntity(currentUser); } + + /** + * Returns a list of locale object indicating the locales that are + * acceptable to the client based on the Accept-Language header. + * The Locales are in decreasing order starting with the preferred locale. + * @return List + */ + public List getClientLocales() { + return clientLocales; + } + + + public void setClientLocales(List clientLocales) { + this.clientLocales = clientLocales; + } + } diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/AbstractDSpaceRestRepository.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/AbstractDSpaceRestRepository.java index 7f815ea8f2cc..57650fa9050a 100644 --- a/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/AbstractDSpaceRestRepository.java +++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/AbstractDSpaceRestRepository.java @@ -7,9 +7,11 @@ */ package org.dspace.app.rest.repository; +import java.util.ArrayList; +import java.util.Enumeration; +import java.util.List; import java.util.Locale; -import org.apache.commons.lang3.StringUtils; import org.dspace.app.rest.converter.ConverterService; import org.dspace.app.rest.utils.ContextUtil; import org.dspace.app.rest.utils.Utils; @@ -42,6 +44,7 @@ protected Context obtainContext() { context = ContextUtil.obtainContext(currentRequest.getServletRequest()); Locale currentLocale = getLocal(context, currentRequest); context.setCurrentLocale(currentLocale); + context.setClientLocales(getLocalesFromRequest(currentRequest)); return context; } @@ -58,9 +61,9 @@ private Locale getLocal(Context context, Request request) { userLocale = new Locale(userLanguage); } } - String locale = request.getHttpServletRequest().getHeader("Accept-Language"); - if (StringUtils.isNotBlank(locale)) { - userLocale = new Locale(locale); + Enumeration locales = request.getHttpServletRequest().getLocales(); + if (locales != null) { + userLocale = locales.nextElement(); } if (userLocale == null) { return I18nUtil.getDefaultLocale(); @@ -68,4 +71,15 @@ private Locale getLocal(Context context, Request request) { supportedLocale = I18nUtil.getSupportedLocale(userLocale); return supportedLocale; } + + private List getLocalesFromRequest(Request request) { + List locales = new ArrayList<>(); + Enumeration reqLocales = request.getHttpServletRequest().getLocales(); + if (reqLocales != null) { + while (reqLocales.hasMoreElements()) { + locales.add(reqLocales.nextElement()); + } + } + return locales; + } } diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/SubmissionFormRestRepository.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/SubmissionFormRestRepository.java index 434a8dc0fd3d..107084891727 100644 --- a/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/SubmissionFormRestRepository.java +++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/SubmissionFormRestRepository.java @@ -46,11 +46,15 @@ public SubmissionFormRestRepository() throws DCInputsReaderException { @Override public SubmissionFormRest findOne(Context context, String submitName) { try { - Locale currentLocale = context.getCurrentLocale(); - DCInputsReader inputReader; - if (currentLocale != null) { - inputReader = inputReaders.get(currentLocale); - } else { + List clientLocales = context.getClientLocales(); + DCInputsReader inputReader = null; + for (Locale locale: clientLocales) { + inputReader = inputReaders.get(locale); + if (inputReader != null) { + break; + } + } + if (inputReader == null) { inputReader = defaultInputReader; } DCInputSet subConfs = inputReader.getInputsByFormName(submitName); From 8407a2f6888658f01f8485462aff4cf2ea2641ab Mon Sep 17 00:00:00 2001 From: Danilo Di Nuzzo Date: Tue, 23 Jun 2020 11:54:48 +0200 Subject: [PATCH 12/33] [CST-2877] fix --- .../main/java/org/dspace/core/Context.java | 22 ------------------- .../main/java/org/dspace/core/I18nUtil.java | 19 ++++++++++++++++ .../AbstractDSpaceRestRepository.java | 22 +++++++------------ .../SubmissionFormRestRepository.java | 10 ++------- 4 files changed, 29 insertions(+), 44 deletions(-) diff --git a/dspace-api/src/main/java/org/dspace/core/Context.java b/dspace-api/src/main/java/org/dspace/core/Context.java index 3ede4ab5a04f..4ea314e10881 100644 --- a/dspace-api/src/main/java/org/dspace/core/Context.java +++ b/dspace-api/src/main/java/org/dspace/core/Context.java @@ -68,13 +68,6 @@ public class Context implements AutoCloseable { */ private Locale currentLocale; - /** - * List of locale object indicating the locales that are - * acceptable to the client based on the Accept-Language header. - * The Locales are in decreasing order starting with the preferred locale. - */ - private List clientLocales; - /** * Extra log info */ @@ -884,19 +877,4 @@ private void reloadContextBoundEntities() throws SQLException { currentUser = reloadEntity(currentUser); } - /** - * Returns a list of locale object indicating the locales that are - * acceptable to the client based on the Accept-Language header. - * The Locales are in decreasing order starting with the preferred locale. - * @return List - */ - public List getClientLocales() { - return clientLocales; - } - - - public void setClientLocales(List clientLocales) { - this.clientLocales = clientLocales; - } - } diff --git a/dspace-api/src/main/java/org/dspace/core/I18nUtil.java b/dspace-api/src/main/java/org/dspace/core/I18nUtil.java index 0d5e95d04820..d06b1e9bc8a0 100644 --- a/dspace-api/src/main/java/org/dspace/core/I18nUtil.java +++ b/dspace-api/src/main/java/org/dspace/core/I18nUtil.java @@ -381,4 +381,23 @@ public static Locale[] parseLocales(String[] locales) { } return resultList.toArray(new Locale[resultList.size()]); } + + /** + * Check if the input locale is in the list of supported locales + * @param locale + * @return true if locale is supported, false otherwise + */ + public static boolean isSupportedLocale(Locale locale) { + boolean isSupported = false; + Locale[] supportedLocales = getSupportedLocales(); + if (supportedLocales != null) { + for (Locale sLocale: supportedLocales) { + if (locale.getLanguage().equals(sLocale.getLanguage()) ) { + isSupported = true; + break; + } + } + } + return isSupported; + } } diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/AbstractDSpaceRestRepository.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/AbstractDSpaceRestRepository.java index 57650fa9050a..6460424f1cbe 100644 --- a/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/AbstractDSpaceRestRepository.java +++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/AbstractDSpaceRestRepository.java @@ -7,9 +7,7 @@ */ package org.dspace.app.rest.repository; -import java.util.ArrayList; import java.util.Enumeration; -import java.util.List; import java.util.Locale; import org.dspace.app.rest.converter.ConverterService; @@ -44,7 +42,6 @@ protected Context obtainContext() { context = ContextUtil.obtainContext(currentRequest.getServletRequest()); Locale currentLocale = getLocal(context, currentRequest); context.setCurrentLocale(currentLocale); - context.setClientLocales(getLocalesFromRequest(currentRequest)); return context; } @@ -61,9 +58,16 @@ private Locale getLocal(Context context, Request request) { userLocale = new Locale(userLanguage); } } + // Locales requested from client Enumeration locales = request.getHttpServletRequest().getLocales(); if (locales != null) { - userLocale = locales.nextElement(); + while (locales.hasMoreElements()) { + Locale current = locales.nextElement(); + if (I18nUtil.isSupportedLocale(current)) { + userLocale = current; + break; + } + } } if (userLocale == null) { return I18nUtil.getDefaultLocale(); @@ -72,14 +76,4 @@ private Locale getLocal(Context context, Request request) { return supportedLocale; } - private List getLocalesFromRequest(Request request) { - List locales = new ArrayList<>(); - Enumeration reqLocales = request.getHttpServletRequest().getLocales(); - if (reqLocales != null) { - while (reqLocales.hasMoreElements()) { - locales.add(reqLocales.nextElement()); - } - } - return locales; - } } diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/SubmissionFormRestRepository.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/SubmissionFormRestRepository.java index 107084891727..770438e183a0 100644 --- a/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/SubmissionFormRestRepository.java +++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/SubmissionFormRestRepository.java @@ -46,14 +46,8 @@ public SubmissionFormRestRepository() throws DCInputsReaderException { @Override public SubmissionFormRest findOne(Context context, String submitName) { try { - List clientLocales = context.getClientLocales(); - DCInputsReader inputReader = null; - for (Locale locale: clientLocales) { - inputReader = inputReaders.get(locale); - if (inputReader != null) { - break; - } - } + Locale currentLocale = context.getCurrentLocale(); + DCInputsReader inputReader = inputReaders.get(currentLocale); if (inputReader == null) { inputReader = defaultInputReader; } From 2271237bc6729ad6508f7482e7fe6f67c5919d6e Mon Sep 17 00:00:00 2001 From: Andrea Bollini Date: Mon, 29 Jun 2020 23:48:37 +0200 Subject: [PATCH 13/33] Add javadoc for the reload method --- .../app/rest/repository/SubmissionFormRestRepository.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/SubmissionFormRestRepository.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/SubmissionFormRestRepository.java index 770438e183a0..76d680cf276d 100644 --- a/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/SubmissionFormRestRepository.java +++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/SubmissionFormRestRepository.java @@ -86,6 +86,13 @@ public Class getDomainClass() { return SubmissionFormRest.class; } + /** + * Reload the current Submission Form configuration based on the currently + * supported locales. This method can be used to force a reload if the + * configured supported locales change. + * + * @throws DCInputsReaderException + */ public void reload() throws DCInputsReaderException { this.defaultInputReader = new DCInputsReader(); Locale[] locales = I18nUtil.getSupportedLocales(); From 8c35f6d8a36d199b0b16f6843f2071ec6497e1c6 Mon Sep 17 00:00:00 2001 From: Andrea Bollini Date: Wed, 1 Jul 2020 12:32:32 +0200 Subject: [PATCH 14/33] DS-3679 improved test to show the bug with auth session --- .../services/email/EmailServiceImplTest.java | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/dspace-services/src/test/java/org/dspace/services/email/EmailServiceImplTest.java b/dspace-services/src/test/java/org/dspace/services/email/EmailServiceImplTest.java index 0be0bfe81e43..958e4f810641 100644 --- a/dspace-services/src/test/java/org/dspace/services/email/EmailServiceImplTest.java +++ b/dspace-services/src/test/java/org/dspace/services/email/EmailServiceImplTest.java @@ -10,6 +10,7 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; import javax.mail.MessagingException; import javax.mail.PasswordAuthentication; @@ -65,11 +66,42 @@ public void testGetSession() // Try to get a Session session = instance.getSession(); assertNotNull(" getSession returned null", session); + assertNull(" getSession returned authenticated session", + session.getProperties().getProperty("mail.smtp.auth")); } private static final String CFG_USERNAME = "mail.server.username"; private static final String CFG_PASSWORD = "mail.server.password"; + /** + * Test of testGetSession method, of class EmailServiceImpl when an smtp + * username is provided. + */ + @Test + public void testGetAuthenticatedInstance() { + System.out.println("getSession"); + ConfigurationService cfg = getKernel().getConfigurationService(); + + // Save existing values. + String oldUsername = cfg.getProperty(CFG_USERNAME); + String oldPassword = cfg.getProperty(CFG_PASSWORD); + + // Set known values. + cfg.setProperty(CFG_USERNAME, USERNAME); + cfg.setProperty(CFG_PASSWORD, PASSWORD); + + EmailServiceImpl instance = (EmailServiceImpl) getService(EmailServiceImpl.class); + instance.reset(); + assertNotNull(" getSession returned null", instance); + assertEquals(" authenticated session ", "true", + instance.getSession().getProperties().getProperty("mail.smtp.auth")); + + // Restore old values, if any. + cfg.setProperty(CFG_USERNAME, oldUsername); + cfg.setProperty(CFG_PASSWORD, oldPassword); + instance.reset(); + } + /** * Test of getPasswordAuthentication method, of class EmailServiceImpl. */ From fe051662528f0f186a5f88c21a1ef01bca4bbb2d Mon Sep 17 00:00:00 2001 From: Andrea Bollini Date: Wed, 1 Jul 2020 12:34:09 +0200 Subject: [PATCH 15/33] DS-3679 fix check for blank username --- .../org/dspace/services/email/EmailServiceImpl.java | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/dspace-services/src/main/java/org/dspace/services/email/EmailServiceImpl.java b/dspace-services/src/main/java/org/dspace/services/email/EmailServiceImpl.java index f20458f51ac3..d4f78514255a 100644 --- a/dspace-services/src/main/java/org/dspace/services/email/EmailServiceImpl.java +++ b/dspace-services/src/main/java/org/dspace/services/email/EmailServiceImpl.java @@ -16,6 +16,7 @@ import javax.naming.NamingException; import javax.naming.NoInitialContextException; +import org.apache.commons.lang3.StringUtils; import org.dspace.kernel.mixins.InitializedService; import org.dspace.services.ConfigurationService; import org.dspace.services.EmailService; @@ -106,7 +107,7 @@ public void init() { props.put(key, value); } } - if (null == cfg.getProperty("mail.server.username")) { + if (StringUtils.isBlank(cfg.getProperty("mail.server.username"))) { session = Session.getInstance(props); } else { props.put("mail.smtp.auth", "true"); @@ -125,4 +126,12 @@ protected PasswordAuthentication getPasswordAuthentication() { cfg.getProperty("mail.server.username"), cfg.getProperty("mail.server.password")); } + + /** + * Force a new initialization of the session, useful for testing purpose + */ + public void reset() { + session = null; + init(); + } } From 861170a179591ee0cc78e75c430caab1cd6219c3 Mon Sep 17 00:00:00 2001 From: Mykhaylo Date: Thu, 2 Jul 2020 19:55:53 +0200 Subject: [PATCH 16/33] added test and fix getLocale --- .../AbstractDSpaceRestRepository.java | 33 +++++++++++-------- .../app/rest/SubmissionFormsControllerIT.java | 31 +++++++++++++++++ 2 files changed, 50 insertions(+), 14 deletions(-) diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/AbstractDSpaceRestRepository.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/AbstractDSpaceRestRepository.java index 6460424f1cbe..f5ef7037000c 100644 --- a/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/AbstractDSpaceRestRepository.java +++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/AbstractDSpaceRestRepository.java @@ -10,6 +10,7 @@ import java.util.Enumeration; import java.util.Locale; +import org.apache.commons.lang3.StringUtils; import org.dspace.app.rest.converter.ConverterService; import org.dspace.app.rest.utils.ContextUtil; import org.dspace.app.rest.utils.Utils; @@ -40,7 +41,7 @@ protected Context obtainContext() { Context context = null; Request currentRequest = requestService.getCurrentRequest(); context = ContextUtil.obtainContext(currentRequest.getServletRequest()); - Locale currentLocale = getLocal(context, currentRequest); + Locale currentLocale = getLocale(context, currentRequest); context.setCurrentLocale(currentLocale); return context; } @@ -49,26 +50,30 @@ public RequestService getRequestService() { return requestService; } - private Locale getLocal(Context context, Request request) { + private Locale getLocale(Context context, Request request) { Locale userLocale = null; Locale supportedLocale = null; - if (context.getCurrentUser() != null) { + + // Locales requested from client + String locale = request.getHttpServletRequest().getHeader("Accept-Language"); + if (StringUtils.isNotBlank(locale)) { + Enumeration locales = request.getHttpServletRequest().getLocales(); + if (locales != null) { + while (locales.hasMoreElements()) { + Locale current = locales.nextElement(); + if (I18nUtil.isSupportedLocale(current)) { + userLocale = current; + break; + } + } + } + } + if (userLocale == null && context.getCurrentUser() != null) { String userLanguage = context.getCurrentUser().getLanguage(); if (userLanguage != null) { userLocale = new Locale(userLanguage); } } - // Locales requested from client - Enumeration locales = request.getHttpServletRequest().getLocales(); - if (locales != null) { - while (locales.hasMoreElements()) { - Locale current = locales.nextElement(); - if (I18nUtil.isSupportedLocale(current)) { - userLocale = current; - break; - } - } - } if (userLocale == null) { return I18nUtil.getDefaultLocale(); } diff --git a/dspace-server-webapp/src/test/java/org/dspace/app/rest/SubmissionFormsControllerIT.java b/dspace-server-webapp/src/test/java/org/dspace/app/rest/SubmissionFormsControllerIT.java index 53c41c62d434..4eee3579ee34 100644 --- a/dspace-server-webapp/src/test/java/org/dspace/app/rest/SubmissionFormsControllerIT.java +++ b/dspace-server-webapp/src/test/java/org/dspace/app/rest/SubmissionFormsControllerIT.java @@ -411,6 +411,37 @@ public void defaultLanguageTest() throws Exception { resetLocalesConfiguration(); } + @Test + public void supportLanguageUsingMultipleLocaleTest() throws Exception { + context.turnOffAuthorisationSystem(); + String[] supportedLanguage = {"it","uk","en"}; + configurationService.setProperty("default.locale","en"); + configurationService.setProperty("webui.supported.locales",supportedLanguage); + submissionFormRestRepository.reload(); + + context.restoreAuthSystemState(); + + String tokenEperson = getAuthToken(eperson.getEmail(), password); + getClient(tokenEperson).perform(get("/api/config/submissionforms/languagetest") + .header("Accept-Language", "fr;q=1, it;q=0.9")) + .andExpect(status().isOk()) + .andExpect(content().contentType(contentType)) + .andExpect(jsonPath("$.id", is("languagetest"))) + .andExpect(jsonPath("$.name", is("languagetest"))) + .andExpect(jsonPath("$.type", is("submissionform"))) + .andExpect(jsonPath("$._links.self.href", Matchers + .startsWith(REST_SERVER_URL + "config/submissionforms/languagetest"))) + .andExpect(jsonPath("$.rows[0].fields", contains(SubmissionFormFieldMatcher + .matchFormFieldDefinition("name", "Autore", "\u00C8 richiesto almeno un autore", true, + "Aggiungi un autore", "dc.contributor.author")))) + .andExpect(jsonPath("$.rows[1].fields", contains(SubmissionFormFieldMatcher + .matchFormFieldDefinition("onebox", "Titolo", + "\u00C8 necessario inserire un titolo principale per questo item", false, + "Inserisci titolo principale di questo item", "dc.title")))); + + resetLocalesConfiguration(); + } + private void resetLocalesConfiguration() throws DCInputsReaderException { configurationService.setProperty("default.locale","en"); configurationService.setProperty("webui.supported.locales",null); From dc2151209a18c5ad112c48301d5cd68267708b8e Mon Sep 17 00:00:00 2001 From: Tim Donohue Date: Thu, 2 Jul 2020 14:21:56 -0500 Subject: [PATCH 17/33] [maven-release-plugin] prepare release dspace-7.0-beta3 --- dspace-api/pom.xml | 2 +- dspace-oai/pom.xml | 2 +- dspace-rdf/pom.xml | 2 +- dspace-rest/pom.xml | 4 ++-- dspace-server-webapp/pom.xml | 2 +- dspace-services/pom.xml | 2 +- dspace-sword/pom.xml | 2 +- dspace-swordv2/pom.xml | 2 +- dspace/modules/additions/pom.xml | 4 ++-- dspace/modules/pom.xml | 2 +- dspace/modules/rest/pom.xml | 2 +- dspace/modules/server/pom.xml | 4 ++-- dspace/pom.xml | 2 +- pom.xml | 26 +++++++++++++------------- 14 files changed, 29 insertions(+), 29 deletions(-) diff --git a/dspace-api/pom.xml b/dspace-api/pom.xml index a0714c04eecb..6571b5f6b181 100644 --- a/dspace-api/pom.xml +++ b/dspace-api/pom.xml @@ -12,7 +12,7 @@ org.dspace dspace-parent - 7.0-beta3-SNAPSHOT + 7.0-beta3 .. diff --git a/dspace-oai/pom.xml b/dspace-oai/pom.xml index d5a129c90afc..137c99096901 100644 --- a/dspace-oai/pom.xml +++ b/dspace-oai/pom.xml @@ -8,7 +8,7 @@ dspace-parent org.dspace - 7.0-beta3-SNAPSHOT + 7.0-beta3 .. diff --git a/dspace-rdf/pom.xml b/dspace-rdf/pom.xml index 47fc5cd204f1..3a3bfe833c35 100644 --- a/dspace-rdf/pom.xml +++ b/dspace-rdf/pom.xml @@ -9,7 +9,7 @@ org.dspace dspace-parent - 7.0-beta3-SNAPSHOT + 7.0-beta3 .. diff --git a/dspace-rest/pom.xml b/dspace-rest/pom.xml index 1038617b49b8..45694cd2d43f 100644 --- a/dspace-rest/pom.xml +++ b/dspace-rest/pom.xml @@ -3,7 +3,7 @@ org.dspace dspace-rest war - 7.0-beta3-SNAPSHOT + 7.0-beta3 DSpace (Deprecated) REST Webapp DSpace RESTful Web Services API. NOTE: this REST API is DEPRECATED. Please consider using the REST API in the dspace-server-webapp instead! @@ -12,7 +12,7 @@ org.dspace dspace-parent - 7.0-beta3-SNAPSHOT + 7.0-beta3 .. diff --git a/dspace-server-webapp/pom.xml b/dspace-server-webapp/pom.xml index d8cc6a758742..6f04013c310a 100644 --- a/dspace-server-webapp/pom.xml +++ b/dspace-server-webapp/pom.xml @@ -15,7 +15,7 @@ org.dspace dspace-parent - 7.0-beta3-SNAPSHOT + 7.0-beta3 .. diff --git a/dspace-services/pom.xml b/dspace-services/pom.xml index 1670c8454f2e..b1d92238e1d2 100644 --- a/dspace-services/pom.xml +++ b/dspace-services/pom.xml @@ -9,7 +9,7 @@ org.dspace dspace-parent - 7.0-beta3-SNAPSHOT + 7.0-beta3 diff --git a/dspace-sword/pom.xml b/dspace-sword/pom.xml index 7bb709932ac1..3d56f3541eb3 100644 --- a/dspace-sword/pom.xml +++ b/dspace-sword/pom.xml @@ -15,7 +15,7 @@ org.dspace dspace-parent - 7.0-beta3-SNAPSHOT + 7.0-beta3 .. diff --git a/dspace-swordv2/pom.xml b/dspace-swordv2/pom.xml index 934eae36823e..cb92dcab9105 100644 --- a/dspace-swordv2/pom.xml +++ b/dspace-swordv2/pom.xml @@ -13,7 +13,7 @@ org.dspace dspace-parent - 7.0-beta3-SNAPSHOT + 7.0-beta3 .. diff --git a/dspace/modules/additions/pom.xml b/dspace/modules/additions/pom.xml index 0c05de84a478..e34a74064261 100644 --- a/dspace/modules/additions/pom.xml +++ b/dspace/modules/additions/pom.xml @@ -17,7 +17,7 @@ org.dspace modules - 7.0-beta3-SNAPSHOT + 7.0-beta3 .. @@ -158,7 +158,7 @@ org.dspace dspace-api - 7.0-beta3-SNAPSHOT + 7.0-beta3 test-jar test diff --git a/dspace/modules/pom.xml b/dspace/modules/pom.xml index 84c685a98129..c5951c13d3d7 100644 --- a/dspace/modules/pom.xml +++ b/dspace/modules/pom.xml @@ -11,7 +11,7 @@ org.dspace dspace-parent - 7.0-beta3-SNAPSHOT + 7.0-beta3 ../../pom.xml diff --git a/dspace/modules/rest/pom.xml b/dspace/modules/rest/pom.xml index a17ff70f80a4..ba0dd1b45d91 100644 --- a/dspace/modules/rest/pom.xml +++ b/dspace/modules/rest/pom.xml @@ -13,7 +13,7 @@ org.dspace modules - 7.0-beta3-SNAPSHOT + 7.0-beta3 .. diff --git a/dspace/modules/server/pom.xml b/dspace/modules/server/pom.xml index 06d466f5222d..78600f0f0c4a 100644 --- a/dspace/modules/server/pom.xml +++ b/dspace/modules/server/pom.xml @@ -13,7 +13,7 @@ just adding new jar in the classloader modules org.dspace - 7.0-beta3-SNAPSHOT + 7.0-beta3 .. @@ -194,7 +194,7 @@ just adding new jar in the classloader org.dspace dspace-server-webapp - 7.0-beta3-SNAPSHOT + 7.0-beta3 test-jar test diff --git a/dspace/pom.xml b/dspace/pom.xml index 6c693eacec46..48e1f0ceb61c 100644 --- a/dspace/pom.xml +++ b/dspace/pom.xml @@ -16,7 +16,7 @@ org.dspace dspace-parent - 7.0-beta3-SNAPSHOT + 7.0-beta3 .. diff --git a/pom.xml b/pom.xml index aa8a8b15dded..a68760ba8866 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ org.dspace dspace-parent pom - 7.0-beta3-SNAPSHOT + 7.0-beta3 DSpace Parent Project DSpace open source software is a turnkey institutional repository application. @@ -848,14 +848,14 @@ org.dspace dspace-rest - 7.0-beta3-SNAPSHOT + 7.0-beta3 jar classes org.dspace dspace-rest - 7.0-beta3-SNAPSHOT + 7.0-beta3 war @@ -1008,50 +1008,50 @@ org.dspace dspace-api - 7.0-beta3-SNAPSHOT + 7.0-beta3 org.dspace.modules additions - 7.0-beta3-SNAPSHOT + 7.0-beta3 org.dspace dspace-sword - 7.0-beta3-SNAPSHOT + 7.0-beta3 org.dspace dspace-swordv2 - 7.0-beta3-SNAPSHOT + 7.0-beta3 org.dspace dspace-oai - 7.0-beta3-SNAPSHOT + 7.0-beta3 org.dspace dspace-services - 7.0-beta3-SNAPSHOT + 7.0-beta3 org.dspace dspace-rdf - 7.0-beta3-SNAPSHOT + 7.0-beta3 org.dspace dspace-server-webapp - 7.0-beta3-SNAPSHOT + 7.0-beta3 jar classes org.dspace dspace-server-webapp - 7.0-beta3-SNAPSHOT + 7.0-beta3 war @@ -1812,7 +1812,7 @@ scm:git:git@github.com:DSpace/DSpace.git scm:git:git@github.com:DSpace/DSpace.git git@github.com:DSpace/DSpace.git - HEAD + dspace-7.0-beta3 From cc7a6c30fd83d153fcd7d5b9af5f4a5454f0c342 Mon Sep 17 00:00:00 2001 From: Tim Donohue Date: Thu, 2 Jul 2020 14:22:06 -0500 Subject: [PATCH 18/33] [maven-release-plugin] prepare for next development iteration --- dspace-api/pom.xml | 2 +- dspace-oai/pom.xml | 2 +- dspace-rdf/pom.xml | 2 +- dspace-rest/pom.xml | 4 ++-- dspace-server-webapp/pom.xml | 2 +- dspace-services/pom.xml | 2 +- dspace-sword/pom.xml | 2 +- dspace-swordv2/pom.xml | 2 +- dspace/modules/additions/pom.xml | 4 ++-- dspace/modules/pom.xml | 2 +- dspace/modules/rest/pom.xml | 2 +- dspace/modules/server/pom.xml | 4 ++-- dspace/pom.xml | 2 +- pom.xml | 26 +++++++++++++------------- 14 files changed, 29 insertions(+), 29 deletions(-) diff --git a/dspace-api/pom.xml b/dspace-api/pom.xml index 6571b5f6b181..49ca062aa665 100644 --- a/dspace-api/pom.xml +++ b/dspace-api/pom.xml @@ -12,7 +12,7 @@ org.dspace dspace-parent - 7.0-beta3 + 7.0-beta4-SNAPSHOT .. diff --git a/dspace-oai/pom.xml b/dspace-oai/pom.xml index 137c99096901..4036348be0ce 100644 --- a/dspace-oai/pom.xml +++ b/dspace-oai/pom.xml @@ -8,7 +8,7 @@ dspace-parent org.dspace - 7.0-beta3 + 7.0-beta4-SNAPSHOT .. diff --git a/dspace-rdf/pom.xml b/dspace-rdf/pom.xml index 3a3bfe833c35..4287188c8efc 100644 --- a/dspace-rdf/pom.xml +++ b/dspace-rdf/pom.xml @@ -9,7 +9,7 @@ org.dspace dspace-parent - 7.0-beta3 + 7.0-beta4-SNAPSHOT .. diff --git a/dspace-rest/pom.xml b/dspace-rest/pom.xml index 45694cd2d43f..744ee24203a4 100644 --- a/dspace-rest/pom.xml +++ b/dspace-rest/pom.xml @@ -3,7 +3,7 @@ org.dspace dspace-rest war - 7.0-beta3 + 7.0-beta4-SNAPSHOT DSpace (Deprecated) REST Webapp DSpace RESTful Web Services API. NOTE: this REST API is DEPRECATED. Please consider using the REST API in the dspace-server-webapp instead! @@ -12,7 +12,7 @@ org.dspace dspace-parent - 7.0-beta3 + 7.0-beta4-SNAPSHOT .. diff --git a/dspace-server-webapp/pom.xml b/dspace-server-webapp/pom.xml index 6f04013c310a..d1f54fd9d6f0 100644 --- a/dspace-server-webapp/pom.xml +++ b/dspace-server-webapp/pom.xml @@ -15,7 +15,7 @@ org.dspace dspace-parent - 7.0-beta3 + 7.0-beta4-SNAPSHOT .. diff --git a/dspace-services/pom.xml b/dspace-services/pom.xml index b1d92238e1d2..95ab75f52ee8 100644 --- a/dspace-services/pom.xml +++ b/dspace-services/pom.xml @@ -9,7 +9,7 @@ org.dspace dspace-parent - 7.0-beta3 + 7.0-beta4-SNAPSHOT diff --git a/dspace-sword/pom.xml b/dspace-sword/pom.xml index 3d56f3541eb3..4b28f091db39 100644 --- a/dspace-sword/pom.xml +++ b/dspace-sword/pom.xml @@ -15,7 +15,7 @@ org.dspace dspace-parent - 7.0-beta3 + 7.0-beta4-SNAPSHOT .. diff --git a/dspace-swordv2/pom.xml b/dspace-swordv2/pom.xml index cb92dcab9105..e0642eaa0b6c 100644 --- a/dspace-swordv2/pom.xml +++ b/dspace-swordv2/pom.xml @@ -13,7 +13,7 @@ org.dspace dspace-parent - 7.0-beta3 + 7.0-beta4-SNAPSHOT .. diff --git a/dspace/modules/additions/pom.xml b/dspace/modules/additions/pom.xml index e34a74064261..59ba279c3f71 100644 --- a/dspace/modules/additions/pom.xml +++ b/dspace/modules/additions/pom.xml @@ -17,7 +17,7 @@ org.dspace modules - 7.0-beta3 + 7.0-beta4-SNAPSHOT .. @@ -158,7 +158,7 @@ org.dspace dspace-api - 7.0-beta3 + 7.0-beta4-SNAPSHOT test-jar test diff --git a/dspace/modules/pom.xml b/dspace/modules/pom.xml index c5951c13d3d7..a875a17ca9a4 100644 --- a/dspace/modules/pom.xml +++ b/dspace/modules/pom.xml @@ -11,7 +11,7 @@ org.dspace dspace-parent - 7.0-beta3 + 7.0-beta4-SNAPSHOT ../../pom.xml diff --git a/dspace/modules/rest/pom.xml b/dspace/modules/rest/pom.xml index ba0dd1b45d91..2f1addb2f99b 100644 --- a/dspace/modules/rest/pom.xml +++ b/dspace/modules/rest/pom.xml @@ -13,7 +13,7 @@ org.dspace modules - 7.0-beta3 + 7.0-beta4-SNAPSHOT .. diff --git a/dspace/modules/server/pom.xml b/dspace/modules/server/pom.xml index 78600f0f0c4a..4ecf2cf5b2e2 100644 --- a/dspace/modules/server/pom.xml +++ b/dspace/modules/server/pom.xml @@ -13,7 +13,7 @@ just adding new jar in the classloader modules org.dspace - 7.0-beta3 + 7.0-beta4-SNAPSHOT .. @@ -194,7 +194,7 @@ just adding new jar in the classloader org.dspace dspace-server-webapp - 7.0-beta3 + 7.0-beta4-SNAPSHOT test-jar test diff --git a/dspace/pom.xml b/dspace/pom.xml index 48e1f0ceb61c..f468746b624c 100644 --- a/dspace/pom.xml +++ b/dspace/pom.xml @@ -16,7 +16,7 @@ org.dspace dspace-parent - 7.0-beta3 + 7.0-beta4-SNAPSHOT .. diff --git a/pom.xml b/pom.xml index a68760ba8866..a3b4b30c9836 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ org.dspace dspace-parent pom - 7.0-beta3 + 7.0-beta4-SNAPSHOT DSpace Parent Project DSpace open source software is a turnkey institutional repository application. @@ -848,14 +848,14 @@ org.dspace dspace-rest - 7.0-beta3 + 7.0-beta4-SNAPSHOT jar classes org.dspace dspace-rest - 7.0-beta3 + 7.0-beta4-SNAPSHOT war @@ -1008,50 +1008,50 @@ org.dspace dspace-api - 7.0-beta3 + 7.0-beta4-SNAPSHOT org.dspace.modules additions - 7.0-beta3 + 7.0-beta4-SNAPSHOT org.dspace dspace-sword - 7.0-beta3 + 7.0-beta4-SNAPSHOT org.dspace dspace-swordv2 - 7.0-beta3 + 7.0-beta4-SNAPSHOT org.dspace dspace-oai - 7.0-beta3 + 7.0-beta4-SNAPSHOT org.dspace dspace-services - 7.0-beta3 + 7.0-beta4-SNAPSHOT org.dspace dspace-rdf - 7.0-beta3 + 7.0-beta4-SNAPSHOT org.dspace dspace-server-webapp - 7.0-beta3 + 7.0-beta4-SNAPSHOT jar classes org.dspace dspace-server-webapp - 7.0-beta3 + 7.0-beta4-SNAPSHOT war @@ -1812,7 +1812,7 @@ scm:git:git@github.com:DSpace/DSpace.git scm:git:git@github.com:DSpace/DSpace.git git@github.com:DSpace/DSpace.git - dspace-7.0-beta3 + HEAD From b524c36a53b5d6625fba2c21bc2e3adcd9d28a32 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 2 Jul 2020 19:22:27 +0000 Subject: [PATCH 19/33] Bump commons-beanutils from 1.9.3 to 1.9.4 Bumps commons-beanutils from 1.9.3 to 1.9.4. Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index a3b4b30c9836..b74e76da5cc3 100644 --- a/pom.xml +++ b/pom.xml @@ -1261,7 +1261,7 @@ commons-beanutils commons-beanutils - 1.9.3 + 1.9.4 commons-cli From e52e88004565525c4e501bf943dd5b0fb542911a Mon Sep 17 00:00:00 2001 From: Raf Ponsaerts Date: Tue, 7 Jul 2020 14:39:40 +0200 Subject: [PATCH 20/33] [Task 71690] implemented the IPAuthenticationFilter --- .../rest/security/IPAuthenticationFilter.java | 67 +++++++++++++++++++ .../security/WebSecurityConfiguration.java | 7 +- dspace/config/modules/authentication.cfg | 2 +- 3 files changed, 74 insertions(+), 2 deletions(-) create mode 100644 dspace-server-webapp/src/main/java/org/dspace/app/rest/security/IPAuthenticationFilter.java diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/security/IPAuthenticationFilter.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/security/IPAuthenticationFilter.java new file mode 100644 index 000000000000..e0f4d189c4dc --- /dev/null +++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/security/IPAuthenticationFilter.java @@ -0,0 +1,67 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ +package org.dspace.app.rest.security; + +import java.io.IOException; +import java.sql.SQLException; +import java.util.List; +import javax.servlet.FilterChain; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.apache.log4j.Logger; +import org.dspace.app.rest.utils.ContextUtil; +import org.dspace.authenticate.service.AuthenticationService; +import org.dspace.core.Context; +import org.dspace.eperson.Group; +import org.springframework.security.authentication.AuthenticationManager; +import org.springframework.security.web.authentication.www.BasicAuthenticationFilter; + +/** + * This is a Filter class that'll fetch special groups from the {@link AuthenticationService} and set these in the + * current DSpace Context. This will allow us to set a specific Group to a specific IP so that any request from that + * IP is always treated as being a part of the configured group. + * The configuration for the authentication through ip can be fined in authentication-ip.cfg + * This can be enabled by uncommenting the IPAuhentication plugin in authentication.cfg + */ +public class IPAuthenticationFilter extends BasicAuthenticationFilter { + + private static final Logger log = Logger.getLogger(IPAuthenticationFilter.class); + + private AuthenticationService authenticationService; + + /** + * Constructor for the class + * @param authenticationManager The relevant AuthenticationManager + * @param authenticationService The autowired AuthenticationService + */ + public IPAuthenticationFilter(AuthenticationManager authenticationManager, + AuthenticationService authenticationService) { + super(authenticationManager); + this.authenticationService = authenticationService; + } + + @Override + protected void doFilterInternal(HttpServletRequest req, + HttpServletResponse res, + FilterChain chain) throws IOException, ServletException { + + Context context = ContextUtil.obtainContext(req); + try { + List groups = authenticationService.getSpecialGroups(context, req); + for (Group group : groups) { + context.setSpecialGroup(group.getID()); + } + } catch (SQLException e) { + log.error("Something went wrong trying to fetch groups in IPAuthenticationFilter", e); + } + chain.doFilter(req, res); + } + +} diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/security/WebSecurityConfiguration.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/security/WebSecurityConfiguration.java index 32c0cdda003f..c5b5dff39d93 100644 --- a/dspace-server-webapp/src/main/java/org/dspace/app/rest/security/WebSecurityConfiguration.java +++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/security/WebSecurityConfiguration.java @@ -7,6 +7,7 @@ */ package org.dspace.app.rest.security; +import org.dspace.authenticate.service.AuthenticationService; import org.dspace.services.RequestService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.security.SecurityProperties; @@ -53,6 +54,9 @@ public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter { @Autowired private CustomLogoutHandler customLogoutHandler; + @Autowired + private AuthenticationService authenticationService; + @Override public void configure(WebSecurity webSecurity) throws Exception { webSecurity @@ -103,7 +107,8 @@ protected void configure(HttpSecurity http) throws Exception { //Everyone can call GET on the status endpoint .antMatchers(HttpMethod.GET, "/api/authn/status").permitAll() .and() - + .addFilterBefore(new IPAuthenticationFilter(authenticationManager(), authenticationService), + StatelessAuthenticationFilter.class) //Add a filter before our login endpoints to do the authentication based on the data in the HTTP request .addFilterBefore(new StatelessLoginFilter("/api/authn/login", authenticationManager(), restAuthenticationService), diff --git a/dspace/config/modules/authentication.cfg b/dspace/config/modules/authentication.cfg index f22e2eaf19ae..fab1f577d271 100644 --- a/dspace/config/modules/authentication.cfg +++ b/dspace/config/modules/authentication.cfg @@ -34,7 +34,7 @@ # defining a new order in local.cfg. # IP-based authentication/authorization. See authentication-ip.cfg for default configuration. -#plugin.sequence.org.dspace.authenticate.AuthenticationMethod = org.dspace.authenticate.IPAuthentication +plugin.sequence.org.dspace.authenticate.AuthenticationMethod = org.dspace.authenticate.IPAuthentication # LDAP authentication/authorization. See authentication-ldap.cfg for default configuration. #plugin.sequence.org.dspace.authenticate.AuthenticationMethod = org.dspace.authenticate.LDAPAuthentication From 4e129cf841e7c103b77e488858f46d3a9744f1c3 Mon Sep 17 00:00:00 2001 From: Raf Ponsaerts Date: Wed, 8 Jul 2020 10:23:08 +0200 Subject: [PATCH 21/33] [Task 71753] implemented feedback and added tests for the ip authentication functionality --- .../test/data/dspaceFolder/config/local.cfg | 3 + ...onymousAdditionalAuthorizationFilter.java} | 12 +- .../security/WebSecurityConfiguration.java | 2 +- ...nymousAdditionalAuthorizationFilterIT.java | 144 ++++++++++++++++++ .../AbstractControllerIntegrationTest.java | 17 +++ dspace/config/modules/authentication.cfg | 2 +- 6 files changed, 173 insertions(+), 7 deletions(-) rename dspace-server-webapp/src/main/java/org/dspace/app/rest/security/{IPAuthenticationFilter.java => AnonymousAdditionalAuthorizationFilter.java} (78%) create mode 100644 dspace-server-webapp/src/test/java/org/dspace/app/rest/AnonymousAdditionalAuthorizationFilterIT.java diff --git a/dspace-api/src/test/data/dspaceFolder/config/local.cfg b/dspace-api/src/test/data/dspaceFolder/config/local.cfg index 51ce1a016521..2455c68cfd0f 100644 --- a/dspace-api/src/test/data/dspaceFolder/config/local.cfg +++ b/dspace-api/src/test/data/dspaceFolder/config/local.cfg @@ -120,3 +120,6 @@ rest.properties.exposed = configuration.not.existing configuration.not.exposed = secret_value configuration.exposed.single.value = public_value configuration.exposed.array.value = public_value_1, public_value_2 + +authentication-ip.Staff = 5.5.5.5 +authentication-ip.Student = 6.6.6.6 diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/security/IPAuthenticationFilter.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/security/AnonymousAdditionalAuthorizationFilter.java similarity index 78% rename from dspace-server-webapp/src/main/java/org/dspace/app/rest/security/IPAuthenticationFilter.java rename to dspace-server-webapp/src/main/java/org/dspace/app/rest/security/AnonymousAdditionalAuthorizationFilter.java index e0f4d189c4dc..ef040daf127f 100644 --- a/dspace-server-webapp/src/main/java/org/dspace/app/rest/security/IPAuthenticationFilter.java +++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/security/AnonymousAdditionalAuthorizationFilter.java @@ -25,14 +25,16 @@ /** * This is a Filter class that'll fetch special groups from the {@link AuthenticationService} and set these in the - * current DSpace Context. This will allow us to set a specific Group to a specific IP so that any request from that + * current DSpace Context. It'll do extra processing on anonymous requests to see which authorizations they + * can implicitly have and adds those + * This will allow us to for example set a specific Group to a specific IP so that any request from that * IP is always treated as being a part of the configured group. * The configuration for the authentication through ip can be fined in authentication-ip.cfg * This can be enabled by uncommenting the IPAuhentication plugin in authentication.cfg */ -public class IPAuthenticationFilter extends BasicAuthenticationFilter { +public class AnonymousAdditionalAuthorizationFilter extends BasicAuthenticationFilter { - private static final Logger log = Logger.getLogger(IPAuthenticationFilter.class); + private static final Logger log = Logger.getLogger(AnonymousAdditionalAuthorizationFilter.class); private AuthenticationService authenticationService; @@ -41,8 +43,8 @@ public class IPAuthenticationFilter extends BasicAuthenticationFilter { * @param authenticationManager The relevant AuthenticationManager * @param authenticationService The autowired AuthenticationService */ - public IPAuthenticationFilter(AuthenticationManager authenticationManager, - AuthenticationService authenticationService) { + public AnonymousAdditionalAuthorizationFilter(AuthenticationManager authenticationManager, + AuthenticationService authenticationService) { super(authenticationManager); this.authenticationService = authenticationService; } diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/security/WebSecurityConfiguration.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/security/WebSecurityConfiguration.java index c5b5dff39d93..4471262ef6a5 100644 --- a/dspace-server-webapp/src/main/java/org/dspace/app/rest/security/WebSecurityConfiguration.java +++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/security/WebSecurityConfiguration.java @@ -107,7 +107,7 @@ protected void configure(HttpSecurity http) throws Exception { //Everyone can call GET on the status endpoint .antMatchers(HttpMethod.GET, "/api/authn/status").permitAll() .and() - .addFilterBefore(new IPAuthenticationFilter(authenticationManager(), authenticationService), + .addFilterBefore(new AnonymousAdditionalAuthorizationFilter(authenticationManager(), authenticationService), StatelessAuthenticationFilter.class) //Add a filter before our login endpoints to do the authentication based on the data in the HTTP request .addFilterBefore(new StatelessLoginFilter("/api/authn/login", authenticationManager(), diff --git a/dspace-server-webapp/src/test/java/org/dspace/app/rest/AnonymousAdditionalAuthorizationFilterIT.java b/dspace-server-webapp/src/test/java/org/dspace/app/rest/AnonymousAdditionalAuthorizationFilterIT.java new file mode 100644 index 000000000000..779bbabee873 --- /dev/null +++ b/dspace-server-webapp/src/test/java/org/dspace/app/rest/AnonymousAdditionalAuthorizationFilterIT.java @@ -0,0 +1,144 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ +package org.dspace.app.rest; + +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +import org.dspace.app.rest.builder.CollectionBuilder; +import org.dspace.app.rest.builder.CommunityBuilder; +import org.dspace.app.rest.builder.GroupBuilder; +import org.dspace.app.rest.builder.ItemBuilder; +import org.dspace.app.rest.test.AbstractControllerIntegrationTest; +import org.dspace.content.Collection; +import org.dspace.content.Community; +import org.dspace.content.Item; +import org.dspace.eperson.Group; +import org.dspace.eperson.service.GroupService; +import org.dspace.services.ConfigurationService; +import org.junit.Before; +import org.junit.Test; +import org.springframework.beans.factory.annotation.Autowired; + +public class AnonymousAdditionalAuthorizationFilterIT extends AbstractControllerIntegrationTest { + + @Autowired + private ConfigurationService configurationService; + + @Autowired + private GroupService groupService; + + public static final String[] IP = {"org.dspace.authenticate.IPAuthentication"}; + public static final String[] IP_AND_PASS = + {"org.dspace.authenticate.IPAuthentication", + "org.dspace.authenticate.PasswordAuthentication"}; + public static final String[] PASS = {"org.dspace.authenticate.PasswordAuthentication"}; + + + Item publicItem1; + Group staff; + + @Before + public void setup() { + context.turnOffAuthorisationSystem(); + + //** GIVEN ** + //1. A community-collection structure with one parent community with sub-community and two collections. + parentCommunity = CommunityBuilder.createCommunity(context) + .withName("Parent Community") + .build(); + Community child1 = CommunityBuilder.createSubCommunity(context, parentCommunity) + .withName("Sub Community") + .build(); + Collection col1 = CollectionBuilder.createCollection(context, child1).withName("Collection 1").build(); + + staff = GroupBuilder.createGroup(context).withName("Staff").build(); + + //2. Three public items that are readable by Anonymous with different subjects + publicItem1 = ItemBuilder.createItem(context, col1) + .withTitle("Public item 1") + .withIssueDate("2017-10-17") + .withAuthor("Smith, Donald").withAuthor("Doe, John") + .withSubject("ExtraEntry") + .withReaderGroup(staff) + .build(); + + } + + @Test + public void verifyIPAuthentication() throws Exception { + configurationService.setProperty("plugin.sequence.org.dspace.authenticate.AuthenticationMethod", IP); + + getClient().perform(get("/api/core/items/" + publicItem1.getID())) + .andExpect(status().isUnauthorized()); + + getClient().perform(get("/api/core/items/" + publicItem1.getID()) + .header("X-Forwarded-For", "5.5.5.5")) + .andExpect(status().isOk()); + + getClient().perform(get("/api/core/items/" + publicItem1.getID()) + .header("X-FORWARDED-FOR", "6.6.6.6")) + .andExpect(status().isUnauthorized()); + } + + @Test + public void verifyIPAndPasswordAuthentication() throws Exception { + configurationService.setProperty("plugin.sequence.org.dspace.authenticate.AuthenticationMethod", IP_AND_PASS); + + groupService.addMember(context, staff, eperson); + + getClient().perform(get("/api/core/items/" + publicItem1.getID())) + .andExpect(status().isUnauthorized()); + + getClient().perform(get("/api/core/items/" + publicItem1.getID()) + .header("X-Forwarded-For", "5.5.5.5")) + .andExpect(status().isOk()); + + getClient().perform(get("/api/core/items/" + publicItem1.getID()) + .header("X-Forwarded-For", "6.6.6.6")) + .andExpect(status().isUnauthorized()); + + String token = getAuthToken(eperson.getEmail(), password); + + getClient(token).perform(get("/api/core/items/" + publicItem1.getID())) + .andExpect(status().isOk()); + + getClient(getAuthTokenWithXForwardedForHeader(eperson.getEmail(), password, "6.6.6.6")) + .perform(get("/api/core/items/" + publicItem1.getID()) + .header("X-Forwarded-For", "6.6.6.6")) + .andExpect(status().isOk()); + } + + @Test + public void verifyPasswordAuthentication() throws Exception { + configurationService.setProperty("plugin.sequence.org.dspace.authenticate.AuthenticationMethod", PASS); + + groupService.addMember(context, staff, eperson); + + getClient().perform(get("/api/core/items/" + publicItem1.getID())) + .andExpect(status().isUnauthorized()); + + getClient().perform(get("/api/core/items/" + publicItem1.getID()) + .header("X-Forwarded-For", "5.5.5.5")) + .andExpect(status().isUnauthorized()); + + getClient().perform(get("/api/core/items/" + publicItem1.getID()) + .header("X-Forwarded-For", "6.6.6.6")) + .andExpect(status().isUnauthorized()); + + String token = getAuthToken(eperson.getEmail(), password); + + getClient(token).perform(get("/api/core/items/" + publicItem1.getID())) + .andExpect(status().isOk()); + + getClient(getAuthTokenWithXForwardedForHeader(eperson.getEmail(), password, "6.6.6.6")) + .perform(get("/api/core/items/" + publicItem1.getID()) + .header("X-Forwarded-For", "6.6.6.6")) + .andExpect(status().isOk()); + } +} diff --git a/dspace-server-webapp/src/test/java/org/dspace/app/rest/test/AbstractControllerIntegrationTest.java b/dspace-server-webapp/src/test/java/org/dspace/app/rest/test/AbstractControllerIntegrationTest.java index de9003b2fee6..c470e8a04513 100644 --- a/dspace-server-webapp/src/test/java/org/dspace/app/rest/test/AbstractControllerIntegrationTest.java +++ b/dspace-server-webapp/src/test/java/org/dspace/app/rest/test/AbstractControllerIntegrationTest.java @@ -134,12 +134,29 @@ public MockHttpServletResponse getAuthResponse(String user, String password) thr .andReturn().getResponse(); } + public MockHttpServletResponse getAuthResponseWithXForwardedForHeader(String user, String password, + String xForwardedFor) throws Exception { + return getClient().perform(post("/api/authn/login") + .param("user", user) + .param("password", password) + .header("X-Forwarded-For", xForwardedFor)) + .andReturn().getResponse(); + } + + public String getAuthToken(String user, String password) throws Exception { return StringUtils.substringAfter( getAuthResponse(user, password).getHeader(AUTHORIZATION_HEADER), AUTHORIZATION_TYPE); } + public String getAuthTokenWithXForwardedForHeader(String user, String password, String xForwardedFor) + throws Exception { + return StringUtils.substringAfter( + getAuthResponseWithXForwardedForHeader(user, password, xForwardedFor).getHeader(AUTHORIZATION_HEADER), + AUTHORIZATION_TYPE); + } + public String getPatchContent(List ops) { ObjectMapper objectMapper = new ObjectMapper(); try { diff --git a/dspace/config/modules/authentication.cfg b/dspace/config/modules/authentication.cfg index fab1f577d271..f22e2eaf19ae 100644 --- a/dspace/config/modules/authentication.cfg +++ b/dspace/config/modules/authentication.cfg @@ -34,7 +34,7 @@ # defining a new order in local.cfg. # IP-based authentication/authorization. See authentication-ip.cfg for default configuration. -plugin.sequence.org.dspace.authenticate.AuthenticationMethod = org.dspace.authenticate.IPAuthentication +#plugin.sequence.org.dspace.authenticate.AuthenticationMethod = org.dspace.authenticate.IPAuthentication # LDAP authentication/authorization. See authentication-ldap.cfg for default configuration. #plugin.sequence.org.dspace.authenticate.AuthenticationMethod = org.dspace.authenticate.LDAPAuthentication From 9184189bb09d132dd9d5763943041691553996e2 Mon Sep 17 00:00:00 2001 From: Raf Ponsaerts Date: Wed, 8 Jul 2020 10:32:53 +0200 Subject: [PATCH 22/33] [Task 71690] added javadoc for the tests and config --- .../test/data/dspaceFolder/config/local.cfg | 1 + ...nymousAdditionalAuthorizationFilterIT.java | 20 +++++++++++++++++++ 2 files changed, 21 insertions(+) diff --git a/dspace-api/src/test/data/dspaceFolder/config/local.cfg b/dspace-api/src/test/data/dspaceFolder/config/local.cfg index 2455c68cfd0f..093e1742bb2d 100644 --- a/dspace-api/src/test/data/dspaceFolder/config/local.cfg +++ b/dspace-api/src/test/data/dspaceFolder/config/local.cfg @@ -121,5 +121,6 @@ configuration.not.exposed = secret_value configuration.exposed.single.value = public_value configuration.exposed.array.value = public_value_1, public_value_2 +# Test config for the authentication ip functionality authentication-ip.Staff = 5.5.5.5 authentication-ip.Student = 6.6.6.6 diff --git a/dspace-server-webapp/src/test/java/org/dspace/app/rest/AnonymousAdditionalAuthorizationFilterIT.java b/dspace-server-webapp/src/test/java/org/dspace/app/rest/AnonymousAdditionalAuthorizationFilterIT.java index 779bbabee873..f520df05f40e 100644 --- a/dspace-server-webapp/src/test/java/org/dspace/app/rest/AnonymousAdditionalAuthorizationFilterIT.java +++ b/dspace-server-webapp/src/test/java/org/dspace/app/rest/AnonymousAdditionalAuthorizationFilterIT.java @@ -25,6 +25,9 @@ import org.junit.Test; import org.springframework.beans.factory.annotation.Autowired; +/** + * Testing class for the {@link org.dspace.app.rest.security.AnonymousAdditionalAuthorizationFilter} filter + */ public class AnonymousAdditionalAuthorizationFilterIT extends AbstractControllerIntegrationTest { @Autowired @@ -74,13 +77,16 @@ public void setup() { public void verifyIPAuthentication() throws Exception { configurationService.setProperty("plugin.sequence.org.dspace.authenticate.AuthenticationMethod", IP); + // Make sure that the item is not accessible for anonymous getClient().perform(get("/api/core/items/" + publicItem1.getID())) .andExpect(status().isUnauthorized()); + // Test that we can access the item using the IP that's configured for the Staff group getClient().perform(get("/api/core/items/" + publicItem1.getID()) .header("X-Forwarded-For", "5.5.5.5")) .andExpect(status().isOk()); + // Test that we can't access the item using the IP that's configured for the Students group getClient().perform(get("/api/core/items/" + publicItem1.getID()) .header("X-FORWARDED-FOR", "6.6.6.6")) .andExpect(status().isUnauthorized()); @@ -92,22 +98,28 @@ public void verifyIPAndPasswordAuthentication() throws Exception { groupService.addMember(context, staff, eperson); + // Make sure that the item is not accessible for anonymous getClient().perform(get("/api/core/items/" + publicItem1.getID())) .andExpect(status().isUnauthorized()); + // Test that we can access the item using the IP that's configured for the Staff group getClient().perform(get("/api/core/items/" + publicItem1.getID()) .header("X-Forwarded-For", "5.5.5.5")) .andExpect(status().isOk()); + // Test that we can't access the item using the IP that's configured for the Students group getClient().perform(get("/api/core/items/" + publicItem1.getID()) .header("X-Forwarded-For", "6.6.6.6")) .andExpect(status().isUnauthorized()); String token = getAuthToken(eperson.getEmail(), password); + // Test that the user in the Staff group can access the Item with the normal password authentication getClient(token).perform(get("/api/core/items/" + publicItem1.getID())) .andExpect(status().isOk()); + // Test that the user in the Staff group can access the Item with the normal password authentication even + // when it's IP is configured to be part of the students group getClient(getAuthTokenWithXForwardedForHeader(eperson.getEmail(), password, "6.6.6.6")) .perform(get("/api/core/items/" + publicItem1.getID()) .header("X-Forwarded-For", "6.6.6.6")) @@ -120,22 +132,30 @@ public void verifyPasswordAuthentication() throws Exception { groupService.addMember(context, staff, eperson); + // Make sure that the item is not accessible for anonymous getClient().perform(get("/api/core/items/" + publicItem1.getID())) .andExpect(status().isUnauthorized()); + // Test that the Item can't be accessed with the IP for the Staff group if the config is turned off and only + // allows password authentication getClient().perform(get("/api/core/items/" + publicItem1.getID()) .header("X-Forwarded-For", "5.5.5.5")) .andExpect(status().isUnauthorized()); + // Test that the Item can't be accessed with the IP for the Students group if the config is turned off and only + // allows password authentication getClient().perform(get("/api/core/items/" + publicItem1.getID()) .header("X-Forwarded-For", "6.6.6.6")) .andExpect(status().isUnauthorized()); String token = getAuthToken(eperson.getEmail(), password); + // Test that the Item is accessible for a user in the Staff group by password login getClient(token).perform(get("/api/core/items/" + publicItem1.getID())) .andExpect(status().isOk()); + // Test that the Item is accessible for a user in the Staff group by password Login when the request + // is coming from the IP that's configured to be for the Student group getClient(getAuthTokenWithXForwardedForHeader(eperson.getEmail(), password, "6.6.6.6")) .perform(get("/api/core/items/" + publicItem1.getID()) .header("X-Forwarded-For", "6.6.6.6")) From 62cfd2d5bd98bcc688395a3c7ba89e77df003fb6 Mon Sep 17 00:00:00 2001 From: Raf Ponsaerts Date: Wed, 8 Jul 2020 13:40:47 +0200 Subject: [PATCH 23/33] [Task 71761] applied feedback to the AnonymousAdditionalAuthorizationFilter and IT --- ...nonymousAdditionalAuthorizationFilter.java | 2 +- ...nymousAdditionalAuthorizationFilterIT.java | 30 +++++++++---------- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/security/AnonymousAdditionalAuthorizationFilter.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/security/AnonymousAdditionalAuthorizationFilter.java index ef040daf127f..3087a5850b81 100644 --- a/dspace-server-webapp/src/main/java/org/dspace/app/rest/security/AnonymousAdditionalAuthorizationFilter.java +++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/security/AnonymousAdditionalAuthorizationFilter.java @@ -29,7 +29,7 @@ * can implicitly have and adds those * This will allow us to for example set a specific Group to a specific IP so that any request from that * IP is always treated as being a part of the configured group. - * The configuration for the authentication through ip can be fined in authentication-ip.cfg + * The configuration for the authentication through ip can be found in authentication-ip.cfg * This can be enabled by uncommenting the IPAuhentication plugin in authentication.cfg */ public class AnonymousAdditionalAuthorizationFilter extends BasicAuthenticationFilter { diff --git a/dspace-server-webapp/src/test/java/org/dspace/app/rest/AnonymousAdditionalAuthorizationFilterIT.java b/dspace-server-webapp/src/test/java/org/dspace/app/rest/AnonymousAdditionalAuthorizationFilterIT.java index f520df05f40e..3202bd37c28f 100644 --- a/dspace-server-webapp/src/test/java/org/dspace/app/rest/AnonymousAdditionalAuthorizationFilterIT.java +++ b/dspace-server-webapp/src/test/java/org/dspace/app/rest/AnonymousAdditionalAuthorizationFilterIT.java @@ -43,7 +43,7 @@ public class AnonymousAdditionalAuthorizationFilterIT extends AbstractController public static final String[] PASS = {"org.dspace.authenticate.PasswordAuthentication"}; - Item publicItem1; + Item staffAccessItem1; Group staff; @Before @@ -63,7 +63,7 @@ public void setup() { staff = GroupBuilder.createGroup(context).withName("Staff").build(); //2. Three public items that are readable by Anonymous with different subjects - publicItem1 = ItemBuilder.createItem(context, col1) + staffAccessItem1 = ItemBuilder.createItem(context, col1) .withTitle("Public item 1") .withIssueDate("2017-10-17") .withAuthor("Smith, Donald").withAuthor("Doe, John") @@ -78,16 +78,16 @@ public void verifyIPAuthentication() throws Exception { configurationService.setProperty("plugin.sequence.org.dspace.authenticate.AuthenticationMethod", IP); // Make sure that the item is not accessible for anonymous - getClient().perform(get("/api/core/items/" + publicItem1.getID())) + getClient().perform(get("/api/core/items/" + staffAccessItem1.getID())) .andExpect(status().isUnauthorized()); // Test that we can access the item using the IP that's configured for the Staff group - getClient().perform(get("/api/core/items/" + publicItem1.getID()) + getClient().perform(get("/api/core/items/" + staffAccessItem1.getID()) .header("X-Forwarded-For", "5.5.5.5")) .andExpect(status().isOk()); // Test that we can't access the item using the IP that's configured for the Students group - getClient().perform(get("/api/core/items/" + publicItem1.getID()) + getClient().perform(get("/api/core/items/" + staffAccessItem1.getID()) .header("X-FORWARDED-FOR", "6.6.6.6")) .andExpect(status().isUnauthorized()); } @@ -99,29 +99,29 @@ public void verifyIPAndPasswordAuthentication() throws Exception { groupService.addMember(context, staff, eperson); // Make sure that the item is not accessible for anonymous - getClient().perform(get("/api/core/items/" + publicItem1.getID())) + getClient().perform(get("/api/core/items/" + staffAccessItem1.getID())) .andExpect(status().isUnauthorized()); // Test that we can access the item using the IP that's configured for the Staff group - getClient().perform(get("/api/core/items/" + publicItem1.getID()) + getClient().perform(get("/api/core/items/" + staffAccessItem1.getID()) .header("X-Forwarded-For", "5.5.5.5")) .andExpect(status().isOk()); // Test that we can't access the item using the IP that's configured for the Students group - getClient().perform(get("/api/core/items/" + publicItem1.getID()) + getClient().perform(get("/api/core/items/" + staffAccessItem1.getID()) .header("X-Forwarded-For", "6.6.6.6")) .andExpect(status().isUnauthorized()); String token = getAuthToken(eperson.getEmail(), password); // Test that the user in the Staff group can access the Item with the normal password authentication - getClient(token).perform(get("/api/core/items/" + publicItem1.getID())) + getClient(token).perform(get("/api/core/items/" + staffAccessItem1.getID())) .andExpect(status().isOk()); // Test that the user in the Staff group can access the Item with the normal password authentication even // when it's IP is configured to be part of the students group getClient(getAuthTokenWithXForwardedForHeader(eperson.getEmail(), password, "6.6.6.6")) - .perform(get("/api/core/items/" + publicItem1.getID()) + .perform(get("/api/core/items/" + staffAccessItem1.getID()) .header("X-Forwarded-For", "6.6.6.6")) .andExpect(status().isOk()); } @@ -133,31 +133,31 @@ public void verifyPasswordAuthentication() throws Exception { groupService.addMember(context, staff, eperson); // Make sure that the item is not accessible for anonymous - getClient().perform(get("/api/core/items/" + publicItem1.getID())) + getClient().perform(get("/api/core/items/" + staffAccessItem1.getID())) .andExpect(status().isUnauthorized()); // Test that the Item can't be accessed with the IP for the Staff group if the config is turned off and only // allows password authentication - getClient().perform(get("/api/core/items/" + publicItem1.getID()) + getClient().perform(get("/api/core/items/" + staffAccessItem1.getID()) .header("X-Forwarded-For", "5.5.5.5")) .andExpect(status().isUnauthorized()); // Test that the Item can't be accessed with the IP for the Students group if the config is turned off and only // allows password authentication - getClient().perform(get("/api/core/items/" + publicItem1.getID()) + getClient().perform(get("/api/core/items/" + staffAccessItem1.getID()) .header("X-Forwarded-For", "6.6.6.6")) .andExpect(status().isUnauthorized()); String token = getAuthToken(eperson.getEmail(), password); // Test that the Item is accessible for a user in the Staff group by password login - getClient(token).perform(get("/api/core/items/" + publicItem1.getID())) + getClient(token).perform(get("/api/core/items/" + staffAccessItem1.getID())) .andExpect(status().isOk()); // Test that the Item is accessible for a user in the Staff group by password Login when the request // is coming from the IP that's configured to be for the Student group getClient(getAuthTokenWithXForwardedForHeader(eperson.getEmail(), password, "6.6.6.6")) - .perform(get("/api/core/items/" + publicItem1.getID()) + .perform(get("/api/core/items/" + staffAccessItem1.getID()) .header("X-Forwarded-For", "6.6.6.6")) .andExpect(status().isOk()); } From 61bed89a0c97e0e71c85ef16ff400c6c30310eae Mon Sep 17 00:00:00 2001 From: Tim Donohue Date: Tue, 14 Jul 2020 09:44:14 -0500 Subject: [PATCH 24/33] Rename master to main. Rename whitelist to allow list. --- .github/pull_request_template.md | 2 +- Dockerfile | 2 +- Dockerfile.cli | 2 +- Dockerfile.test | 2 +- README.md | 36 +++++++++---------- .../service/CitationDocumentService.java | 2 +- .../SimpleXpathMetadatumContributor.java | 2 +- .../webapp/WEB-INF/applicationContext.xml | 2 +- .../java/org/dspace/app/rest/Application.java | 4 +-- .../java/org/dspace/app/rest/utils/Utils.java | 2 +- .../crosswalks/google-metadata.properties | 14 ++++---- dspace/src/main/docker-compose/cli.ingest.yml | 2 +- dspace/src/main/docker/README.md | 6 ++-- pom.xml | 2 +- 14 files changed, 40 insertions(+), 40 deletions(-) diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index 3605531adb5b..6542242af760 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -23,5 +23,5 @@ _This checklist provides a reminder of what we are going to look for when review - [ ] My PR passes Checkstyle validation based on the [Code Style Guide](https://wiki.lyrasis.org/display/DSPACE/Code+Style+Guide). - [ ] My PR includes Javadoc for _all new (or modified) public methods and classes_. It also includes Javadoc for large or complex private methods. - [ ] My PR passes all tests and includes new/updated Unit or Integration Tests based on the [Code Testing Guide](https://wiki.lyrasis.org/display/DSPACE/Code+Testing+Guide). -- [ ] If my PR includes new, third-party dependencies (in any `pom.xml`), I've made sure their licenses align with the [DSpace BSD License](https://github.com/DSpace/DSpace/blob/master/LICENSE) based on the [Licensing of Contributions](https://wiki.lyrasis.org/display/DSPACE/Code+Contribution+Guidelines#CodeContributionGuidelines-LicensingofContributions) documentation. +- [ ] If my PR includes new, third-party dependencies (in any `pom.xml`), I've made sure their licenses align with the [DSpace BSD License](https://github.com/DSpace/DSpace/blob/main/LICENSE) based on the [Licensing of Contributions](https://wiki.lyrasis.org/display/DSPACE/Code+Contribution+Guidelines#CodeContributionGuidelines-LicensingofContributions) documentation. - [ ] If my PR modifies the REST API, I've linked to the REST Contract page (or open PR) related to this change. diff --git a/Dockerfile b/Dockerfile index 006f32f28e97..2dc3ee9bda6c 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,5 +1,5 @@ # This image will be published as dspace/dspace -# See https://github.com/DSpace/DSpace/tree/master/dspace/src/main/docker for usage details +# See https://github.com/DSpace/DSpace/tree/main/dspace/src/main/docker for usage details # # This version is JDK11 compatible # - tomcat:8-jdk11 diff --git a/Dockerfile.cli b/Dockerfile.cli index 116b251f2d09..d4204ebdd073 100644 --- a/Dockerfile.cli +++ b/Dockerfile.cli @@ -1,5 +1,5 @@ # This image will be published as dspace/dspace-cli -# See https://github.com/DSpace/DSpace/tree/master/dspace/src/main/docker for usage details +# See https://github.com/DSpace/DSpace/tree/main/dspace/src/main/docker for usage details # # This version is JDK11 compatible # - openjdk:11 diff --git a/Dockerfile.test b/Dockerfile.test index 090f714e288e..82ffdef1777b 100644 --- a/Dockerfile.test +++ b/Dockerfile.test @@ -1,5 +1,5 @@ # This image will be published as dspace/dspace -# See https://github.com/DSpace/DSpace/tree/master/dspace/src/main/docker for usage details +# See https://github.com/DSpace/DSpace/tree/main/dspace/src/main/docker for usage details # # This version is JDK11 compatible # - tomcat:8-jdk11 diff --git a/README.md b/README.md index 49f3814b49a2..1b28c958d4d8 100644 --- a/README.md +++ b/README.md @@ -1,24 +1,24 @@ # DSpace -[![Build Status](https://travis-ci.org/DSpace/DSpace.png?branch=master)](https://travis-ci.org/DSpace/DSpace) +[![Build Status](https://travis-ci.com/DSpace/DSpace.png?branch=main)](https://travis-ci.com/DSpace/DSpace) -[DSpace Documentation](https://wiki.duraspace.org/display/DSDOC/) | +[DSpace Documentation](https://wiki.lyrasis.org/display/DSDOC/) | [DSpace Releases](https://github.com/DSpace/DSpace/releases) | -[DSpace Wiki](https://wiki.duraspace.org/display/DSPACE/Home) | -[Support](https://wiki.duraspace.org/display/DSPACE/Support) +[DSpace Wiki](https://wiki.lyrasis.org/display/DSPACE/Home) | +[Support](https://wiki.lyrasis.org/display/DSPACE/Support) DSpace open source software is a turnkey repository application used by more than 2,000 organizations and institutions worldwide to provide durable access to digital resources. For more information, visit http://www.dspace.org/ *** -:warning: **Work on DSpace 7 has begun on our `master` branch.** This means that there is temporarily NO user interface on this `master` branch. DSpace 7 will feature a new, unified [Angular](https://angular.io/) user interface, along with an enhanced, rebuilt REST API. The latest status of this work can be found on the [DSpace 7 UI Working Group](https://wiki.duraspace.org/display/DSPACE/DSpace+7+UI+Working+Group) page. Additionally, the codebases can be found in the following places: - * DSpace 7 REST API work is occurring on the [`master` branch](https://github.com/DSpace/DSpace/tree/master/dspace-server-webapp) of this repository. - * The REST Contract is being documented at https://github.com/DSpace/Rest7Contract +:warning: **Work on DSpace 7 has begun on our `main` branch.** This means that there is NO user interface on this `main` branch. DSpace 7 will feature a new, unified [Angular](https://angular.io/) user interface, along with an enhanced, rebuilt REST API. The latest status of this work can be found on the [DSpace 7 Working Group](https://wiki.lyrasis.org/display/DSPACE/DSpace+7+Working+Group) page. Additionally, the codebases can be found in the following places: + * DSpace 7 REST API work is occurring on the [`main` branch](https://github.com/DSpace/DSpace/tree/main/dspace-server-webapp) of this repository. + * The REST Contract is at https://github.com/DSpace/Rest7Contract * DSpace 7 Angular UI work is occurring at https://github.com/DSpace/dspace-angular -**If you would like to get involved in our DSpace 7 development effort, we welcome new contributors.** Just join one of our meetings or get in touch via Slack. See the [DSpace 7 UI Working Group](https://wiki.duraspace.org/display/DSPACE/DSpace+7+UI+Working+Group) wiki page for more info. +**If you would like to get involved in our DSpace 7 development effort, we welcome new contributors.** Just join one of our meetings or get in touch via Slack. See the [DSpace 7 Working Group](https://wiki.lyrasis.org/display/DSPACE/DSpace+7+Working+Group) wiki page for more info. **If you are looking for the ongoing maintenance work for DSpace 6 (or prior releases)**, you can find that work on the corresponding maintenance branch (e.g. [`dspace-6_x`](https://github.com/DSpace/DSpace/tree/dspace-6_x)) in this repository. *** @@ -31,10 +31,10 @@ Past releases are all available via GitHub at https://github.com/DSpace/DSpace/r ## Documentation / Installation -Documentation for each release may be viewed online or downloaded via our [Documentation Wiki](https://wiki.duraspace.org/display/DSDOC/). +Documentation for each release may be viewed online or downloaded via our [Documentation Wiki](https://wiki.lyrasis.org/display/DSDOC/). The latest DSpace Installation instructions are available at: -https://wiki.duraspace.org/display/DSDOC6x/Installing+DSpace +https://wiki.lyrasis.org/display/DSDOC6x/Installing+DSpace Please be aware that, as a Java web application, DSpace requires a database (PostgreSQL or Oracle) and a servlet container (usually Tomcat) in order to function. @@ -49,11 +49,11 @@ DSpace is a community built and supported project. We do not have a centralized but have a dedicated group of volunteers who help us improve the software, documentation, resources, etc. We welcome contributions of any type. Here's a few basic guides that provide suggestions for contributing to DSpace: -* [How to Contribute to DSpace](https://wiki.duraspace.org/display/DSPACE/How+to+Contribute+to+DSpace): How to contribute in general (via code, documentation, bug reports, expertise, etc) -* [Code Contribution Guidelines](https://wiki.duraspace.org/display/DSPACE/Code+Contribution+Guidelines): How to give back code or contribute features, bug fixes, etc. -* [DSpace Community Advisory Team (DCAT)](https://wiki.duraspace.org/display/cmtygp/DSpace+Community+Advisory+Team): If you are not a developer, we also have an interest group specifically for repository managers. The DCAT group meets virtually, once a month, and sends open invitations to join their meetings via the [DCAT mailing list](https://groups.google.com/d/forum/DSpaceCommunityAdvisoryTeam). +* [How to Contribute to DSpace](https://wiki.lyrasis.org/display/DSPACE/How+to+Contribute+to+DSpace): How to contribute in general (via code, documentation, bug reports, expertise, etc) +* [Code Contribution Guidelines](https://wiki.lyrasis.org/display/DSPACE/Code+Contribution+Guidelines): How to give back code or contribute features, bug fixes, etc. +* [DSpace Community Advisory Team (DCAT)](https://wiki.lyrasis.org/display/cmtygp/DSpace+Community+Advisory+Team): If you are not a developer, we also have an interest group specifically for repository managers. The DCAT group meets virtually, once a month, and sends open invitations to join their meetings via the [DCAT mailing list](https://groups.google.com/d/forum/DSpaceCommunityAdvisoryTeam). -We also encourage GitHub Pull Requests (PRs) at any time. Please see our [Development with Git](https://wiki.duraspace.org/display/DSPACE/Development+with+Git) guide for more info. +We also encourage GitHub Pull Requests (PRs) at any time. Please see our [Development with Git](https://wiki.lyrasis.org/display/DSPACE/Development+with+Git) guide for more info. In addition, a listing of all known contributors to DSpace software can be found online at: https://wiki.duraspace.org/display/DSPACE/DSpaceContributors @@ -64,12 +64,12 @@ DSpace provides public mailing lists where you can post questions or raise topic We welcome everyone to participate in these lists: * [dspace-community@googlegroups.com](https://groups.google.com/d/forum/dspace-community) : General discussion about DSpace platform, announcements, sharing of best practices -* [dspace-tech@googlegroups.com](https://groups.google.com/d/forum/dspace-tech) : Technical support mailing list. See also our guide for [How to troubleshoot an error](https://wiki.duraspace.org/display/DSPACE/Troubleshoot+an+error). +* [dspace-tech@googlegroups.com](https://groups.google.com/d/forum/dspace-tech) : Technical support mailing list. See also our guide for [How to troubleshoot an error](https://wiki.lyrasis.org/display/DSPACE/Troubleshoot+an+error). * [dspace-devel@googlegroups.com](https://groups.google.com/d/forum/dspace-devel) : Developers / Development mailing list Great Q&A is also available under the [DSpace tag on Stackoverflow](http://stackoverflow.com/questions/tagged/dspace) -Additional support options are listed at https://wiki.duraspace.org/display/DSPACE/Support +Additional support options are at https://wiki.lyrasis.org/display/DSPACE/Support DSpace also has an active service provider network. If you'd rather hire a service provider to install, upgrade, customize or host DSpace, then we recommend getting in touch with one of our @@ -84,7 +84,7 @@ The DSpace Issue Tracker can be found at: https://jira.duraspace.org/projects/DS ### Running Tests By default, in DSpace, Unit Tests and Integration Tests are disabled. However, they are -run automatically by [Travis CI](https://travis-ci.org/DSpace/DSpace/) for all Pull Requests and code commits. +run automatically by [Travis CI](https://travis-ci.com/DSpace/DSpace/) for all Pull Requests and code commits. * How to run both Unit Tests (via `maven-surefire-plugin`) and Integration Tests (via `maven-failsafe-plugin`): ``` @@ -130,4 +130,4 @@ run automatically by [Travis CI](https://travis-ci.org/DSpace/DSpace/) for all P ## License DSpace source code is freely available under a standard [BSD 3-Clause license](https://opensource.org/licenses/BSD-3-Clause). -The full license is available at http://www.dspace.org/license/ +The full license is available in the [LICENSE](LICENSE) file or online at http://www.dspace.org/license/ diff --git a/dspace-api/src/main/java/org/dspace/disseminate/service/CitationDocumentService.java b/dspace-api/src/main/java/org/dspace/disseminate/service/CitationDocumentService.java index d6c7935a869f..4a59de3f5fe1 100644 --- a/dspace-api/src/main/java/org/dspace/disseminate/service/CitationDocumentService.java +++ b/dspace-api/src/main/java/org/dspace/disseminate/service/CitationDocumentService.java @@ -38,7 +38,7 @@ public interface CitationDocumentService { * Citation enabled globally (all citable bitstreams will get "watermarked") modules/disseminate-citation: * enable_globally * OR - * The container is this object is whitelist enabled. + * The container is this object is "allow list" enabled. * - community: modules/disseminate-citation: enabled_communities * - collection: modules/disseminate-citation: enabled_collections * AND diff --git a/dspace-api/src/main/java/org/dspace/importer/external/metadatamapping/contributor/SimpleXpathMetadatumContributor.java b/dspace-api/src/main/java/org/dspace/importer/external/metadatamapping/contributor/SimpleXpathMetadatumContributor.java index ba5afceb5f97..ef2571acc69c 100644 --- a/dspace-api/src/main/java/org/dspace/importer/external/metadatamapping/contributor/SimpleXpathMetadatumContributor.java +++ b/dspace-api/src/main/java/org/dspace/importer/external/metadatamapping/contributor/SimpleXpathMetadatumContributor.java @@ -79,7 +79,7 @@ public void setPrefixToNamespaceMapping(Map prefixToNamespaceMap * @param query query string * @param prefixToNamespaceMapping metadata prefix to namespace mapping * @param field - * MetadataFieldConfig + * MetadataFieldConfig */ public SimpleXpathMetadatumContributor(String query, Map prefixToNamespaceMapping, MetadataFieldConfig field) { diff --git a/dspace-rest/src/main/webapp/WEB-INF/applicationContext.xml b/dspace-rest/src/main/webapp/WEB-INF/applicationContext.xml index 62b660b86b0b..ec892fbaa4f1 100644 --- a/dspace-rest/src/main/webapp/WEB-INF/applicationContext.xml +++ b/dspace-rest/src/main/webapp/WEB-INF/applicationContext.xml @@ -28,7 +28,7 @@