From e456127bec77d96fcde3bd6286243e64fc0f91c0 Mon Sep 17 00:00:00 2001 From: mengyaoXu2023 <141789788+mengyaoXu2023@users.noreply.github.com> Date: Tue, 24 Oct 2023 01:01:15 +1100 Subject: [PATCH 01/44] ImportHandlerTest-handleDuplicatesTest (#10513) * ImportHandlerTest-handleDuplicatesTest * Style changed * Style changed * Style changed-ImportHandler.java * remove message-Objects.requireNonNull * modify details * Refactor entryToInsert to use Optional - Encapsulated `cleanedEntry` within an Optional for better null handling. - Adjusted condition checks using `isEmpty` method of Optional for clarity. - Made changes based on feedback from @koppor to improve code robustness. * -Delete the code of duplicate functions in importEntryWithDuplicateCheck function * Simplified the comparison of Optional values in the ImportHandlerTest based on feedback. * Convert DuplicateDecisionResult to a record. * Refactor DuplicateDecisionResult using Java record features * Refactor: Remove unnecessary Optionals in ImportHandler * re-adds entryToInsert --- .../DuplicateDecisionResult.java | 11 ++ .../gui/externalfiles/ImportHandler.java | 111 ++++++++---- .../gui/externalfiles/ImportHandlerTest.java | 166 ++++++++++++++++++ 3 files changed, 254 insertions(+), 34 deletions(-) create mode 100644 src/main/java/org/jabref/gui/externalfiles/DuplicateDecisionResult.java diff --git a/src/main/java/org/jabref/gui/externalfiles/DuplicateDecisionResult.java b/src/main/java/org/jabref/gui/externalfiles/DuplicateDecisionResult.java new file mode 100644 index 00000000000..8bfc842297d --- /dev/null +++ b/src/main/java/org/jabref/gui/externalfiles/DuplicateDecisionResult.java @@ -0,0 +1,11 @@ +package org.jabref.gui.externalfiles; + +import org.jabref.gui.duplicationFinder.DuplicateResolverDialog; +import org.jabref.model.entry.BibEntry; + +public record DuplicateDecisionResult( + DuplicateResolverDialog.DuplicateResolverResult decision, + BibEntry mergedEntry) { +} + + diff --git a/src/main/java/org/jabref/gui/externalfiles/ImportHandler.java b/src/main/java/org/jabref/gui/externalfiles/ImportHandler.java index 31edf671e97..430099becdc 100644 --- a/src/main/java/org/jabref/gui/externalfiles/ImportHandler.java +++ b/src/main/java/org/jabref/gui/externalfiles/ImportHandler.java @@ -194,52 +194,95 @@ public void importEntries(List entries) { } public void importEntryWithDuplicateCheck(BibDatabaseContext bibDatabaseContext, BibEntry entry) { - ImportCleanup cleanup = new ImportCleanup(bibDatabaseContext.getMode()); - BibEntry cleanedEntry = cleanup.doPostCleanup(entry); + BibEntry cleanedEntry = cleanUpEntry(bibDatabaseContext, entry); + Optional existingDuplicateInLibrary = findDuplicate(bibDatabaseContext, cleanedEntry); + BibEntry entryToInsert = cleanedEntry; - Optional existingDuplicateInLibrary = new DuplicateCheck(Globals.entryTypesManager).containsDuplicate(bibDatabaseContext.getDatabase(), entryToInsert, bibDatabaseContext.getMode()); if (existingDuplicateInLibrary.isPresent()) { - DuplicateResolverDialog dialog = new DuplicateResolverDialog(existingDuplicateInLibrary.get(), entryToInsert, DuplicateResolverDialog.DuplicateResolverType.IMPORT_CHECK, bibDatabaseContext, stateManager, dialogService, preferencesService); - switch (dialogService.showCustomDialogAndWait(dialog).orElse(DuplicateResolverDialog.DuplicateResolverResult.BREAK)) { - case KEEP_RIGHT: - bibDatabaseContext.getDatabase().removeEntry(existingDuplicateInLibrary.get()); - break; - case KEEP_BOTH: - break; - case KEEP_MERGE: - bibDatabaseContext.getDatabase().removeEntry(existingDuplicateInLibrary.get()); - entryToInsert = dialog.getMergedEntry(); - break; - case KEEP_LEFT: - case AUTOREMOVE_EXACT: - case BREAK: - default: - return; + Optional duplicateHandledEntry = handleDuplicates(bibDatabaseContext, cleanedEntry, existingDuplicateInLibrary.get()); + if (duplicateHandledEntry.isEmpty()) { + return; } + entryToInsert = duplicateHandledEntry.get(); + } + regenerateCiteKey(entryToInsert); + bibDatabaseContext.getDatabase().insertEntry(entryToInsert); + + setAutomaticFieldsForEntry(entryToInsert); + + addEntryToGroups(entryToInsert); + + downloadLinkedFiles(entryToInsert); + } + + public BibEntry cleanUpEntry(BibDatabaseContext bibDatabaseContext, BibEntry entry) { + ImportCleanup cleanup = new ImportCleanup(bibDatabaseContext.getMode()); + return cleanup.doPostCleanup(entry); + } + + public Optional findDuplicate(BibDatabaseContext bibDatabaseContext, BibEntry entryToCheck) { + return new DuplicateCheck(Globals.entryTypesManager).containsDuplicate(bibDatabaseContext.getDatabase(), entryToCheck, bibDatabaseContext.getMode()); + } + + public Optional handleDuplicates(BibDatabaseContext bibDatabaseContext, BibEntry originalEntry, BibEntry duplicateEntry) { + DuplicateDecisionResult decisionResult = getDuplicateDecision(originalEntry, duplicateEntry, bibDatabaseContext); + switch (decisionResult.decision()) { + case KEEP_RIGHT: + bibDatabaseContext.getDatabase().removeEntry(duplicateEntry); + break; + case KEEP_BOTH: + break; + case KEEP_MERGE: + bibDatabaseContext.getDatabase().removeEntry(duplicateEntry); + return Optional.of(decisionResult.mergedEntry()); + case KEEP_LEFT: + case AUTOREMOVE_EXACT: + case BREAK: + default: + return Optional.empty(); } - // Regenerate CiteKey of imported BibEntry + return Optional.of(originalEntry); + } + + public DuplicateDecisionResult getDuplicateDecision(BibEntry originalEntry, BibEntry duplicateEntry, BibDatabaseContext bibDatabaseContext) { + DuplicateResolverDialog dialog = new DuplicateResolverDialog(duplicateEntry, originalEntry, DuplicateResolverDialog.DuplicateResolverType.IMPORT_CHECK, bibDatabaseContext, stateManager, dialogService, preferencesService); + DuplicateResolverDialog.DuplicateResolverResult decision = dialogService.showCustomDialogAndWait(dialog).orElse(DuplicateResolverDialog.DuplicateResolverResult.BREAK); + return new DuplicateDecisionResult(decision, dialog.getMergedEntry()); + } + + public void regenerateCiteKey(BibEntry entry) { if (preferencesService.getImporterPreferences().isGenerateNewKeyOnImport()) { - generateKeys(List.of(entryToInsert)); + generateKeys(List.of(entry)); } - bibDatabaseContext.getDatabase().insertEntry(entryToInsert); + } - // Set owner/timestamp - UpdateField.setAutomaticFields(List.of(entryToInsert), - preferencesService.getOwnerPreferences(), - preferencesService.getTimestampPreferences()); + public void setAutomaticFieldsForEntry(BibEntry entry) { + UpdateField.setAutomaticFields( + List.of(entry), + preferencesService.getOwnerPreferences(), + preferencesService.getTimestampPreferences() + ); + } + public void addEntryToGroups(BibEntry entry) { addToGroups(List.of(entry), stateManager.getSelectedGroup(this.bibDatabaseContext)); + } + public void downloadLinkedFiles(BibEntry entry) { if (preferencesService.getFilePreferences().shouldDownloadLinkedFiles()) { - entry.getFiles().stream().filter(LinkedFile::isOnlineLink).forEach(linkedFile -> - new LinkedFileViewModel( - linkedFile, - entry, - bibDatabaseContext, - taskExecutor, - dialogService, - preferencesService).download()); + entry.getFiles().stream() + .filter(LinkedFile::isOnlineLink) + .forEach(linkedFile -> + new LinkedFileViewModel( + linkedFile, + entry, + bibDatabaseContext, + taskExecutor, + dialogService, + preferencesService + ).download() + ); } } diff --git a/src/test/java/org/jabref/gui/externalfiles/ImportHandlerTest.java b/src/test/java/org/jabref/gui/externalfiles/ImportHandlerTest.java index 443e14545a6..0c17b00335d 100644 --- a/src/test/java/org/jabref/gui/externalfiles/ImportHandlerTest.java +++ b/src/test/java/org/jabref/gui/externalfiles/ImportHandlerTest.java @@ -1,13 +1,17 @@ package org.jabref.gui.externalfiles; import java.util.List; +import java.util.Optional; import javax.swing.undo.UndoManager; import org.jabref.gui.DialogService; import org.jabref.gui.StateManager; +import org.jabref.gui.duplicationFinder.DuplicateResolverDialog; import org.jabref.gui.util.CurrentThreadTaskExecutor; +import org.jabref.logic.database.DuplicateCheck; import org.jabref.logic.importer.ImportFormatPreferences; +import org.jabref.model.database.BibDatabase; import org.jabref.model.database.BibDatabaseContext; import org.jabref.model.entry.BibEntry; import org.jabref.model.entry.field.StandardField; @@ -16,15 +20,59 @@ import org.jabref.preferences.FilePreferences; import org.jabref.preferences.PreferencesService; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.mockito.Answers; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.MockitoAnnotations; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; class ImportHandlerTest { + + private ImportHandler importHandler; + private BibDatabaseContext bibDatabaseContext; + private BibEntry testEntry; + + @Mock + private PreferencesService preferencesService; + @Mock + private DuplicateCheck duplicateCheck; + + @BeforeEach + void setUp() { + MockitoAnnotations.initMocks(this); + + ImportFormatPreferences importFormatPreferences = mock(ImportFormatPreferences.class, Answers.RETURNS_DEEP_STUBS); + when(preferencesService.getImportFormatPreferences()).thenReturn(importFormatPreferences); + when(preferencesService.getFilePreferences()).thenReturn(mock(FilePreferences.class)); + + bibDatabaseContext = mock(BibDatabaseContext.class); + BibDatabase bibDatabase = new BibDatabase(); + when(bibDatabaseContext.getDatabase()).thenReturn(bibDatabase); + when(duplicateCheck.isDuplicate(any(), any(), any())).thenReturn(false); + importHandler = new ImportHandler( + bibDatabaseContext, + preferencesService, + new DummyFileUpdateMonitor(), + mock(UndoManager.class), + mock(StateManager.class), + mock(DialogService.class), + new CurrentThreadTaskExecutor() + ); + + testEntry = new BibEntry(StandardEntryType.Article) + .withCitationKey("Test2023") + .withField(StandardField.AUTHOR, "Test Author"); + } + @Test void handleBibTeXData() { ImportFormatPreferences importFormatPreferences = mock(ImportFormatPreferences.class, Answers.RETURNS_DEEP_STUBS); @@ -54,4 +102,122 @@ void handleBibTeXData() { assertEquals(List.of(expected), bibEntries.stream().toList()); } + + @Test + void cleanUpEntryTest() { + BibEntry entry = new BibEntry().withField(StandardField.AUTHOR, "Clear Author"); + BibEntry cleanedEntry = importHandler.cleanUpEntry(bibDatabaseContext, entry); + + Optional authorOptional = cleanedEntry.getField(StandardField.AUTHOR); + + assertEquals(Optional.of("Clear Author"), authorOptional); + } + + @Test + void findDuplicateTest() { + // Assume there's no duplicate initially + assertFalse(importHandler.findDuplicate(bibDatabaseContext, testEntry).isPresent()); + } + + @Test + void handleDuplicatesKeepRightTest() { + // Arrange + BibEntry duplicateEntry = new BibEntry(StandardEntryType.Article) + .withCitationKey("Duplicate2023") + .withField(StandardField.AUTHOR, "Duplicate Author"); + + BibDatabase bibDatabase = bibDatabaseContext.getDatabase(); + bibDatabase.insertEntry(duplicateEntry); // Simulate that the duplicate entry is already in the database + + DuplicateDecisionResult decisionResult = new DuplicateDecisionResult(DuplicateResolverDialog.DuplicateResolverResult.KEEP_RIGHT, null); + importHandler = Mockito.spy(new ImportHandler( + bibDatabaseContext, + preferencesService, + new DummyFileUpdateMonitor(), + mock(UndoManager.class), + mock(StateManager.class), + mock(DialogService.class), + new CurrentThreadTaskExecutor() + )); + // Mock the behavior of getDuplicateDecision to return KEEP_RIGHT + Mockito.doReturn(decisionResult).when(importHandler).getDuplicateDecision(testEntry, duplicateEntry, bibDatabaseContext); + + // Act + BibEntry result = importHandler.handleDuplicates(bibDatabaseContext, testEntry, duplicateEntry).get(); + + // Assert that the duplicate entry was removed from the database + assertFalse(bibDatabase.getEntries().contains(duplicateEntry)); + // Assert that the original entry is returned + assertEquals(testEntry, result); + } + + @Test + void handleDuplicatesKeepBothTest() { + // Arrange + BibEntry duplicateEntry = new BibEntry(StandardEntryType.Article) + .withCitationKey("Duplicate2023") + .withField(StandardField.AUTHOR, "Duplicate Author"); + + BibDatabase bibDatabase = bibDatabaseContext.getDatabase(); + bibDatabase.insertEntry(duplicateEntry); // Simulate that the duplicate entry is already in the database + + DuplicateDecisionResult decisionResult = new DuplicateDecisionResult(DuplicateResolverDialog.DuplicateResolverResult.KEEP_BOTH, null); + importHandler = Mockito.spy(new ImportHandler( + bibDatabaseContext, + preferencesService, + new DummyFileUpdateMonitor(), + mock(UndoManager.class), + mock(StateManager.class), + mock(DialogService.class), + new CurrentThreadTaskExecutor() + )); + // Mock the behavior of getDuplicateDecision to return KEEP_BOTH + Mockito.doReturn(decisionResult).when(importHandler).getDuplicateDecision(testEntry, duplicateEntry, bibDatabaseContext); + + // Act + BibEntry result = importHandler.handleDuplicates(bibDatabaseContext, testEntry, duplicateEntry).get(); + + // Assert + assertTrue(bibDatabase.getEntries().contains(duplicateEntry)); // Assert that the duplicate entry is still in the database + assertEquals(testEntry, result); // Assert that the original entry is returned + } + + @Test + void handleDuplicatesKeepMergeTest() { + // Arrange + BibEntry duplicateEntry = new BibEntry(StandardEntryType.Article) + .withCitationKey("Duplicate2023") + .withField(StandardField.AUTHOR, "Duplicate Author"); + + BibEntry mergedEntry = new BibEntry(StandardEntryType.Article) + .withCitationKey("Merged2023") + .withField(StandardField.AUTHOR, "Merged Author"); + + BibDatabase bibDatabase = bibDatabaseContext.getDatabase(); + bibDatabase.insertEntry(duplicateEntry); // Simulate that the duplicate entry is already in the database + + DuplicateDecisionResult decisionResult = new DuplicateDecisionResult(DuplicateResolverDialog.DuplicateResolverResult.KEEP_MERGE, mergedEntry); + importHandler = Mockito.spy(new ImportHandler( + bibDatabaseContext, + preferencesService, + new DummyFileUpdateMonitor(), + mock(UndoManager.class), + mock(StateManager.class), + mock(DialogService.class), + new CurrentThreadTaskExecutor() + )); + // Mock the behavior of getDuplicateDecision to return KEEP_MERGE + Mockito.doReturn(decisionResult).when(importHandler).getDuplicateDecision(testEntry, duplicateEntry, bibDatabaseContext); + + // Act + BibEntry result = importHandler.handleDuplicates(bibDatabaseContext, testEntry, duplicateEntry) + .orElseGet(() -> { + // create and return a default BibEntry or do other computations + return new BibEntry(); + }); + + // Assert + assertFalse(bibDatabase.getEntries().contains(duplicateEntry)); // Assert that the duplicate entry was removed from the database + assertEquals(mergedEntry, result); // Assert that the merged entry is returned + } } From 7892f524ee186c37a1f6376f6934bdeda6e821fb Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 23 Oct 2023 14:20:03 +0000 Subject: [PATCH 02/44] Bump DavidAnson/markdownlint-cli2-action from 9 to 13 (#10550) Bumps [DavidAnson/markdownlint-cli2-action](https://github.com/davidanson/markdownlint-cli2-action) from 9 to 13. - [Release notes](https://github.com/davidanson/markdownlint-cli2-action/releases) - [Commits](https://github.com/davidanson/markdownlint-cli2-action/compare/v9...v13) --- updated-dependencies: - dependency-name: DavidAnson/markdownlint-cli2-action dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 5ec087a8e62..03914a7cbb1 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -136,7 +136,7 @@ jobs: submodules: 'false' show-progress: 'false' - name: markdownlint-cli2-action - uses: DavidAnson/markdownlint-cli2-action@v9 + uses: DavidAnson/markdownlint-cli2-action@v13 with: globs: | *.md From d211243bad8ac1ec5dcc4fedbd986f5168201435 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 23 Oct 2023 14:44:22 +0000 Subject: [PATCH 03/44] Bump org.openrewrite.rewrite from 6.3.18 to 6.4.0 (#10553) Bumps org.openrewrite.rewrite from 6.3.18 to 6.4.0. --- updated-dependencies: - dependency-name: org.openrewrite.rewrite dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index cc3cd713f75..85d0392fedf 100644 --- a/build.gradle +++ b/build.gradle @@ -27,7 +27,7 @@ plugins { id 'idea' - id 'org.openrewrite.rewrite' version '6.3.18' + id 'org.openrewrite.rewrite' version '6.4.0' } // Enable following for debugging From 5331ab811b23f626695a82f4c55b7f2478ffc789 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 23 Oct 2023 14:46:25 +0000 Subject: [PATCH 04/44] Bump org.openrewrite.recipe:rewrite-recipe-bom from 2.3.1 to 2.4.0 (#10552) Bumps [org.openrewrite.recipe:rewrite-recipe-bom](https://github.com/openrewrite/rewrite-recipe-bom) from 2.3.1 to 2.4.0. - [Release notes](https://github.com/openrewrite/rewrite-recipe-bom/releases) - [Commits](https://github.com/openrewrite/rewrite-recipe-bom/compare/v2.3.1...v2.4.0) --- updated-dependencies: - dependency-name: org.openrewrite.recipe:rewrite-recipe-bom dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 85d0392fedf..3d6da552bb2 100644 --- a/build.gradle +++ b/build.gradle @@ -250,7 +250,7 @@ dependencies { xjc group: 'org.glassfish.jaxb', name: 'jaxb-xjc', version: '3.0.2' xjc group: 'org.glassfish.jaxb', name: 'jaxb-runtime', version: '3.0.2' - rewrite(platform("org.openrewrite.recipe:rewrite-recipe-bom:2.3.1")) + rewrite(platform("org.openrewrite.recipe:rewrite-recipe-bom:2.4.0")) rewrite("org.openrewrite.recipe:rewrite-static-analysis") rewrite("org.openrewrite.recipe:rewrite-logging-frameworks") rewrite("org.openrewrite.recipe:rewrite-testing-frameworks") From 0f126799e2becfcf667ca9f789c0484b408b2923 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 23 Oct 2023 14:48:11 +0000 Subject: [PATCH 05/44] Bump org.glassfish.hk2:hk2-api from 3.0.4 to 3.0.5 (#10551) Bumps [org.glassfish.hk2:hk2-api](https://github.com/eclipse-ee4j/glassfish-hk2) from 3.0.4 to 3.0.5. - [Release notes](https://github.com/eclipse-ee4j/glassfish-hk2/releases) - [Changelog](https://github.com/eclipse-ee4j/glassfish-hk2/blob/master/CHANGELOG) - [Commits](https://github.com/eclipse-ee4j/glassfish-hk2/commits) --- updated-dependencies: - dependency-name: org.glassfish.hk2:hk2-api dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 3d6da552bb2..eb75ed77fbe 100644 --- a/build.gradle +++ b/build.gradle @@ -221,7 +221,7 @@ dependencies { implementation 'org.glassfish.jersey.core:jersey-server:3.1.3' // injection framework implementation 'org.glassfish.jersey.inject:jersey-hk2:3.1.3' - implementation 'org.glassfish.hk2:hk2-api:3.0.4' + implementation 'org.glassfish.hk2:hk2-api:3.0.5' // testImplementation 'org.glassfish.hk2:hk2-testing:3.0.4' // implementation 'org.glassfish.hk2:hk2-testing-jersey:3.0.4' // testImplementation 'org.glassfish.hk2:hk2-junitrunner:3.0.4' From a1050eda79199e7daf59bfcfcccd50c0205580ae Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 23 Oct 2023 14:58:52 +0000 Subject: [PATCH 06/44] Bump org.apache.logging.log4j:log4j-to-slf4j from 2.20.0 to 2.21.0 (#10555) * Bump org.apache.logging.log4j:log4j-to-slf4j from 2.20.0 to 2.21.0 Bumps org.apache.logging.log4j:log4j-to-slf4j from 2.20.0 to 2.21.0. --- updated-dependencies: - dependency-name: org.apache.logging.log4j:log4j-to-slf4j dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] * fix dep name --------- Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Siedlerchr --- build.gradle | 2 +- src/main/java/module-info.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/build.gradle b/build.gradle index eb75ed77fbe..390a77ff3e1 100644 --- a/build.gradle +++ b/build.gradle @@ -190,7 +190,7 @@ dependencies { // route all requests to java.util.logging to SLF4J (which in turn routes to tinylog) implementation 'org.slf4j:jul-to-slf4j:2.0.9' // route all requests to log4j to SLF4J - implementation 'org.apache.logging.log4j:log4j-to-slf4j:2.20.0' + implementation 'org.apache.logging.log4j:log4j-to-slf4j:2.21.0' implementation('de.undercouch:citeproc-java:3.0.0-beta.2') { exclude group: 'org.antlr' diff --git a/src/main/java/module-info.java b/src/main/java/module-info.java index ba646d0737e..fd08733b2ab 100644 --- a/src/main/java/module-info.java +++ b/src/main/java/module-info.java @@ -42,7 +42,7 @@ // Logging requires org.slf4j; requires jul.to.slf4j; - requires org.apache.logging.slf4j; + requires org.apache.logging.log4j.to.slf4j; requires org.tinylog.api; requires org.tinylog.api.slf4j; requires org.tinylog.impl; From 1729d64f25e4521e82e99df2e51b9191a4df47c1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 23 Oct 2023 15:58:34 +0000 Subject: [PATCH 07/44] Bump com.fasterxml:aalto-xml from 1.3.1 to 1.3.2 (#10554) Bumps [com.fasterxml:aalto-xml](https://github.com/FasterXML/aalto-xml) from 1.3.1 to 1.3.2. - [Commits](https://github.com/FasterXML/aalto-xml/compare/aalto-xml-1.3.1...aalto-xml-1.3.2) --- updated-dependencies: - dependency-name: com.fasterxml:aalto-xml dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 390a77ff3e1..31a0ea7c2f2 100644 --- a/build.gradle +++ b/build.gradle @@ -145,7 +145,7 @@ dependencies { implementation group: 'com.fasterxml.jackson.dataformat', name: 'jackson-dataformat-yaml', version: '2.15.3' implementation group: 'com.fasterxml.jackson.datatype', name: 'jackson-datatype-jsr310', version: '2.15.3' - implementation 'com.fasterxml:aalto-xml:1.3.1' + implementation 'com.fasterxml:aalto-xml:1.3.2' implementation group: 'org.mariadb.jdbc', name: 'mariadb-java-client', version: '2.7.9' From 260ea31cfc1986502e18227bcae57ef2624dd3fe Mon Sep 17 00:00:00 2001 From: Oliver Kopp Date: Mon, 23 Oct 2023 22:50:50 +0200 Subject: [PATCH 08/44] Minor code improvements to ImportHandler (#10562) * Minor code improvements * Introduce interface ImportCleanup (better inheritance) * Refine ImportHandler --- src/main/java/org/jabref/gui/JabRefFrame.java | 2 +- .../gui/entryeditor/RelatedArticlesTab.java | 2 +- .../gui/externalfiles/ImportHandler.java | 69 +++++++------------ .../gui/mergeentries/FetchAndMergeEntry.java | 4 +- .../jabref/logic/importer/ImportCleanup.java | 29 +++----- .../logic/importer/ImportCleanupBiblatex.java | 21 ++++++ .../logic/importer/ImportCleanupBibtex.java | 21 ++++++ .../gui/externalfiles/ImportHandlerTest.java | 12 ++-- .../importer/fetcher/ArXivFetcherTest.java | 6 +- .../CompositeSearchBasedFetcherTest.java | 2 +- .../SearchBasedFetcherCapabilityTest.java | 8 +-- 11 files changed, 92 insertions(+), 84 deletions(-) create mode 100644 src/main/java/org/jabref/logic/importer/ImportCleanupBiblatex.java create mode 100644 src/main/java/org/jabref/logic/importer/ImportCleanupBibtex.java diff --git a/src/main/java/org/jabref/gui/JabRefFrame.java b/src/main/java/org/jabref/gui/JabRefFrame.java index 3dff38bafbb..f8fe7a35937 100644 --- a/src/main/java/org/jabref/gui/JabRefFrame.java +++ b/src/main/java/org/jabref/gui/JabRefFrame.java @@ -790,7 +790,7 @@ public void addTab(ParserResult parserResult, boolean raisePanel) { */ private void addImportedEntries(final LibraryTab panel, final ParserResult parserResult) { BackgroundTask task = BackgroundTask.wrap(() -> parserResult); - ImportCleanup cleanup = new ImportCleanup(panel.getBibDatabaseContext().getMode()); + ImportCleanup cleanup = ImportCleanup.targeting(panel.getBibDatabaseContext().getMode()); cleanup.doPostCleanup(parserResult.getDatabase().getEntries()); ImportEntriesDialog dialog = new ImportEntriesDialog(panel.getBibDatabaseContext(), task); dialog.setTitle(Localization.lang("Import")); diff --git a/src/main/java/org/jabref/gui/entryeditor/RelatedArticlesTab.java b/src/main/java/org/jabref/gui/entryeditor/RelatedArticlesTab.java index baf22123c35..1cf3ad74e5b 100644 --- a/src/main/java/org/jabref/gui/entryeditor/RelatedArticlesTab.java +++ b/src/main/java/org/jabref/gui/entryeditor/RelatedArticlesTab.java @@ -78,7 +78,7 @@ private StackPane getRelatedArticlesPane(BibEntry entry) { .wrap(() -> fetcher.performSearch(entry)) .onRunning(() -> progress.setVisible(true)) .onSuccess(relatedArticles -> { - ImportCleanup cleanup = new ImportCleanup(BibDatabaseModeDetection.inferMode(new BibDatabase(List.of(entry)))); + ImportCleanup cleanup = ImportCleanup.targeting(BibDatabaseModeDetection.inferMode(new BibDatabase(List.of(entry)))); cleanup.doPostCleanup(relatedArticles); progress.setVisible(false); root.getChildren().add(getRelatedArticleInfo(relatedArticles, fetcher)); diff --git a/src/main/java/org/jabref/gui/externalfiles/ImportHandler.java b/src/main/java/org/jabref/gui/externalfiles/ImportHandler.java index 430099becdc..a9fbbe28eb8 100644 --- a/src/main/java/org/jabref/gui/externalfiles/ImportHandler.java +++ b/src/main/java/org/jabref/gui/externalfiles/ImportHandler.java @@ -52,6 +52,7 @@ import org.jabref.model.util.OptionalUtil; import org.jabref.preferences.PreferencesService; +import com.google.common.annotations.VisibleForTesting; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -174,50 +175,40 @@ private BibEntry createEmptyEntryWithLink(Path file) { return entry; } + /** + * Cleans up the given entries and adds them to the library. + * There is no automatic download done. + */ public void importEntries(List entries) { - ImportCleanup cleanup = new ImportCleanup(bibDatabaseContext.getMode()); + ImportCleanup cleanup = ImportCleanup.targeting(bibDatabaseContext.getMode()); cleanup.doPostCleanup(entries); - bibDatabaseContext.getDatabase().insertEntries(entries); - - // Set owner/timestamp - UpdateField.setAutomaticFields(entries, - preferencesService.getOwnerPreferences(), - preferencesService.getTimestampPreferences()); - - // Generate citation keys - if (preferencesService.getImporterPreferences().isGenerateNewKeyOnImport()) { - generateKeys(entries); - } + importCleanedEntries(entries); + } - // Add to group + public void importCleanedEntries(List entries) { + bibDatabaseContext.getDatabase().insertEntries(entries); + generateKeys(entries); + setAutomaticFields(entries); addToGroups(entries, stateManager.getSelectedGroup(bibDatabaseContext)); } public void importEntryWithDuplicateCheck(BibDatabaseContext bibDatabaseContext, BibEntry entry) { - BibEntry cleanedEntry = cleanUpEntry(bibDatabaseContext, entry); - Optional existingDuplicateInLibrary = findDuplicate(bibDatabaseContext, cleanedEntry); - - BibEntry entryToInsert = cleanedEntry; - + BibEntry entryToInsert = cleanUpEntry(bibDatabaseContext, entry); + Optional existingDuplicateInLibrary = findDuplicate(bibDatabaseContext, entryToInsert); if (existingDuplicateInLibrary.isPresent()) { - Optional duplicateHandledEntry = handleDuplicates(bibDatabaseContext, cleanedEntry, existingDuplicateInLibrary.get()); + Optional duplicateHandledEntry = handleDuplicates(bibDatabaseContext, entryToInsert, existingDuplicateInLibrary.get()); if (duplicateHandledEntry.isEmpty()) { return; } entryToInsert = duplicateHandledEntry.get(); } - regenerateCiteKey(entryToInsert); - bibDatabaseContext.getDatabase().insertEntry(entryToInsert); - - setAutomaticFieldsForEntry(entryToInsert); - - addEntryToGroups(entryToInsert); - + importCleanedEntries(List.of(entryToInsert)); downloadLinkedFiles(entryToInsert); } - public BibEntry cleanUpEntry(BibDatabaseContext bibDatabaseContext, BibEntry entry) { - ImportCleanup cleanup = new ImportCleanup(bibDatabaseContext.getMode()); + @VisibleForTesting + BibEntry cleanUpEntry(BibDatabaseContext bibDatabaseContext, BibEntry entry) { + ImportCleanup cleanup = ImportCleanup.targeting(bibDatabaseContext.getMode()); return cleanup.doPostCleanup(entry); } @@ -251,24 +242,14 @@ public DuplicateDecisionResult getDuplicateDecision(BibEntry originalEntry, BibE return new DuplicateDecisionResult(decision, dialog.getMergedEntry()); } - public void regenerateCiteKey(BibEntry entry) { - if (preferencesService.getImporterPreferences().isGenerateNewKeyOnImport()) { - generateKeys(List.of(entry)); - } - } - - public void setAutomaticFieldsForEntry(BibEntry entry) { + public void setAutomaticFields(List entries) { UpdateField.setAutomaticFields( - List.of(entry), + entries, preferencesService.getOwnerPreferences(), preferencesService.getTimestampPreferences() ); } - public void addEntryToGroups(BibEntry entry) { - addToGroups(List.of(entry), stateManager.getSelectedGroup(this.bibDatabaseContext)); - } - public void downloadLinkedFiles(BibEntry entry) { if (preferencesService.getFilePreferences().shouldDownloadLinkedFiles()) { entry.getFiles().stream() @@ -305,15 +286,15 @@ private void addToGroups(List entries, Collection group * @param entries entries to generate keys for */ private void generateKeys(List entries) { + if (!preferencesService.getImporterPreferences().isGenerateNewKeyOnImport()) { + return; + } CitationKeyGenerator keyGenerator = new CitationKeyGenerator( bibDatabaseContext.getMetaData().getCiteKeyPattern(preferencesService.getCitationKeyPatternPreferences() .getKeyPattern()), bibDatabaseContext.getDatabase(), preferencesService.getCitationKeyPatternPreferences()); - - for (BibEntry entry : entries) { - keyGenerator.generateAndSetKey(entry); - } + entries.forEach(keyGenerator::generateAndSetKey); } public List handleBibTeXData(String entries) { diff --git a/src/main/java/org/jabref/gui/mergeentries/FetchAndMergeEntry.java b/src/main/java/org/jabref/gui/mergeentries/FetchAndMergeEntry.java index 0aa765d81ba..c5c65b1cc5d 100644 --- a/src/main/java/org/jabref/gui/mergeentries/FetchAndMergeEntry.java +++ b/src/main/java/org/jabref/gui/mergeentries/FetchAndMergeEntry.java @@ -77,7 +77,7 @@ public void fetchAndMerge(BibEntry entry, List fields) { if (fetcher.isPresent()) { BackgroundTask.wrap(() -> fetcher.get().performSearchById(fieldContent.get())) .onSuccess(fetchedEntry -> { - ImportCleanup cleanup = new ImportCleanup(bibDatabaseContext.getMode()); + ImportCleanup cleanup = ImportCleanup.targeting(bibDatabaseContext.getMode()); String type = field.getDisplayName(); if (fetchedEntry.isPresent()) { cleanup.doPostCleanup(fetchedEntry.get()); @@ -169,7 +169,7 @@ public void fetchAndMerge(BibEntry entry, EntryBasedFetcher fetcher) { BackgroundTask.wrap(() -> fetcher.performSearch(entry).stream().findFirst()) .onSuccess(fetchedEntry -> { if (fetchedEntry.isPresent()) { - ImportCleanup cleanup = new ImportCleanup(bibDatabaseContext.getMode()); + ImportCleanup cleanup = ImportCleanup.targeting(bibDatabaseContext.getMode()); cleanup.doPostCleanup(fetchedEntry.get()); showMergeDialog(entry, fetchedEntry.get(), fetcher); } else { diff --git a/src/main/java/org/jabref/logic/importer/ImportCleanup.java b/src/main/java/org/jabref/logic/importer/ImportCleanup.java index 6aae40cd0d5..c6af4d0a2cd 100644 --- a/src/main/java/org/jabref/logic/importer/ImportCleanup.java +++ b/src/main/java/org/jabref/logic/importer/ImportCleanup.java @@ -2,37 +2,24 @@ import java.util.Collection; -import org.jabref.logic.cleanup.ConvertToBiblatexCleanup; -import org.jabref.logic.cleanup.ConvertToBibtexCleanup; import org.jabref.model.database.BibDatabaseMode; import org.jabref.model.entry.BibEntry; -public class ImportCleanup { +public interface ImportCleanup { - private final BibDatabaseMode targetBibEntryFormat; - - public ImportCleanup(BibDatabaseMode targetBibEntryFormat) { - this.targetBibEntryFormat = targetBibEntryFormat; + static ImportCleanup targeting(BibDatabaseMode mode) { + return switch (mode) { + case BIBTEX -> new ImportCleanupBibtex(); + case BIBLATEX -> new ImportCleanupBiblatex(); + }; } - /** - * Performs a format conversion of the given entry into the targeted format. - * - * @return Returns the cleaned up bibentry to enable usage of doPostCleanup in streams. - */ - public BibEntry doPostCleanup(BibEntry entry) { - if (targetBibEntryFormat == BibDatabaseMode.BIBTEX) { - new ConvertToBibtexCleanup().cleanup(entry); - } else if (targetBibEntryFormat == BibDatabaseMode.BIBLATEX) { - new ConvertToBiblatexCleanup().cleanup(entry); - } - return entry; - } + BibEntry doPostCleanup(BibEntry entry); /** * Performs a format conversion of the given entry collection into the targeted format. */ - public void doPostCleanup(Collection entries) { + default void doPostCleanup(Collection entries) { entries.forEach(this::doPostCleanup); } } diff --git a/src/main/java/org/jabref/logic/importer/ImportCleanupBiblatex.java b/src/main/java/org/jabref/logic/importer/ImportCleanupBiblatex.java new file mode 100644 index 00000000000..99919a2d3f0 --- /dev/null +++ b/src/main/java/org/jabref/logic/importer/ImportCleanupBiblatex.java @@ -0,0 +1,21 @@ +package org.jabref.logic.importer; + +import org.jabref.logic.cleanup.ConvertToBiblatexCleanup; +import org.jabref.model.entry.BibEntry; + +public class ImportCleanupBiblatex implements ImportCleanup { + + private final ConvertToBiblatexCleanup convertToBiblatexCleanup = new ConvertToBiblatexCleanup(); + + /** + * Performs a format conversion of the given entry into the targeted format. + * Modifies the given entry and also returns it to enable usage of doPostCleanup in streams. + * + * @return Cleaned up BibEntry + */ + @Override + public BibEntry doPostCleanup(BibEntry entry) { + convertToBiblatexCleanup.cleanup(entry); + return entry; + } +} diff --git a/src/main/java/org/jabref/logic/importer/ImportCleanupBibtex.java b/src/main/java/org/jabref/logic/importer/ImportCleanupBibtex.java new file mode 100644 index 00000000000..ddda1f73e73 --- /dev/null +++ b/src/main/java/org/jabref/logic/importer/ImportCleanupBibtex.java @@ -0,0 +1,21 @@ +package org.jabref.logic.importer; + +import org.jabref.logic.cleanup.ConvertToBibtexCleanup; +import org.jabref.model.entry.BibEntry; + +public class ImportCleanupBibtex implements ImportCleanup { + + private final ConvertToBibtexCleanup convertToBibtexCleanup = new ConvertToBibtexCleanup(); + + /** + * Performs a format conversion of the given entry into the targeted format. + * Modifies the given entry and also returns it to enable usage of doPostCleanup in streams. + * + * @return Cleaned up BibEntry + */ + @Override + public BibEntry doPostCleanup(BibEntry entry) { + convertToBibtexCleanup.cleanup(entry); + return entry; + } +} diff --git a/src/test/java/org/jabref/gui/externalfiles/ImportHandlerTest.java b/src/test/java/org/jabref/gui/externalfiles/ImportHandlerTest.java index 0c17b00335d..2e973ac5a23 100644 --- a/src/test/java/org/jabref/gui/externalfiles/ImportHandlerTest.java +++ b/src/test/java/org/jabref/gui/externalfiles/ImportHandlerTest.java @@ -1,7 +1,6 @@ package org.jabref.gui.externalfiles; import java.util.List; -import java.util.Optional; import javax.swing.undo.UndoManager; @@ -13,6 +12,7 @@ import org.jabref.logic.importer.ImportFormatPreferences; import org.jabref.model.database.BibDatabase; import org.jabref.model.database.BibDatabaseContext; +import org.jabref.model.database.BibDatabaseMode; import org.jabref.model.entry.BibEntry; import org.jabref.model.entry.field.StandardField; import org.jabref.model.entry.types.StandardEntryType; @@ -56,6 +56,7 @@ void setUp() { bibDatabaseContext = mock(BibDatabaseContext.class); BibDatabase bibDatabase = new BibDatabase(); + when(bibDatabaseContext.getMode()).thenReturn(BibDatabaseMode.BIBTEX); when(bibDatabaseContext.getDatabase()).thenReturn(bibDatabase); when(duplicateCheck.isDuplicate(any(), any(), any())).thenReturn(false); importHandler = new ImportHandler( @@ -107,16 +108,13 @@ void handleBibTeXData() { void cleanUpEntryTest() { BibEntry entry = new BibEntry().withField(StandardField.AUTHOR, "Clear Author"); BibEntry cleanedEntry = importHandler.cleanUpEntry(bibDatabaseContext, entry); - - Optional authorOptional = cleanedEntry.getField(StandardField.AUTHOR); - - assertEquals(Optional.of("Clear Author"), authorOptional); + assertEquals(new BibEntry().withField(StandardField.AUTHOR, "Clear Author"), cleanedEntry); } @Test void findDuplicateTest() { - // Assume there's no duplicate initially - assertFalse(importHandler.findDuplicate(bibDatabaseContext, testEntry).isPresent()); + // Assume there is no duplicate initially + assertTrue(importHandler.findDuplicate(bibDatabaseContext, testEntry).isEmpty()); } @Test diff --git a/src/test/java/org/jabref/logic/importer/fetcher/ArXivFetcherTest.java b/src/test/java/org/jabref/logic/importer/fetcher/ArXivFetcherTest.java index 5ab1bf7032f..65d3c2bcfc9 100644 --- a/src/test/java/org/jabref/logic/importer/fetcher/ArXivFetcherTest.java +++ b/src/test/java/org/jabref/logic/importer/fetcher/ArXivFetcherTest.java @@ -182,7 +182,7 @@ public void supportsAuthorSearch() throws FetcherException { getInputTestAuthors().forEach(queryBuilder::add); List result = getFetcher().performSearch(queryBuilder.toString()); - new ImportCleanup(BibDatabaseMode.BIBTEX).doPostCleanup(result); + ImportCleanup.targeting(BibDatabaseMode.BIBTEX).doPostCleanup(result); assertFalse(result.isEmpty()); result.forEach(bibEntry -> { @@ -199,9 +199,9 @@ public void noSupportsAuthorSearchWithLastFirstName() throws FetcherException { getTestAuthors().forEach(queryBuilder::add); List result = getFetcher().performSearch(queryBuilder.toString()); - new ImportCleanup(BibDatabaseMode.BIBTEX).doPostCleanup(result); + ImportCleanup.targeting(BibDatabaseMode.BIBTEX).doPostCleanup(result); - assertTrue(result.isEmpty()); + assertEquals(List.of(), result); } @Test diff --git a/src/test/java/org/jabref/logic/importer/fetcher/CompositeSearchBasedFetcherTest.java b/src/test/java/org/jabref/logic/importer/fetcher/CompositeSearchBasedFetcherTest.java index 27b781014fb..8667a600427 100644 --- a/src/test/java/org/jabref/logic/importer/fetcher/CompositeSearchBasedFetcherTest.java +++ b/src/test/java/org/jabref/logic/importer/fetcher/CompositeSearchBasedFetcherTest.java @@ -68,7 +68,7 @@ public void performSearchOnEmptyQuery(Set fetchers) throws E @MethodSource("performSearchParameters") public void performSearchOnNonEmptyQuery(Set fetchers) throws Exception { CompositeSearchBasedFetcher compositeFetcher = new CompositeSearchBasedFetcher(fetchers, Integer.MAX_VALUE); - ImportCleanup cleanup = new ImportCleanup(BibDatabaseMode.BIBTEX); + ImportCleanup cleanup = ImportCleanup.targeting(BibDatabaseMode.BIBTEX); List compositeResult = compositeFetcher.performSearch("quantum"); for (SearchBasedFetcher fetcher : fetchers) { diff --git a/src/test/java/org/jabref/logic/importer/fetcher/SearchBasedFetcherCapabilityTest.java b/src/test/java/org/jabref/logic/importer/fetcher/SearchBasedFetcherCapabilityTest.java index 3de0af37fd4..a93f73bed17 100644 --- a/src/test/java/org/jabref/logic/importer/fetcher/SearchBasedFetcherCapabilityTest.java +++ b/src/test/java/org/jabref/logic/importer/fetcher/SearchBasedFetcherCapabilityTest.java @@ -36,7 +36,7 @@ default void supportsAuthorSearch() throws Exception { getTestAuthors().forEach(queryBuilder::add); List result = getFetcher().performSearch(queryBuilder.toString()); - new ImportCleanup(BibDatabaseMode.BIBTEX).doPostCleanup(result); + ImportCleanup.targeting(BibDatabaseMode.BIBTEX).doPostCleanup(result); assertFalse(result.isEmpty()); result.forEach(bibEntry -> { @@ -53,7 +53,7 @@ default void supportsAuthorSearch() throws Exception { @Test default void supportsYearSearch() throws Exception { List result = getFetcher().performSearch("year:" + getTestYear()); - new ImportCleanup(BibDatabaseMode.BIBTEX).doPostCleanup(result); + ImportCleanup.targeting(BibDatabaseMode.BIBTEX).doPostCleanup(result); List differentYearsInResult = result.stream() .map(bibEntry -> bibEntry.getField(StandardField.YEAR)) .filter(Optional::isPresent) @@ -72,7 +72,7 @@ default void supportsYearRangeSearch() throws Exception { List yearsInYearRange = List.of("2018", "2019", "2020"); List result = getFetcher().performSearch("year-range:2018-2020"); - new ImportCleanup(BibDatabaseMode.BIBTEX).doPostCleanup(result); + ImportCleanup.targeting(BibDatabaseMode.BIBTEX).doPostCleanup(result); List differentYearsInResult = result.stream() .map(bibEntry -> bibEntry.getField(StandardField.YEAR)) .filter(Optional::isPresent) @@ -92,7 +92,7 @@ default void supportsYearRangeSearch() throws Exception { @Test default void supportsJournalSearch() throws Exception { List result = getFetcher().performSearch("journal:\"" + getTestJournal() + "\""); - new ImportCleanup(BibDatabaseMode.BIBTEX).doPostCleanup(result); + ImportCleanup.targeting(BibDatabaseMode.BIBTEX).doPostCleanup(result); assertFalse(result.isEmpty()); result.forEach(bibEntry -> { From 4c1aa94cc3ac562dc06c190da821d3859ed4ca9e Mon Sep 17 00:00:00 2001 From: Oliver Kopp Date: Mon, 23 Oct 2023 23:22:41 +0200 Subject: [PATCH 09/44] Update .gitignore --- .gitignore | 193 +++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 135 insertions(+), 58 deletions(-) diff --git a/.gitignore b/.gitignore index 1d3864a220b..72603d9dc08 100644 --- a/.gitignore +++ b/.gitignore @@ -3,6 +3,9 @@ src/main/gen/ src/main/generated/ src-gen/ +# generated by https://plugins.jetbrains.com/plugin/15991-plantuml-diagram-generator +*.puml + structure101-settings.java.hsw # private data @@ -59,8 +62,8 @@ jabref.xml ## !! IN CASE YOU UPDATE, PLEASE KEEP THE LINES AT THE END OF THE FILE !! -# Created by https://www.gitignore.io/api/gradle,java,jabref,intellij,eclipse,netbeans,windows,linux,macos,node,snapcraft -# Edit at https://www.gitignore.io/?templates=gradle,java,jabref,intellij,eclipse,netbeans,windows,linux,macos,node,snapcraft +# Created by https://www.toptal.com/developers/gitignore/api/gradle,java,jabref,jetbrains,eclipse,netbeans,windows,linux,macos,node,snapcraft +# Edit at https://www.toptal.com/developers/gitignore?templates=gradle,java,jabref,jetbrains,eclipse,netbeans,windows,linux,macos,node,snapcraft ### Eclipse ### .metadata @@ -113,26 +116,53 @@ local.properties # Annotation Processing .apt_generated/ +.apt_generated_test/ # Scala IDE specific (Scala & Java development for Eclipse) .cache-main .scala_dependencies .worksheet +# Uncomment this line if you wish to ignore the project description file. +# Typically, this file would be tracked if it contains build/dependency configurations: +#.project + ### Eclipse Patch ### -# Eclipse Core -.project +# Spring Boot Tooling +.sts4-cache/ -# JDT-specific (Eclipse Java Development Tools) -.classpath +### JabRef ### +# JabRef - https://www.jabref.org/ +*.sav -# Annotation Processing -.apt_generated +### Java ### +# Compiled class file +*.class -.sts4-cache/ +# Log file +*.log + +# BlueJ files +*.ctxt + +# Mobile Tools for Java (J2ME) +.mtj.tmp/ + +# Package Files # +*.jar +*.war +*.nar +*.ear +*.zip +*.tar.gz +*.rar -### Intellij ### -# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and WebStorm +# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml +hs_err_pid* +replay_pid* + +### JetBrains ### +# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 # User-specific stuff @@ -142,6 +172,9 @@ local.properties .idea/**/dictionaries .idea/**/shelf +# AWS User-specific +.idea/**/aws.xml + # Generated files .idea/**/contentModel.xml @@ -162,6 +195,9 @@ local.properties # When using Gradle or Maven with auto-import, you should exclude module files, # since they will be recreated, and may cause churn. Uncomment if using # auto-import. +# .idea/artifacts +# .idea/compiler.xml +# .idea/jarRepositories.xml # .idea/modules.xml # .idea/*.iml # .idea/modules @@ -189,6 +225,9 @@ atlassian-ide-plugin.xml # Cursive Clojure plugin .idea/replstate.xml +# SonarLint plugin +.idea/sonarlint/ + # Crashlytics plugin (for Android Studio and IntelliJ) com_crashlytics_export_strings.xml crashlytics.properties @@ -201,7 +240,7 @@ fabric.properties # Android studio 3.1+ serialized cache file .idea/caches/build_file_checksums.ser -### Intellij Patch ### +### JetBrains Patch ### # Comment Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-215987721 # *.iml @@ -210,43 +249,30 @@ fabric.properties # *.ipr # Sonarlint plugin +# https://plugins.jetbrains.com/plugin/7973-sonarlint .idea/**/sonarlint/ # SonarQube Plugin +# https://plugins.jetbrains.com/plugin/7238-sonarqube-community-plugin .idea/**/sonarIssues.xml # Markdown Navigator plugin +# https://plugins.jetbrains.com/plugin/7896-markdown-navigator-enhanced .idea/**/markdown-navigator.xml +.idea/**/markdown-navigator-enh.xml .idea/**/markdown-navigator/ -### JabRef ### -# JabRef - https://www.jabref.org/ -*.sav - -### Java ### -# Compiled class file -*.class - -# Log file -*.log +# Cache file creation bug +# See https://youtrack.jetbrains.com/issue/JBR-2257 +.idea/$CACHE_FILE$ -# BlueJ files -*.ctxt +# CodeStream plugin +# https://plugins.jetbrains.com/plugin/12206-codestream +.idea/codestream.xml -# Mobile Tools for Java (J2ME) -.mtj.tmp/ - -# Package Files # -*.jar -*.war -*.nar -*.ear -*.zip -*.tar.gz -*.rar - -# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml -hs_err_pid* +# Azure Toolkit for IntelliJ plugin +# https://plugins.jetbrains.com/plugin/8053-azure-toolkit-for-intellij +.idea/**/azureSettings.xml ### Linux ### *~ @@ -272,6 +298,7 @@ hs_err_pid* # Icon must end with two \r Icon + # Thumbnails ._* @@ -291,6 +318,10 @@ Network Trash Folder Temporary Items .apdisk +### macOS Patch ### +# iCloud generated files +*.icloud + ### NetBeans ### **/nbproject/private/ **/nbproject/Makefile-*.mk @@ -308,6 +339,7 @@ npm-debug.log* yarn-debug.log* yarn-error.log* lerna-debug.log* +.pnpm-debug.log* # Diagnostic reports (https://nodejs.org/api/report.html) report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json @@ -344,8 +376,8 @@ build/Release node_modules/ jspm_packages/ -# TypeScript v1 declaration files -typings/ +# Snowpack dependency directory (https://snowpack.dev/) +web_modules/ # TypeScript cache *.tsbuildinfo @@ -356,6 +388,15 @@ typings/ # Optional eslint cache .eslintcache +# Optional stylelint cache +.stylelintcache + +# Microbundle cache +.rpt2_cache/ +.rts2_cache_cjs/ +.rts2_cache_es/ +.rts2_cache_umd/ + # Optional REPL history .node_repl_history @@ -365,33 +406,40 @@ typings/ # Yarn Integrity file .yarn-integrity -# dotenv environment variables file +# dotenv environment variable files .env -.env.test +.env.development.local +.env.test.local +.env.production.local +.env.local # parcel-bundler cache (https://parceljs.org/) .cache +.parcel-cache -# next.js build output +# Next.js build output .next +out -# nuxt.js build output +# Nuxt.js build / generate output .nuxt +dist -# rollup.js default build output - -# Uncomment the public line if your project uses Gatsby +# Gatsby files +.cache/ +# Comment in the public line in if your project uses Gatsby and not Next.js # https://nextjs.org/blog/next-9-1#public-directory-support -# https://create-react-app.dev/docs/using-the-public-folder/#docsNav # public -# Storybook build outputs -.out -.storybook-out - # vuepress build output .vuepress/dist +# vuepress v2.x temp and cache directory +.temp + +# Docusaurus cache and generated files +.docusaurus + # Serverless directories .serverless/ @@ -401,8 +449,27 @@ typings/ # DynamoDB Local files .dynamodb/ -# Temporary folders -temp/ +# TernJS port file +.tern-port + +# Stores VSCode versions used for testing VSCode extensions +.vscode-test + +# yarn v2 +.yarn/cache +.yarn/unplugged +.yarn/build-state.yml +.yarn/install-state.gz +.pnp.* + +### Node Patch ### +# Serverless Webpack directories +.webpack/ + +# Optional stylelint cache + +# SvelteKit build / generate output +.svelte-kit ### Snapcraft ### /parts/ @@ -445,6 +512,8 @@ $RECYCLE.BIN/ ### Gradle ### .gradle +**/build/ +!src/**/build/ # Ignore Gradle GUI config gradle-app.setting @@ -452,16 +521,24 @@ gradle-app.setting # Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored) !gradle-wrapper.jar +# Avoid ignore Gradle wrappper properties +!gradle-wrapper.properties + # Cache of project .gradletasknamecache -# # Work around https://youtrack.jetbrains.com/issue/IDEA-116898 -# gradle/wrapper/gradle-wrapper.properties +# Eclipse Gradle plugin generated files +# Eclipse Core +.project +# JDT-specific (Eclipse Java Development Tools) +.classpath ### Gradle Patch ### -**/build/ +# Java heap dump +*.hprof + +# End of https://www.toptal.com/developers/gitignore/api/gradle,java,jabref,jetbrains,eclipse,netbeans,windows,linux,macos,node,snapcraft -# End of https://www.gitignore.io/api/gradle,java,jabref,intellij,eclipse,netbeans,windows,linux,macos,node,snapcraft ## !! KEEP THESE LINES !! From 26bf32cefa5b2d0bbdc8308c8cea8d1efba0b704 Mon Sep 17 00:00:00 2001 From: Christoph Date: Mon, 23 Oct 2023 23:30:06 +0200 Subject: [PATCH 10/44] Add api key for semantic scholar if available (#10561) * Add api key for semantic scholar if available Refactor api key getting Co-authored-by: Carl Christian Snethlage <50491877+calixtus@users.noreply.github.com> * fix javadoc * make olly happy * fuck this checkstyle --------- Co-authored-by: Carl Christian Snethlage <50491877+calixtus@users.noreply.github.com> --- .../logic/importer/ImporterPreferences.java | 9 +++++ .../jabref/logic/importer/WebFetchers.java | 6 ++-- .../fetcher/AstrophysicsDataSystem.java | 20 +++-------- .../importer/fetcher/BiodiversityLibrary.java | 13 +------ .../jabref/logic/importer/fetcher/IEEE.java | 9 +---- .../logic/importer/fetcher/ScienceDirect.java | 13 +------ .../importer/fetcher/SemanticScholar.java | 35 ++++++++++++------- .../importer/fetcher/SpringerFetcher.java | 13 +------ .../logic/importer/fetcher/SpringerLink.java | 20 ++++------- .../jabref/logic/importer/fetcher/ZbMATH.java | 2 +- .../importer/fetcher/SemanticScholarTest.java | 19 ++++++---- 11 files changed, 63 insertions(+), 96 deletions(-) diff --git a/src/main/java/org/jabref/logic/importer/ImporterPreferences.java b/src/main/java/org/jabref/logic/importer/ImporterPreferences.java index 5923680af9e..171c653821f 100644 --- a/src/main/java/org/jabref/logic/importer/ImporterPreferences.java +++ b/src/main/java/org/jabref/logic/importer/ImporterPreferences.java @@ -1,6 +1,7 @@ package org.jabref.logic.importer; import java.nio.file.Path; +import java.util.Optional; import java.util.Set; import javafx.beans.property.BooleanProperty; @@ -111,4 +112,12 @@ public BooleanProperty persistCustomKeysProperty() { public void setPersistCustomKeys(boolean persistCustomKeys) { this.persistCustomKeys.set(persistCustomKeys); } + + public Optional getApiKey(String name) { + return apiKeys.stream() + .filter(key -> key.getName().equalsIgnoreCase(name)) + .filter(FetcherApiKey::shouldUse) + .findFirst() + .map(FetcherApiKey::getKey); + } } diff --git a/src/main/java/org/jabref/logic/importer/WebFetchers.java b/src/main/java/org/jabref/logic/importer/WebFetchers.java index 95b6fce4f9d..6a7b0f7d07d 100644 --- a/src/main/java/org/jabref/logic/importer/WebFetchers.java +++ b/src/main/java/org/jabref/logic/importer/WebFetchers.java @@ -117,7 +117,7 @@ public static SortedSet getSearchBasedFetchers(ImportFormatP // set.add(new CollectionOfComputerScienceBibliographiesFetcher(importFormatPreferences)); set.add(new DOABFetcher()); // set.add(new JstorFetcher(importFormatPreferences)); - set.add(new SemanticScholar()); + set.add(new SemanticScholar(importerPreferences)); set.add(new ResearchGate(importFormatPreferences)); set.add(new BiodiversityLibrary(importerPreferences)); set.add(new LOBIDFetcher(importerPreferences)); @@ -168,7 +168,7 @@ public static SortedSet getEntryBasedFetchers(ImporterPrefere set.add(new CrossRef()); set.add(new ZbMATH(importFormatPreferences)); set.add(new PdfMergeMetadataImporter.EntryBasedFetcherWrapper(importFormatPreferences, filePreferences, databaseContext)); - set.add(new SemanticScholar()); + set.add(new SemanticScholar(importerPreferences)); set.add(new ResearchGate(importFormatPreferences)); return set; } @@ -206,7 +206,7 @@ public static Set getFullTextFetchers(ImportFormatPreferences i // fetchers.add(new GoogleScholar(importFormatPreferences)); fetchers.add(new CiteSeer()); fetchers.add(new OpenAccessDoi()); - fetchers.add(new SemanticScholar()); + fetchers.add(new SemanticScholar(importerPreferences)); fetchers.add(new ResearchGate(importFormatPreferences)); return fetchers; } diff --git a/src/main/java/org/jabref/logic/importer/fetcher/AstrophysicsDataSystem.java b/src/main/java/org/jabref/logic/importer/fetcher/AstrophysicsDataSystem.java index 60fc30e718c..65a32b295cb 100644 --- a/src/main/java/org/jabref/logic/importer/fetcher/AstrophysicsDataSystem.java +++ b/src/main/java/org/jabref/logic/importer/fetcher/AstrophysicsDataSystem.java @@ -31,7 +31,6 @@ import org.jabref.logic.importer.fetcher.transformers.DefaultQueryTransformer; import org.jabref.logic.importer.fileformat.BibtexParser; import org.jabref.logic.net.URLDownload; -import org.jabref.logic.preferences.FetcherApiKey; import org.jabref.logic.util.BuildInfo; import org.jabref.model.entry.BibEntry; import org.jabref.model.entry.field.StandardField; @@ -84,16 +83,6 @@ public String getName() { return "SAO/NASA ADS"; } - private String getApiKey() { - return importerPreferences.getApiKeys() - .stream() - .filter(key -> key.getName().equalsIgnoreCase(this.getName())) - .filter(FetcherApiKey::shouldUse) - .findFirst() - .map(FetcherApiKey::getKey) - .orElse(API_KEY); - } - /** * @param luceneQuery query string, matching the apache solr format * @return URL which points to a search request for given query @@ -171,7 +160,7 @@ public void doPostCleanup(BibEntry entry) { // Move adsurl to url field new MoveFieldCleanup(new UnknownField("adsurl"), StandardField.URL).cleanup(entry); entry.getField(StandardField.ABSTRACT) - .filter(abstractText -> "Not Available

".equals(abstractText)) + .filter("Not Available

"::equals) .ifPresent(abstractText -> entry.clearField(StandardField.ABSTRACT)); entry.getField(StandardField.ABSTRACT) @@ -259,7 +248,7 @@ private List performSearchByIds(Collection identifiers) throws try { String postData = buildPostData(ids); URLDownload download = new URLDownload(getURLforExport()); - download.addHeader("Authorization", "Bearer " + this.getApiKey()); + download.addHeader("Authorization", "Bearer " + importerPreferences.getApiKey(getName()).orElse(API_KEY)); download.addHeader("ContentType", "application/json"); download.setPostData(postData); String content = download.asString(); @@ -297,8 +286,7 @@ public List performSearch(QueryNode luceneQuery) throws FetcherExcepti throw new FetcherException("A network error occurred", e); } List bibCodes = fetchBibcodes(urlForQuery); - List results = performSearchByIds(bibCodes); - return results; + return performSearchByIds(bibCodes); } @Override @@ -320,7 +308,7 @@ public Page performSearchPaged(QueryNode luceneQuery, int pageNumber) @Override public URLDownload getUrlDownload(URL url) { URLDownload urlDownload = new URLDownload(url); - urlDownload.addHeader("Authorization", "Bearer " + this.getApiKey()); + urlDownload.addHeader("Authorization", "Bearer " + importerPreferences.getApiKey(getName()).orElse(API_KEY)); return urlDownload; } } diff --git a/src/main/java/org/jabref/logic/importer/fetcher/BiodiversityLibrary.java b/src/main/java/org/jabref/logic/importer/fetcher/BiodiversityLibrary.java index 52af28c9766..f118e035a77 100644 --- a/src/main/java/org/jabref/logic/importer/fetcher/BiodiversityLibrary.java +++ b/src/main/java/org/jabref/logic/importer/fetcher/BiodiversityLibrary.java @@ -17,7 +17,6 @@ import org.jabref.logic.importer.fetcher.transformers.BiodiversityLibraryTransformer; import org.jabref.logic.importer.util.JsonReader; import org.jabref.logic.net.URLDownload; -import org.jabref.logic.preferences.FetcherApiKey; import org.jabref.logic.util.BuildInfo; import org.jabref.model.entry.Author; import org.jabref.model.entry.AuthorList; @@ -64,7 +63,7 @@ public String getTestUrl() { public URL getBaseURL() throws URISyntaxException, MalformedURLException { URIBuilder baseURI = new URIBuilder(BASE_URL); - baseURI.addParameter("apikey", getApiKey()); + baseURI.addParameter("apikey", importerPreferences.getApiKey(getName()).orElse(API_KEY)); baseURI.addParameter("format", RESPONSE_FORMAT); return baseURI.build().toURL(); @@ -209,14 +208,4 @@ public URL getURLForQuery(QueryNode luceneQuery) throws URISyntaxException, Malf uriBuilder.addParameter("searchterm", transformer.transformLuceneQuery(luceneQuery).orElse("")); return uriBuilder.build().toURL(); } - - private String getApiKey() { - return importerPreferences.getApiKeys() - .stream() - .filter(key -> key.getName().equalsIgnoreCase(this.getName())) - .filter(FetcherApiKey::shouldUse) - .findFirst() - .map(FetcherApiKey::getKey) - .orElse(API_KEY); - } } diff --git a/src/main/java/org/jabref/logic/importer/fetcher/IEEE.java b/src/main/java/org/jabref/logic/importer/fetcher/IEEE.java index 20242693755..398ebf62fc1 100644 --- a/src/main/java/org/jabref/logic/importer/fetcher/IEEE.java +++ b/src/main/java/org/jabref/logic/importer/fetcher/IEEE.java @@ -23,7 +23,6 @@ import org.jabref.logic.importer.Parser; import org.jabref.logic.importer.fetcher.transformers.IEEEQueryTransformer; import org.jabref.logic.net.URLDownload; -import org.jabref.logic.preferences.FetcherApiKey; import org.jabref.logic.util.BuildInfo; import org.jabref.logic.util.OS; import org.jabref.model.entry.BibEntry; @@ -250,13 +249,7 @@ public Optional getHelpPage() { } private String getApiKey() { - return importerPreferences.getApiKeys() - .stream() - .filter(key -> key.getName().equalsIgnoreCase(this.getName())) - .filter(FetcherApiKey::shouldUse) - .findFirst() - .map(FetcherApiKey::getKey) - .orElse(API_KEY); + return importerPreferences.getApiKey(getName()).orElse(API_KEY); } @Override diff --git a/src/main/java/org/jabref/logic/importer/fetcher/ScienceDirect.java b/src/main/java/org/jabref/logic/importer/fetcher/ScienceDirect.java index 96a30c3703f..8b555e2da2f 100644 --- a/src/main/java/org/jabref/logic/importer/fetcher/ScienceDirect.java +++ b/src/main/java/org/jabref/logic/importer/fetcher/ScienceDirect.java @@ -10,7 +10,6 @@ import org.jabref.logic.importer.FulltextFetcher; import org.jabref.logic.importer.ImporterPreferences; import org.jabref.logic.net.URLDownload; -import org.jabref.logic.preferences.FetcherApiKey; import org.jabref.logic.util.BuildInfo; import org.jabref.model.entry.BibEntry; import org.jabref.model.entry.field.StandardField; @@ -140,7 +139,7 @@ private String getUrlByDoi(String doi) throws UnirestException { try { String request = API_URL + doi; HttpResponse jsonResponse = Unirest.get(request) - .header("X-ELS-APIKey", this.getApiKey()) + .header("X-ELS-APIKey", importerPreferences.getApiKey(getName()).orElse(API_KEY)) .queryString("httpAccept", "application/json") .asJson(); @@ -166,14 +165,4 @@ private String getUrlByDoi(String doi) throws UnirestException { public String getName() { return FETCHER_NAME; } - - private String getApiKey() { - return importerPreferences.getApiKeys() - .stream() - .filter(key -> key.getName().equalsIgnoreCase(this.getName())) - .filter(FetcherApiKey::shouldUse) - .findFirst() - .map(FetcherApiKey::getKey) - .orElse(API_KEY); - } } diff --git a/src/main/java/org/jabref/logic/importer/fetcher/SemanticScholar.java b/src/main/java/org/jabref/logic/importer/fetcher/SemanticScholar.java index 4d56eb7aa6d..cde8ae98ece 100644 --- a/src/main/java/org/jabref/logic/importer/fetcher/SemanticScholar.java +++ b/src/main/java/org/jabref/logic/importer/fetcher/SemanticScholar.java @@ -15,6 +15,7 @@ import org.jabref.logic.importer.EntryBasedFetcher; import org.jabref.logic.importer.FetcherException; import org.jabref.logic.importer.FulltextFetcher; +import org.jabref.logic.importer.ImporterPreferences; import org.jabref.logic.importer.PagedSearchBasedParserFetcher; import org.jabref.logic.importer.ParseException; import org.jabref.logic.importer.Parser; @@ -38,12 +39,17 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -public class SemanticScholar implements FulltextFetcher, PagedSearchBasedParserFetcher, EntryBasedFetcher { +public class SemanticScholar implements FulltextFetcher, PagedSearchBasedParserFetcher, EntryBasedFetcher, CustomizableKeyFetcher { private static final Logger LOGGER = LoggerFactory.getLogger(SemanticScholar.class); private static final String SOURCE_ID_SEARCH = "https://api.semanticscholar.org/v1/paper/"; private static final String SOURCE_WEB_SEARCH = "https://api.semanticscholar.org/graph/v1/paper/search?"; + private final ImporterPreferences importerPreferences; + + public SemanticScholar(ImporterPreferences importerPreferences) { + this.importerPreferences = importerPreferences; + } /** * Tries to find a fulltext URL for a given BibTex entry. @@ -67,12 +73,15 @@ public Optional findFullText(BibEntry entry) throws IOException, FetcherExc try { // Retrieve PDF link String source = SOURCE_ID_SEARCH + doi.get().getDOI(); - html = Jsoup.connect(getURLBySource(source)) - .userAgent(URLDownload.USER_AGENT) - .referrer("https://www.google.com") - .ignoreHttpErrors(true) - .get(); - } catch (IOException e) { + var jsoupRequest = Jsoup.connect(getURLBySource(source)) + .userAgent(URLDownload.USER_AGENT) + .referrer("https://www.google.com") + .ignoreHttpErrors(true); + importerPreferences.getApiKey(getName()).ifPresent( + key -> jsoupRequest.header("x-api-key", key)); + html = jsoupRequest.get(); + } catch ( + IOException e) { LOGGER.info("Error for pdf lookup with DOI"); } } @@ -83,11 +92,13 @@ public Optional findFullText(BibEntry entry) throws IOException, FetcherExc arXivString = "arXiv:" + arXivString; } String source = SOURCE_ID_SEARCH + arXivString; - html = Jsoup.connect(getURLBySource(source)) - .userAgent(URLDownload.USER_AGENT) - .referrer("https://www.google.com") - .ignoreHttpErrors(true) - .get(); + var jsoupRequest = Jsoup.connect(getURLBySource(source)) + .userAgent(URLDownload.USER_AGENT) + .referrer("https://www.google.com") + .ignoreHttpErrors(true); + importerPreferences.getApiKey(getName()).ifPresent( + key -> jsoupRequest.header("x-api-key", key)); + html = jsoupRequest.get(); } if (html == null) { return Optional.empty(); diff --git a/src/main/java/org/jabref/logic/importer/fetcher/SpringerFetcher.java b/src/main/java/org/jabref/logic/importer/fetcher/SpringerFetcher.java index 4815206a1ae..c2acb59c04a 100644 --- a/src/main/java/org/jabref/logic/importer/fetcher/SpringerFetcher.java +++ b/src/main/java/org/jabref/logic/importer/fetcher/SpringerFetcher.java @@ -16,7 +16,6 @@ import org.jabref.logic.importer.PagedSearchBasedParserFetcher; import org.jabref.logic.importer.Parser; import org.jabref.logic.importer.fetcher.transformers.SpringerQueryTransformer; -import org.jabref.logic.preferences.FetcherApiKey; import org.jabref.logic.util.BuildInfo; import org.jabref.logic.util.OS; import org.jabref.model.entry.BibEntry; @@ -172,16 +171,6 @@ public Optional getHelpPage() { return Optional.of(HelpFile.FETCHER_SPRINGER); } - private String getApiKey() { - return importerPreferences.getApiKeys() - .stream() - .filter(key -> key.getName().equalsIgnoreCase(FETCHER_NAME)) - .filter(FetcherApiKey::shouldUse) - .findFirst() - .map(FetcherApiKey::getKey) - .orElse(API_KEY); - } - @Override public String getTestUrl() { return TEST_URL_WITHOUT_API_KEY; @@ -199,7 +188,7 @@ public URL getURLForQuery(QueryNode luceneQuery, int pageNumber) throws URISynta URIBuilder uriBuilder = new URIBuilder(API_URL); uriBuilder.addParameter("q", new SpringerQueryTransformer().transformLuceneQuery(luceneQuery).orElse("")); // Search query - uriBuilder.addParameter("api_key", getApiKey()); // API key + uriBuilder.addParameter("api_key", importerPreferences.getApiKey(getName()).orElse(API_KEY)); // API key uriBuilder.addParameter("s", String.valueOf(getPageSize() * pageNumber + 1)); // Start entry, starts indexing at 1 uriBuilder.addParameter("p", String.valueOf(getPageSize())); // Page size return uriBuilder.build().toURL(); diff --git a/src/main/java/org/jabref/logic/importer/fetcher/SpringerLink.java b/src/main/java/org/jabref/logic/importer/fetcher/SpringerLink.java index 769e7f6c200..57ad994c78d 100644 --- a/src/main/java/org/jabref/logic/importer/fetcher/SpringerLink.java +++ b/src/main/java/org/jabref/logic/importer/fetcher/SpringerLink.java @@ -7,7 +7,6 @@ import org.jabref.logic.importer.FulltextFetcher; import org.jabref.logic.importer.ImporterPreferences; -import org.jabref.logic.preferences.FetcherApiKey; import org.jabref.logic.util.BuildInfo; import org.jabref.model.entry.BibEntry; import org.jabref.model.entry.field.StandardField; @@ -26,7 +25,7 @@ *

* Uses Springer API, see https://dev.springer.com */ -public class SpringerLink implements FulltextFetcher { +public class SpringerLink implements FulltextFetcher, CustomizableKeyFetcher { public static final String FETCHER_NAME = "Springer"; private static final Logger LOGGER = LoggerFactory.getLogger(SpringerLink.class); @@ -41,16 +40,6 @@ public SpringerLink(ImporterPreferences importerPreferences) { this.importerPreferences = importerPreferences; } - private String getApiKey() { - return importerPreferences.getApiKeys() - .stream() - .filter(key -> key.getName().equalsIgnoreCase(FETCHER_NAME)) - .filter(FetcherApiKey::shouldUse) - .findFirst() - .map(FetcherApiKey::getKey) - .orElse(API_KEY); - } - @Override public Optional findFullText(BibEntry entry) throws IOException { Objects.requireNonNull(entry); @@ -64,7 +53,7 @@ public Optional findFullText(BibEntry entry) throws IOException { // Available in catalog? try { HttpResponse jsonResponse = Unirest.get(API_URL) - .queryString("api_key", getApiKey()) + .queryString("api_key", importerPreferences.getApiKey(getName()).orElse(API_KEY)) .queryString("q", String.format("doi:%s", doi.get().getDOI())) .asJson(); if (jsonResponse.getBody() != null) { @@ -86,4 +75,9 @@ public Optional findFullText(BibEntry entry) throws IOException { public TrustLevel getTrustLevel() { return TrustLevel.PUBLISHER; } + + @Override + public String getName() { + return FETCHER_NAME; + } } diff --git a/src/main/java/org/jabref/logic/importer/fetcher/ZbMATH.java b/src/main/java/org/jabref/logic/importer/fetcher/ZbMATH.java index 51d1f734399..f1b0b5fb32c 100644 --- a/src/main/java/org/jabref/logic/importer/fetcher/ZbMATH.java +++ b/src/main/java/org/jabref/logic/importer/fetcher/ZbMATH.java @@ -89,7 +89,7 @@ public URL getURLForEntry(BibEntry entry) throws URISyntaxException, MalformedUR JSONArray result = response.getBody() .getObject() .getJSONArray("results"); - if (result.length() > 0) { + if (!result.isEmpty()) { zblid = result.getJSONObject(0) .get("zbl_id") .toString(); diff --git a/src/test/java/org/jabref/logic/importer/fetcher/SemanticScholarTest.java b/src/test/java/org/jabref/logic/importer/fetcher/SemanticScholarTest.java index c546c73718c..806f400009c 100644 --- a/src/test/java/org/jabref/logic/importer/fetcher/SemanticScholarTest.java +++ b/src/test/java/org/jabref/logic/importer/fetcher/SemanticScholarTest.java @@ -2,6 +2,7 @@ import java.io.IOException; import java.net.MalformedURLException; +import java.net.URI; import java.net.URISyntaxException; import java.net.URL; import java.util.Collections; @@ -9,6 +10,7 @@ import java.util.Optional; import org.jabref.logic.importer.FetcherException; +import org.jabref.logic.importer.ImporterPreferences; import org.jabref.logic.importer.PagedSearchBasedFetcher; import org.jabref.model.entry.BibEntry; import org.jabref.model.entry.field.StandardField; @@ -23,12 +25,15 @@ import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.Mockito.mock; @FetcherTest public class SemanticScholarTest implements PagedSearchFetcherTest { private static final String DOI = "10.23919/IFIPNetworking52078.2021.9472772"; + private final ImporterPreferences importerPreferences = mock(ImporterPreferences.class); + private final BibEntry IGOR_NEWCOMERS = new BibEntry(StandardEntryType.Article) .withField(StandardField.AUTHOR, "Igor Steinmacher and T. Conte and Christoph Treude and M. Gerosa") .withField(StandardField.YEAR, "2016") @@ -42,7 +47,7 @@ public class SemanticScholarTest implements PagedSearchFetcherTest { @BeforeEach void setUp() { - fetcher = new SemanticScholar(); + fetcher = new SemanticScholar(importerPreferences); entry = new BibEntry(); } @@ -56,19 +61,19 @@ void getDocument() throws IOException, FetcherException { @Test @DisabledOnCIServer("CI server is unreliable") - void fullTextFindByDOI() throws IOException, FetcherException { + void fullTextFindByDOI() throws Exception { entry.withField(StandardField.DOI, "10.1038/nrn3241"); assertEquals( - Optional.of(new URL("https://europepmc.org/articles/pmc4907333?pdf=render")), + Optional.of(new URI("https://europepmc.org/articles/pmc4907333?pdf=render").toURL()), fetcher.findFullText(entry) ); } @Test @DisabledOnCIServer("CI server is unreliable") - void fullTextFindByDOIAlternate() throws IOException, FetcherException { + void fullTextFindByDOIAlternate() throws Exception { assertEquals( - Optional.of(new URL("https://pdfs.semanticscholar.org/7f6e/61c254bc2df38a784c1228f56c13317caded.pdf")), + Optional.of(new URI("https://pdfs.semanticscholar.org/7f6e/61c254bc2df38a784c1228f56c13317caded.pdf").toURL()), fetcher.findFullText(new BibEntry() .withField(StandardField.DOI, "10.3390/healthcare9020206"))); } @@ -91,11 +96,11 @@ void fullTextNotFoundByDOI() throws IOException, FetcherException { @Test @DisabledOnCIServer("CI server is unreliable") - void fullTextFindByArXiv() throws IOException, FetcherException { + void fullTextFindByArXiv() throws Exception { entry = new BibEntry().withField(StandardField.EPRINT, "1407.3561") .withField(StandardField.ARCHIVEPREFIX, "arXiv"); assertEquals( - Optional.of(new URL("https://arxiv.org/pdf/1407.3561.pdf")), + Optional.of(new URI("https://arxiv.org/pdf/1407.3561.pdf").toURL()), fetcher.findFullText(entry) ); } From 847b732a4a4061e115e7645deeed313a1debbd97 Mon Sep 17 00:00:00 2001 From: Oliver Kopp Date: Tue, 24 Oct 2023 01:13:36 +0200 Subject: [PATCH 11/44] Try other github.token --- .github/workflows/add-to-projects.yml | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/.github/workflows/add-to-projects.yml b/.github/workflows/add-to-projects.yml index 83ab818bbbb..3729f2bb062 100644 --- a/.github/workflows/add-to-projects.yml +++ b/.github/workflows/add-to-projects.yml @@ -4,6 +4,9 @@ on: issues: types: [labeled] +permissions: + issues: write + jobs: add-to-project: runs-on: ubuntu-latest @@ -12,28 +15,28 @@ jobs: - name: "good first issue" if: "${{ github.event.label.name == 'good first issue' }}" env: - GH_TOKEN: ${{ secrets.PROJECT_TOKEN }} + GH_TOKEN: ${{ github.token }} run: | ISSUE_URL=$(jq --raw-output .issue.html_url "$GITHUB_EVENT_PATH") gh project item-add 5 --owner jabref --url $ISSUE_URL - name: needs-refinement if: github.event.label.name == 'needs-refinement' env: - GH_TOKEN: ${{ secrets.PROJECT_TOKEN }} + GH_TOKEN: ${{ github.token }} run: | ISSUE_URL=$(jq --raw-output .issue.html_url "$GITHUB_EVENT_PATH") gh project item-add 15 --owner jabref --url $ISSUE_URL - name: "status: freeze" if: "${{ github.event.label.name == 'status: freeze' }}" env: - GH_TOKEN: ${{ secrets.PROJECT_TOKEN }} + GH_TOKEN: ${{ github.token }} run: | ISSUE_URL=$(jq --raw-output .issue.html_url "$GITHUB_EVENT_PATH") gh project item-add 9 --owner jabref --url $ISSUE_URL - name: ui if: "${{ github.event.label.name == 'ui' }}" env: - GH_TOKEN: ${{ secrets.PROJECT_TOKEN }} + GH_TOKEN: ${{ github.token }} run: | ISSUE_URL=$(jq --raw-output .issue.html_url "$GITHUB_EVENT_PATH") gh project item-add 8 --owner jabref --url $ISSUE_URL From fdb26fe54cb1317e38cf2901468cc6481f5ab3a9 Mon Sep 17 00:00:00 2001 From: Oscar <71343264+0scvr@users.noreply.github.com> Date: Tue, 24 Oct 2023 11:42:00 +0200 Subject: [PATCH 12/44] Update Java version in gitpod config (#10566) --- .gitpod.Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitpod.Dockerfile b/.gitpod.Dockerfile index 007108a0f49..0e80edc3ec8 100644 --- a/.gitpod.Dockerfile +++ b/.gitpod.Dockerfile @@ -5,4 +5,4 @@ FROM gitpod/workspace-full # All available versions can be listed using sdk ls java # More information about SDKMAN available at https://github.com/sdkman/sdkman-cli#sdkman-cli RUN bash -c ". /home/gitpod/.sdkman/bin/sdkman-init.sh \ - && sdk install java 18.0.1.1-open" + && sdk install java 21-open" From 31f137bcf22c15314f9bc951b694286b34ab2f2f Mon Sep 17 00:00:00 2001 From: Oliver Kopp Date: Tue, 24 Oct 2023 12:09:36 +0200 Subject: [PATCH 13/44] Update to latest recipes (#10564) --- build.gradle | 2 +- .../java/org/jabref/logic/importer/fetcher/ArXivFetcher.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/build.gradle b/build.gradle index 31a0ea7c2f2..2600023df0a 100644 --- a/build.gradle +++ b/build.gradle @@ -250,7 +250,7 @@ dependencies { xjc group: 'org.glassfish.jaxb', name: 'jaxb-xjc', version: '3.0.2' xjc group: 'org.glassfish.jaxb', name: 'jaxb-runtime', version: '3.0.2' - rewrite(platform("org.openrewrite.recipe:rewrite-recipe-bom:2.4.0")) + rewrite(platform("org.openrewrite.recipe:rewrite-recipe-bom:latest.integration")) rewrite("org.openrewrite.recipe:rewrite-static-analysis") rewrite("org.openrewrite.recipe:rewrite-logging-frameworks") rewrite("org.openrewrite.recipe:rewrite-testing-frameworks") diff --git a/src/main/java/org/jabref/logic/importer/fetcher/ArXivFetcher.java b/src/main/java/org/jabref/logic/importer/fetcher/ArXivFetcher.java index b3abf1fd699..6586226e275 100644 --- a/src/main/java/org/jabref/logic/importer/fetcher/ArXivFetcher.java +++ b/src/main/java/org/jabref/logic/importer/fetcher/ArXivFetcher.java @@ -442,7 +442,7 @@ private Optional searchForEntryById(String id) throws FetcherExcepti } List entries = queryApi("", Collections.singletonList(identifier.get()), 0, 1); - if (entries.size() >= 1) { + if (!entries.isEmpty()) { return Optional.of(entries.get(0)); } else { return Optional.empty(); From 082c17653cd72bcef8e011300f6ba4ec483be038 Mon Sep 17 00:00:00 2001 From: Oliver Kopp Date: Tue, 24 Oct 2023 12:55:30 +0200 Subject: [PATCH 14/44] Update build.gradle (#10567) --- build.gradle | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 2600023df0a..c77ae3f8613 100644 --- a/build.gradle +++ b/build.gradle @@ -48,7 +48,9 @@ java { modularity.inferModulePath.set(false) toolchain { - // If this is updated, also update .devcontainer/devcontainer.json#L34 + // If this is updated, also update + // - .devcontainer/devcontainer.json#L34 and + // - .gitpod.Dockerfile languageVersion = JavaLanguageVersion.of(21) } } From f6334e904c573774e292e560bbfcd2aefd218146 Mon Sep 17 00:00:00 2001 From: Christoph Date: Tue, 24 Oct 2023 15:56:46 +0200 Subject: [PATCH 15/44] New Crowdin updates (#10570) Co-authored-by: Oliver Kopp --- .github/workflows/automerge.yml | 14 ++++++++++---- src/main/resources/l10n/JabRef_fa.properties | 1 + src/main/resources/l10n/JabRef_fr.properties | 1 + src/main/resources/l10n/JabRef_it.properties | 1 + src/main/resources/l10n/JabRef_pl.properties | 17 +++++++++++++++++ src/main/resources/l10n/JabRef_pt_BR.properties | 7 ++++--- 6 files changed, 34 insertions(+), 7 deletions(-) diff --git a/.github/workflows/automerge.yml b/.github/workflows/automerge.yml index f2cc18a22f9..7d339a6355d 100644 --- a/.github/workflows/automerge.yml +++ b/.github/workflows/automerge.yml @@ -10,10 +10,16 @@ jobs: runs-on: ubuntu-latest # Run only if PR is inside JabRef's main repository and created by dependabot or by an update workflow if: > - (github.repository == 'JabRef/jabref') && - ((github.actor == 'dependabot[bot]') || - ((startsWith(github.event.pull_request.title, '[Bot] ') || (startsWith(github.event.pull_request.title, 'Bump '))) && - (github.event.pull_request.head.repo.full_name == 'JabRef/jabref'))) + (github.repository == 'JabRef/jabref') && + (github.event.pull_request.head.repo.full_name == 'JabRef/jabref') && + ( + (github.actor == 'dependabot[bot]') || + ( + startsWith(github.event.pull_request.title, '[Bot] ') || + startsWith(github.event.pull_request.title, 'Bump ') || + startsWith(github.event.pull_request.title, 'New Crowdin updates') + ) + ) steps: - name: Approve PR run: gh pr review --approve "$PR_URL" diff --git a/src/main/resources/l10n/JabRef_fa.properties b/src/main/resources/l10n/JabRef_fa.properties index 0f1d081fb8e..0e24b672115 100644 --- a/src/main/resources/l10n/JabRef_fa.properties +++ b/src/main/resources/l10n/JabRef_fa.properties @@ -1,3 +1,4 @@ +Proxy\ requires\ password=پراکسی به رمز عبور نیاز دارد Unable\ to\ monitor\ file\ changes.\ Please\ close\ files\ and\ processes\ and\ restart.\ You\ may\ encounter\ errors\ if\ you\ continue\ with\ this\ session.=قادر به نمايش تغيير پرونده نمی باشد. لطفا پرونده ها و فرايند ها را بسته و شروع دوباره كنيد. در صورت ادامه ممكن است با خطاهایی مواجه شويد. diff --git a/src/main/resources/l10n/JabRef_fr.properties b/src/main/resources/l10n/JabRef_fr.properties index 6317ee80c65..6df2ca8b1aa 100644 --- a/src/main/resources/l10n/JabRef_fr.properties +++ b/src/main/resources/l10n/JabRef_fr.properties @@ -839,6 +839,7 @@ Search\ results\ from\ open\ libraries=Résultats de recherche pour les fichiers Select\ all=Tout sélectionner Select\ new\ encoding=Sélectionner un nouvel encodage +Select\ library=Sélectionner le fichier Select\ entry\ type=Sélectionner un type d'entrée Select\ file\ from\ ZIP-archive=Sélectionner un fichier depuis une archive ZIP diff --git a/src/main/resources/l10n/JabRef_it.properties b/src/main/resources/l10n/JabRef_it.properties index 4d39226f8fd..73d93d639a1 100644 --- a/src/main/resources/l10n/JabRef_it.properties +++ b/src/main/resources/l10n/JabRef_it.properties @@ -839,6 +839,7 @@ Search\ results\ from\ open\ libraries=Risultati della ricerca da librerie apert Select\ all=Seleziona tutto Select\ new\ encoding=Seleziona la nuova codifica +Select\ library=Seleziona la biblioteca Select\ entry\ type=Seleziona un tipo di voce Select\ file\ from\ ZIP-archive=Seleziona un file da un archivio ZIP diff --git a/src/main/resources/l10n/JabRef_pl.properties b/src/main/resources/l10n/JabRef_pl.properties index 55d76acfb6d..5bfc22fc4f3 100644 --- a/src/main/resources/l10n/JabRef_pl.properties +++ b/src/main/resources/l10n/JabRef_pl.properties @@ -318,7 +318,13 @@ Export\ preferences\ to\ file=Eksportuj ustawienia do pliku Export\ to\ clipboard=Eksportuj do schowka Export\ to\ text\ file.=Eksportuj do pliku tekstowego. +Exporting\ %0=Eksportowanie %0 +Could\ not\ export\ file\ '%0'\ (reason\:\ %1)=Nie można wyeksportować pliku '%0' (powód\: %1) +Unknown\ export\ format\ %0=Nieznany format eksportu %0 +Importing\ %0=Importowanie %0 +Importing\ file\ %0\ as\ unknown\ format=Importowanie pliku %0 jako nieznany format +Format\ used\:\ %0=Użyty format\: %0 Extension=Rozszerzenie @@ -466,6 +472,7 @@ Incorrect\ ISSN\ format=Nieprawidłowy format ISSN Error\ accessing\ catalog=Błąd dostępu do katalogu Check\ for\ latest\ version\ online=Sprawdź najnowszą wersję online +If\ you\ encounter\ an\ issue\ or\ a\ bug,\ please\ check\ the\ latest\ version,\ whether\ the\ issue\ is\ still\ present.=Jeśli napotkasz problem lub błąd, sprawdź w najnowszej wersję, czy problem nadal występuje. Keep\ both=Zachowaj oba @@ -545,6 +552,7 @@ New\ group=Nowa grupa New\ string=Nowy ciąg znaków Next\ entry=Następny wpis +no\ base-BibTeX-file\ specified\!=nie określono pliku bazowego BibTeX\! no\ library\ generated=nie wygenerowano biblioteki @@ -805,6 +813,7 @@ Search\ results\ from\ open\ libraries=Wyniki przeszukiwania otwartych bibliotek Select\ all=Wybierz wszystko Select\ new\ encoding=Wybierz nowe kodowanie +Select\ library=Wybierz bibliotekę Select\ entry\ type=Wybierz typ wpisu Select\ file\ from\ ZIP-archive=Wybierz plik z archiwum ZIP @@ -848,6 +857,9 @@ Open\ library\ error=Błąd podczas otwierania biblioteki Please\ check\ your\ library\ file\ for\ wrong\ syntax.=Proszę sprawdzić plik biblioteki pod kątem nieprawidłowej składni. Sort\ subgroups\ A-Z=Sortuj podgrupy A-Z +Sort\ subgroups\ Z-A=Sortuj podgrupy A-Z +Sort\ subgroups\ by\ \#\ of\ entries\ (Descending)=Sortuj podgrupy według \# wpisów (malejąco) +Sort\ subgroups\ by\ \#\ of\ entries\ (Ascending)=Sortuj podgrupy według \# wpisów (rosnąco) source\ edit=edycja źródła @@ -967,6 +979,7 @@ Rename\ field=Zmień nazwę pola A\ local\ copy\ will\ be\ opened.=Kopia lokalna zostanie otwarta. Error\ opening\ file=Błąd podczas otwierania pliku +Error\ opening\ file\ '%0'=Błąd podczas otwierania pliku '%0' Metadata\ change=Zmiana metadanych @@ -1339,6 +1352,7 @@ Looking\ up\ %0...\ -\ entry\ %1\ out\ of\ %2\ -\ found\ %3=Szukanie %0... - wpi Audio\ CD=CD audio British\ patent=Patent brytyjski British\ patent\ request=Zgłoszenie o brytyjski patent +Bachelor's\ thesis=Praca licencjacka Column=Kolumna Compiler=Kompilator Data\ CD=CD z danymi @@ -1733,4 +1747,7 @@ Finished\ writing\ metadata\ for\ library\ %0\ (%1\ succeeded,\ %2\ skipped,\ %3 Processing...=Przetwarzanie... +Cancel\ search=Anuluj wyszukiwanie +Select\ entry=Wybierz wpis +Search\ aborted\!=Wyszukiwanie przerwane\! diff --git a/src/main/resources/l10n/JabRef_pt_BR.properties b/src/main/resources/l10n/JabRef_pt_BR.properties index bf3321e7a88..8efbf0f319c 100644 --- a/src/main/resources/l10n/JabRef_pt_BR.properties +++ b/src/main/resources/l10n/JabRef_pt_BR.properties @@ -269,7 +269,7 @@ Downloaded\ website\ as\ an\ HTML\ file.=Site baixado como arquivo HTML. duplicate\ removal=remoção de duplicatas -Duplicate\ fields=Duplicar campos +Duplicate\ fields=Campos duplicados Unable\ to\ change\ field\ name.\ "%0"\ already\ in\ use.=Não é possível alterar o nome do campo. "%0" já está em uso. @@ -839,6 +839,7 @@ Search\ results\ from\ open\ libraries=Resultados da pesquisa para as biblioteca Select\ all=Selecionar tudo Select\ new\ encoding=Selecionar codificação +Select\ library=Selecionar biblioteca Select\ entry\ type=Selecionar tipo de referência Select\ file\ from\ ZIP-archive=Selecionar arquivo a partir de um arquivo ZIP @@ -1557,7 +1558,7 @@ Looking\ up\ %0...\ -\ entry\ %1\ out\ of\ %2\ -\ found\ %3=Procurando %0... - r Audio\ CD=CD de Áudio British\ patent=Patente britânica British\ patent\ request=Pedido de patente britânico -Bachelor's\ thesis=Tese de Bacharel +Bachelor's\ thesis=Tese de Bacharel (monografia) Candidate\ thesis=Tese candidata Collaborator=Colaborador Column=Coluna @@ -1650,7 +1651,7 @@ No\ bibliography\ style\ is\ selected\ for\ citation.=Nenhum estilo bibliográfi No\ database=Nenhum banco de dados No\ entries\ selected\ for\ citation=Não há referências selecionadas para referência -Open\ one\ before\ citing.=Abra-a antes de citar. +Open\ one\ before\ citing.=Abra um antes de citar. Select\ one\ before\ citing.=Selecione uma antes de citar. Select\ some\ before\ citing.=Selecione algum antes de citar. From 956e9f6053b236eab545f71e40c85d3981ac319f Mon Sep 17 00:00:00 2001 From: Christoph Date: Tue, 24 Oct 2023 21:21:23 +0200 Subject: [PATCH 16/44] Fix file field merging (#10573) Add test Fixes https://github.com/JabRef/jabref/issues/10572 --- CHANGELOG.md | 1 + .../fieldsmerger/FileMerger.java | 9 ++--- .../fieldsmerger/FileMergerTest.java | 36 +++++++++++++++++++ 3 files changed, 40 insertions(+), 6 deletions(-) create mode 100644 src/test/java/org/jabref/gui/mergeentries/newmergedialog/fieldsmerger/FileMergerTest.java diff --git a/CHANGELOG.md b/CHANGELOG.md index 3c4869a0d16..6e5a7853897 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,6 +20,7 @@ Note that this project **does not** adhere to [Semantic Versioning](https://semv ### Fixed - We fixed an issue where the added protected term has unwanted leading and trailing whitespaces, where the formatted text has unwanted empty brackets and where the word at the cursor in the textbox can be added to the list [#10415](https://github.com/JabRef/jabref/issues/10415). +- We fixed an issue where in the merge dialog the file field of entries was not correctly merged when the first and second entry both contained values inside the file field [#10572](https://github.com/JabRef/jabref/issues/10572) ### Removed diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/fieldsmerger/FileMerger.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/fieldsmerger/FileMerger.java index 4b4e2034226..91063b931f1 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/fieldsmerger/FileMerger.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/fieldsmerger/FileMerger.java @@ -1,8 +1,6 @@ package org.jabref.gui.mergeentries.newmergedialog.fieldsmerger; import java.util.List; -import java.util.stream.Collectors; -import java.util.stream.Stream; import org.jabref.logic.bibtex.FileFieldWriter; import org.jabref.logic.importer.util.FileFieldParser; @@ -25,10 +23,9 @@ public String merge(String filesA, String filesB) { } else { List linkedFilesA = FileFieldParser.parse(filesA); List linkedFilesB = FileFieldParser.parse(filesB); - // TODO: If one of the linked files list is empty then the its string value is malformed. - return Stream.concat(linkedFilesA.stream(), linkedFilesB.stream()) - .map(FileFieldWriter::getStringRepresentation) - .collect(Collectors.joining()); + + linkedFilesA.addAll(linkedFilesB); + return FileFieldWriter.getStringRepresentation(linkedFilesA); } } } diff --git a/src/test/java/org/jabref/gui/mergeentries/newmergedialog/fieldsmerger/FileMergerTest.java b/src/test/java/org/jabref/gui/mergeentries/newmergedialog/fieldsmerger/FileMergerTest.java new file mode 100644 index 00000000000..164015cbfdc --- /dev/null +++ b/src/test/java/org/jabref/gui/mergeentries/newmergedialog/fieldsmerger/FileMergerTest.java @@ -0,0 +1,36 @@ +package org.jabref.gui.mergeentries.newmergedialog.fieldsmerger; + +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.CsvSource; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +class FileMergerTest { + FileMerger fileMerger = new FileMerger(); + + /** + * Test the following cases + * nullvalues + * emptyString for FileB + * emptyString for FileA + * FileA and FileB are valid strings and are separated by semicolon + * + * @param expect Expected value + * @param fileA File string a + * @param fileB File String b + */ + @ParameterizedTest + @CsvSource(textBlock = """ + ,,, + FileA,FileA, + FileA,FileA,'' + FileB, ,FileB + FileB,'',FileB + :A2012 -A.pdf:PDF;B2013 - B.pdf:PDF:,:A2012 -A.pdf:PDF,B2013 - B.pdf:PDF + :A2012 -A.pdf:;B2013 - B.pdf:PDF:,A2012 -A.pdf,B2013 - B.pdf:PDF + :A2012 -A.pdf:;:asdf:,A2012 -A.pdf,asdf + """) + void testMerge(String expect, String fileA, String fileB) { + assertEquals(expect, fileMerger.merge(fileA, fileB)); + } +} From 4828b7fde898d954474f7cef4fb1ecc03d41a479 Mon Sep 17 00:00:00 2001 From: Oliver Kopp Date: Tue, 24 Oct 2023 23:04:32 +0200 Subject: [PATCH 17/44] Enable collecting GitHub build artifacts for forks (#10574) --- .github/workflows/deployment.yml | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/.github/workflows/deployment.yml b/.github/workflows/deployment.yml index 0352cf29551..c23f0ccf516 100644 --- a/.github/workflows/deployment.yml +++ b/.github/workflows/deployment.yml @@ -224,6 +224,13 @@ jobs: # tbn = to-be-notarized name: JabRef-macOS-tbn path: build/distribution + - name: Upload to GitHub workflow artifacts store + if: (steps.checksecrets.outputs.secretspresent != 'YES') + uses: actions/upload-artifact@v3 + with: + # tbn = to-be-notarized + name: JabRef-${{ matrix.os }} + path: build/distribution announce: name: Comment on pull request runs-on: ubuntu-latest @@ -242,7 +249,7 @@ jobs: env: BUILDJABREFPRIVATEKEY: ${{ secrets.buildJabRefPrivateKey }} - name: Comment PR - if: steps.checksecrets.outputs.secretspresent == 'YES' + if: (steps.checksecrets.outputs.secretspresent == 'YES') uses: thollander/actions-comment-pull-request@v2 with: message: | From b06e1ec3ab79d3f7d8cc2137d1754ceed80bfaf1 Mon Sep 17 00:00:00 2001 From: Oliver Kopp Date: Wed, 25 Oct 2023 14:12:00 +0200 Subject: [PATCH 18/44] Fix link (#10575) --- docs/contributing.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/contributing.md b/docs/contributing.md index c0b04513625..bd187bf1f3f 100644 --- a/docs/contributing.md +++ b/docs/contributing.md @@ -18,7 +18,7 @@ We welcome contributions to JabRef and encourage you to follow the GitHub workfl 1. Fork the JabRef into your GitHub account. 2. Clone your forked repository on your local machine. 2. **Create a new branch** (such as `fix-for-issue-121`). Be sure to create a **separate branch** for each improvement you implement. -3. Work on the **new branch — not the `main` branch.** Refer to our [code how-tos](https://devdocs.jabref.org/getting-into-the-code/code-howtos) if you have questions about your implementation. +3. Work on the **new branch — not the `main` branch.** Refer to our [code how-tos](https://devdocs.jabref.org/code-howtos) if you have questions about your implementation. 4. Create a pull request. For an overview of pull requests, take a look at GitHub's [pull request help documentation](https://help.github.com/articles/about-pull-requests/). 5. In case your pull request is not yet complete or not yet ready for review, create a [draft pull request](https://github.blog/2019-02-14-introducing-draft-pull-requests/) instead. From afb9e76cda1f224b41c12ff5ed79dd225263c983 Mon Sep 17 00:00:00 2001 From: Oliver Kopp Date: Wed, 25 Oct 2023 14:46:12 +0200 Subject: [PATCH 19/44] Change JavaDoc to annotation (#10571) * Change JavaDoc to annoation (and fix visibility) * Fix visibility --- .../citationkeypattern/CitationKeyPatternPreferences.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/jabref/logic/citationkeypattern/CitationKeyPatternPreferences.java b/src/main/java/org/jabref/logic/citationkeypattern/CitationKeyPatternPreferences.java index 37a678b26c5..3e2c4492d27 100644 --- a/src/main/java/org/jabref/logic/citationkeypattern/CitationKeyPatternPreferences.java +++ b/src/main/java/org/jabref/logic/citationkeypattern/CitationKeyPatternPreferences.java @@ -8,6 +8,8 @@ import javafx.beans.property.SimpleStringProperty; import javafx.beans.property.StringProperty; +import com.google.common.annotations.VisibleForTesting; + public class CitationKeyPatternPreferences { public enum KeySuffix { @@ -51,9 +53,7 @@ public CitationKeyPatternPreferences(boolean shouldAvoidOverwriteCiteKey, this.keywordDelimiter = keywordDelimiter; } - /** - * For use in test - */ + @VisibleForTesting public CitationKeyPatternPreferences(boolean shouldAvoidOverwriteCiteKey, boolean shouldWarnBeforeOverwriteCiteKey, boolean shouldGenerateCiteKeysBeforeSaving, From 8c0f89783e5c2fe840ad6619a50e0930e0c16cfc Mon Sep 17 00:00:00 2001 From: Oliver Kopp Date: Wed, 25 Oct 2023 20:40:55 +0200 Subject: [PATCH 20/44] Replace "fixes" by "resolves" --- .github/PULL_REQUEST_TEMPLATE.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 6151358ef2f..7c40b5ff7fd 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -1,7 +1,7 @@ From 1445fc07aec787e67f3a57d6ee5fb6c0f8b23c75 Mon Sep 17 00:00:00 2001 From: Oliver Kopp Date: Wed, 25 Oct 2023 20:44:09 +0200 Subject: [PATCH 21/44] Update PULL_REQUEST_TEMPLATE.md --- .github/PULL_REQUEST_TEMPLATE.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 7c40b5ff7fd..4692933c196 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -1,7 +1,8 @@ From 6dd7f8d1307a7270704eb80645593470ffc49ac3 Mon Sep 17 00:00:00 2001 From: Oliver Kopp Date: Wed, 25 Oct 2023 22:31:33 +0200 Subject: [PATCH 22/44] Update .github/PULL_REQUEST_TEMPLATE.md Co-authored-by: Jonatan Asketorp --- .github/PULL_REQUEST_TEMPLATE.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 4692933c196..d3c83450590 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -1,9 +1,9 @@ From 99b8eccc3ba28ff7760fbf1e43d0ec73b4c7cc0e Mon Sep 17 00:00:00 2001 From: Oliver Kopp Date: Wed, 25 Oct 2023 22:32:49 +0200 Subject: [PATCH 23/44] Update PULL_REQUEST_TEMPLATE.md --- .github/PULL_REQUEST_TEMPLATE.md | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index d3c83450590..19e73c47937 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -1,19 +1,18 @@ +### Mandatory checks -### Mandatory checks - - [ ] Change in `CHANGELOG.md` described in a way that is understandable for the average user (if applicable) - [ ] Tests created for changes (if applicable) - [ ] Manually tested changed features in running JabRef (always required) From 4333a101c8cf2f63ef0eedf3fe740a0301e7e2fa Mon Sep 17 00:00:00 2001 From: Oliver Kopp Date: Wed, 25 Oct 2023 22:52:53 +0200 Subject: [PATCH 24/44] Update .github/PULL_REQUEST_TEMPLATE.md Co-authored-by: Jonatan Asketorp --- .github/PULL_REQUEST_TEMPLATE.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 19e73c47937..16199f2abf7 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -1,6 +1,6 @@