From 547d2174de6d57f55013e61b431ffd148af91f56 Mon Sep 17 00:00:00 2001 From: u7901628 Date: Wed, 8 Oct 2025 07:53:51 +1100 Subject: [PATCH 01/28] Improve INSPIRE citekey handling and cleanup - Prioritize 'texkeys' field as citation key if present, and clear it after use - Add post-cleanup logic to detect and replace bad citation keys - Implement texkeys-style citekey generation --- .../importer/fetcher/INSPIREFetcher.java | 87 +++++++++++++++++++ 1 file changed, 87 insertions(+) diff --git a/jablib/src/main/java/org/jabref/logic/importer/fetcher/INSPIREFetcher.java b/jablib/src/main/java/org/jabref/logic/importer/fetcher/INSPIREFetcher.java index 83fdf7ea483..eb52e454645 100644 --- a/jablib/src/main/java/org/jabref/logic/importer/fetcher/INSPIREFetcher.java +++ b/jablib/src/main/java/org/jabref/logic/importer/fetcher/INSPIREFetcher.java @@ -22,6 +22,8 @@ import org.jabref.logic.importer.util.MediaTypes; import org.jabref.logic.layout.format.LatexToUnicodeFormatter; import org.jabref.logic.net.URLDownload; +import org.jabref.model.entry.Author; +import org.jabref.model.entry.AuthorList; import org.jabref.model.entry.BibEntry; import org.jabref.model.entry.field.StandardField; import org.jabref.model.entry.field.UnknownField; @@ -78,6 +80,90 @@ public void doPostCleanup(BibEntry entry) { new FieldFormatterCleanup(StandardField.TITLE, new RemoveEnclosingBracesFormatter()).cleanup(entry); new FieldFormatterCleanup(StandardField.TITLE, new LatexToUnicodeFormatter()).cleanup(entry); + + // Check if the current citation key is bad (too long, contains URL, or illegal chars) + String key = entry.getCitationKey().orElse(""); + if (isBadKey(key)) { + // If so, generate a new citation key and set as citation key + entry.setCitationKey(generateNewKey(entry)); + } + } + + String generateNewKey(BibEntry entry){ + // Generate a new citation key following INSPIRE texkey rules + String newKey = ""; + Optional authors = entry.getField(StandardField.AUTHOR); + Optional year = entry.getField(StandardField.YEAR); + + // Parse authors into structured list; if absent, returns empty list + List authorList = AuthorList.parse(authors.orElse("")).getAuthors(); + if (year.isPresent()){ + // If author info is available, use [first author's last name]:[year][other initials] + if (authors.isPresent() && !authorList.isEmpty()){ + String firstLastName = authorList.getFirst().getNamePrefixAndFamilyName(); + StringBuilder suffix = new StringBuilder(); + + // Append the first letter of each author's last name + for (Author author : authorList) { + String lastName = author.getNamePrefixAndFamilyName(); + if (!lastName.isEmpty()) { + suffix.append(lastName.charAt(0)); + } + } + + // Remove the first author's initial + if (!suffix.isEmpty()) { + suffix.deleteCharAt(0); + } + newKey = firstLastName + ":" + year.get() + suffix; + } + // If no author, but collaboration field exists, use [collaboration]:[year] + else if (entry.getField(new UnknownField("collaboration")).isPresent()) { + newKey = entry.getField(new UnknownField("collaboration")).get() + ":" + year.get(); + } + // If no author/collaboration, but arXiv eprint exists, use arXiv:[eprint] + else if (entry.getField(StandardField.EPRINT).isPresent()) { + newKey = "arXiv:" + entry.getField(StandardField.EPRINT).get(); + } + else { + // TODO: warning for missing important information + } + } + else { + // If no year, fallback to arXiv if available + if (entry.getField(StandardField.EPRINT).isPresent()) { + newKey = "arXiv:" + entry.getField(StandardField.EPRINT).get(); + } + else { + // TODO: warning for missing important information + } + } + return newKey; + } + + /** + * Checks if the citation key is bad: contains illegal characters, is too long, or is a URL. + */ + boolean isBadKey(String key){ + char[] invalidChars = {'/', '\\', '*', '?', '"', '<', '>', '|', '#', '%'}; + for (char c : invalidChars) { + if (key.contains(String.valueOf(c))) { + return true; + } + } + // Consider key bad if too long or is a URL + return key.length() > 30 || key.startsWith("http://") || key.startsWith("https://"); + } + + /** + * If the BibEntry contains a 'texkeys' field, use it as the citation key and clear the field. + */ + void setTexkeys(BibEntry entry){ + Optional texkeys = entry.getField(new UnknownField("texkeys")); + if (texkeys.isPresent() && !texkeys.get().isBlank()) { + entry.setCitationKey(texkeys.get()); + entry.clearField(new UnknownField("texkeys")); + } } @Override @@ -110,6 +196,7 @@ public List performSearch(@NonNull BibEntry entry) throws FetcherExcep try { URLDownload download = getUrlDownload(url); List results = getParser().parseEntries(download.asInputStream()); + results.forEach(this::setTexkeys); results.forEach(this::doPostCleanup); return results; } catch (ParseException e) { From 91ae89f8b42d288ef96966d2e7b92d8cd9a63dd0 Mon Sep 17 00:00:00 2001 From: u7978428 Date: Wed, 8 Oct 2025 16:51:57 +1100 Subject: [PATCH 02/28] Provide a switch to let users choose whether to enable the texkeys function --- .../gui/preferences/websearch/WebSearchTab.java | 4 ++++ .../websearch/WebSearchTabViewModel.java | 10 ++++++++++ .../gui/preferences/websearch/WebSearchTab.fxml | 5 +++++ .../logic/importer/ImporterPreferences.java | 17 ++++++++++++++++- .../logic/preferences/JabRefCliPreferences.java | 6 +++++- 5 files changed, 40 insertions(+), 2 deletions(-) diff --git a/jabgui/src/main/java/org/jabref/gui/preferences/websearch/WebSearchTab.java b/jabgui/src/main/java/org/jabref/gui/preferences/websearch/WebSearchTab.java index 12064d26e92..ff3ae253b6a 100644 --- a/jabgui/src/main/java/org/jabref/gui/preferences/websearch/WebSearchTab.java +++ b/jabgui/src/main/java/org/jabref/gui/preferences/websearch/WebSearchTab.java @@ -45,6 +45,8 @@ public class WebSearchTab extends AbstractPreferenceTabView fetchersContainer .getChildren() .setAll(viewModel.getFetchers() diff --git a/jabgui/src/main/java/org/jabref/gui/preferences/websearch/WebSearchTabViewModel.java b/jabgui/src/main/java/org/jabref/gui/preferences/websearch/WebSearchTabViewModel.java index dca966ff906..811b9ce866b 100644 --- a/jabgui/src/main/java/org/jabref/gui/preferences/websearch/WebSearchTabViewModel.java +++ b/jabgui/src/main/java/org/jabref/gui/preferences/websearch/WebSearchTabViewModel.java @@ -69,6 +69,8 @@ public class WebSearchTabViewModel implements PreferenceTabViewModel { private final BooleanProperty grobidEnabledProperty = new SimpleBooleanProperty(); private final StringProperty grobidURLProperty = new SimpleStringProperty(""); + private final BooleanProperty preferInspireTexkeysProperty = new SimpleBooleanProperty(); + private final BooleanProperty apikeyPersistProperty = new SimpleBooleanProperty(); private final BooleanProperty apikeyPersistAvailableProperty = new SimpleBooleanProperty(); @@ -153,6 +155,8 @@ public void setValues() { grobidEnabledProperty.setValue(grobidPreferences.isGrobidEnabled()); grobidURLProperty.setValue(grobidPreferences.getGrobidURL()); + preferInspireTexkeysProperty.setValue(preferences.getImporterPreferences().isPreferInspireTexkeys()); + Set savedApiKeys = preferences.getImporterPreferences().getApiKeys(); Set enabledCatalogs = new HashSet<>(importerPreferences.getCatalogs()); @@ -207,6 +211,8 @@ public void storeSettings() { doiPreferences.setUseCustom(useCustomDOIProperty.get()); doiPreferences.setDefaultBaseURI(useCustomDOINameProperty.getValue().trim()); + importerPreferences.setPreferInspireTexkeys(preferInspireTexkeysProperty.getValue()); + importerPreferences.setCatalogs( fetchers.stream() .filter(FetcherViewModel::isEnabled) @@ -289,6 +295,10 @@ public IntegerProperty citationsRelationsStoreTTLProperty() { return citationsRelationStoreTTL; } + public BooleanProperty preferInspireTexkeysProperty() { + return preferInspireTexkeysProperty; + } + public void checkApiKey(FetcherViewModel fetcherViewModel, String apiKey, Consumer onFinished) { Callable tester = () -> { WebFetcher webFetcher = fetcherViewModel.getFetcher(); diff --git a/jabgui/src/main/resources/org/jabref/gui/preferences/websearch/WebSearchTab.fxml b/jabgui/src/main/resources/org/jabref/gui/preferences/websearch/WebSearchTab.fxml index cf9d45183de..db25d349073 100644 --- a/jabgui/src/main/resources/org/jabref/gui/preferences/websearch/WebSearchTab.fxml +++ b/jabgui/src/main/resources/org/jabref/gui/preferences/websearch/WebSearchTab.fxml @@ -47,6 +47,11 @@ +