Skip to content

Commit 4de4651

Browse files
authored
Merge branch 'main' into fix-for-issue-JabRef#12272
2 parents 7db3b81 + 1c5a73c commit 4de4651

File tree

12 files changed

+202
-104
lines changed

12 files changed

+202
-104
lines changed

.github/ISSUE_TEMPLATE/suggestion-for-improvement.md

+2-1
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,14 @@ name: Suggestion for improvement
33
about: Suggest an enhancement
44
title: ''
55
labels: ''
6+
type: 'feature'
67
assignees: ''
78

89
---
910

1011
<!--
1112
Please use the GitHub issue tracker only for bug reports and smaller suggestions for improvements.
12-
Requests for completely new features, questions and general feedback is now handled at http://discourse.jabref.org.
13+
Requests for completely new features, questions and general feedback is now handled at https://discourse.jabref.org.
1314
Thanks!
1415
-->
1516

.github/workflows/assign-issue.yml

+6-5
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ jobs:
1919
uses: takanome-dev/assign-issue-action@fix-rate-limit-err
2020
with:
2121
github_token: '${{ secrets.GITHUB_TOKEN }}'
22-
days_until_unassign: 90
22+
days_until_unassign: 45
2323
maintainers: 'koppor,Siedlerchr,ThiloteE,calixtus,HoussemNasri,subhramit,LinusDietz'
2424
assigned_comment: |
2525
👋 Hey @{{ handle }}, thank you for your interest in this issue! 🎉
@@ -34,8 +34,9 @@ jobs:
3434
3535
⏳ Please note, you will be automatically unassigned if the issue isn't closed within **{{ total_days }} days** (by **{{ unassigned_date }}**). A maintainer can also add the "**{{ pin_label }}**"" label to prevent automatic unassignment.
3636
- name: Move Issue to "Assigned" Column in "Candidates for University Projects"
37-
if: steps.assign.outputs.assigned == 'yes'
38-
uses: m7kvqbe1/github-action-move-issues@feat/skip-if-not-in-project-flag
37+
uses: koppor/github-action-move-issues@work-for-labeled
38+
# Action currently works for issues only - pre-condition: https://github.com/takanome-dev/assign-issue-action/issues/269 fixed
39+
if: github.event_name == 'issue_comment'
3940
with:
4041
github-token: ${{ secrets.GH_TOKEN_ACTION_MOVE_ISSUE }}
4142
project-url: "https://github.com/orgs/JabRef/projects/3"
@@ -45,8 +46,8 @@ jobs:
4546
default-column: "Free to take"
4647
skip-if-not-in-project: true
4748
- name: Move Issue to "Assigned" Column in "Good First Issues"
48-
if: steps.assign.outputs.assigned == 'yes'
49-
uses: m7kvqbe1/github-action-move-issues@feat/skip-if-not-in-project-flag
49+
uses: koppor/github-action-move-issues@work-for-labeled
50+
if: github.event_name == 'issue_comment'
5051
with:
5152
github-token: ${{ secrets.GH_TOKEN_ACTION_MOVE_ISSUE }}
5253
project-url: "https://github.com/orgs/JabRef/projects/5"

CHANGELOG.md

+2
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ Note that this project **does not** adhere to [Semantic Versioning](https://semv
1515
- We added a new CLI that supports txt, csv, and console-based output for consistency in BibTeX entries. [#11984](https://github.com/JabRef/jabref/issues/11984)
1616
- We added a new dialog for bibliography consistency check. [#11950](https://github.com/JabRef/jabref/issues/11950)
1717
- We added a feature for copying entries to libraries, available via the context menu, with an option to include cross-references. [#12374](https://github.com/JabRef/jabref/pull/12374)
18+
- We added an integrity check if a URL appears in a title. [#12354](https://github.com/JabRef/jabref/issues/12354)
1819

1920
### Changed
2021

@@ -27,6 +28,7 @@ Note that this project **does not** adhere to [Semantic Versioning](https://semv
2728
- The "automatically sync bibliography when citing" feature of the LibreOffice integration is now disabled by default (can be enabled in settings). [#12472](https://github.com/JabRef/jabref/pull/12472)
2829
- For the Citation key generator patterns, we reverted how `[authorsAlpha]` would behave to the original pattern and renamed the LNI-based pattern introduced in V6.0-alpha to `[authorsAlphaLNI]`. [#12499](https://github.com/JabRef/jabref/pull/12499)
2930
- We keep the list of recent files if one files could not be found. [#12517](https://github.com/JabRef/jabref/pull/12517)
31+
- During the import process, the labels indicating individual paragraphs within an abstract returned by PubMed/Medline XML are preserved. [#12527](https://github.com/JabRef/jabref/issues/12527)
3032

3133
### Fixed
3234

src/main/java/org/jabref/logic/importer/fileformat/MedlineImporter.java

+51-26
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,9 @@
1515
import java.util.Optional;
1616

1717
import javax.xml.stream.XMLInputFactory;
18+
import javax.xml.stream.XMLStreamConstants;
1819
import javax.xml.stream.XMLStreamException;
1920
import javax.xml.stream.XMLStreamReader;
20-
import javax.xml.stream.events.XMLEvent;
2121

2222
import org.jabref.logic.importer.Importer;
2323
import org.jabref.logic.importer.ParseException;
@@ -998,7 +998,7 @@ private void addAbstract(XMLStreamReader reader, Map<Field, String> fields, Stri
998998
putIfValueNotNull(fields, new UnknownField("copyright"), reader.getText());
999999
}
10001000
}
1001-
case "AbstractText" -> handleTextElement(reader, abstractTextList, elementName);
1001+
case "AbstractText" -> handleAbstractTextElement(reader, abstractTextList, elementName);
10021002
}
10031003
}
10041004

@@ -1008,7 +1008,7 @@ private void addAbstract(XMLStreamReader reader, Map<Field, String> fields, Stri
10081008
}
10091009

10101010
if (!abstractTextList.isEmpty()) {
1011-
fields.put(StandardField.ABSTRACT, String.join(" ", abstractTextList));
1011+
fields.put(StandardField.ABSTRACT, String.join("\n\n", abstractTextList));
10121012
}
10131013
}
10141014

@@ -1020,7 +1020,25 @@ private void addAbstract(XMLStreamReader reader, Map<Field, String> fields, Stri
10201020
private void handleTextElement(XMLStreamReader reader, List<String> textList, String startElement)
10211021
throws XMLStreamException {
10221022
StringBuilder result = new StringBuilder();
1023+
handleText(reader, textList, startElement, result);
1024+
}
1025+
1026+
/**
1027+
* Handles text entities of abstracts that can have inner tags such as {@literal <}i{@literal >}, {@literal <}b{@literal >} etc.
1028+
* We ignore the tags and return only the characters present in the enclosing parent element.
1029+
*
1030+
*/
1031+
private void handleAbstractTextElement(XMLStreamReader reader, List<String> textList, String startElement)
1032+
throws XMLStreamException {
1033+
StringBuilder result = new StringBuilder();
1034+
Optional.ofNullable(reader.getAttributeValue(null, "Label"))
1035+
.map(String::trim)
1036+
.filter(label -> !label.isEmpty() && !"UNLABELLED".equals(label))
1037+
.ifPresent(label -> result.append(label).append(": "));
1038+
handleText(reader, textList, startElement, result);
1039+
}
10231040

1041+
private void handleText(XMLStreamReader reader, List<String> textList, String startElement, StringBuilder result) throws XMLStreamException {
10241042
while (reader.hasNext()) {
10251043
reader.next();
10261044
if (isStartXMLEvent(reader)) {
@@ -1099,8 +1117,8 @@ private void handleAuthorList(XMLStreamReader reader, Map<Field, String> fields,
10991117
reader.next();
11001118
if (isStartXMLEvent(reader)) {
11011119
String elementName = reader.getName().getLocalPart();
1102-
switch (elementName) {
1103-
case "Author" -> parseAuthor(reader, authorNames);
1120+
if ("Author".equals(elementName)) {
1121+
parseAuthor(reader, authorNames);
11041122
}
11051123
}
11061124

@@ -1121,24 +1139,9 @@ private void parseAuthor(XMLStreamReader reader, List<String> authorNames) throw
11211139
if (isStartXMLEvent(reader)) {
11221140
String elementName = reader.getName().getLocalPart();
11231141
switch (elementName) {
1124-
case "CollectiveName" -> {
1125-
reader.next();
1126-
if (isCharacterXMLEvent(reader)) {
1127-
collectiveNames.add(reader.getText());
1128-
}
1129-
}
1130-
case "LastName" -> {
1131-
reader.next();
1132-
if (isCharacterXMLEvent(reader)) {
1133-
authorName = new StringBuilder(reader.getText());
1134-
}
1135-
}
1136-
case "ForeName" -> {
1137-
reader.next();
1138-
if (isCharacterXMLEvent(reader)) {
1139-
authorName.append(", ").append(reader.getText());
1140-
}
1141-
}
1142+
case "CollectiveName" -> parseCollectiveName(reader, collectiveNames);
1143+
case "LastName" -> authorName = parseLastName(reader, authorName);
1144+
case "ForeName" -> parseForeName(reader, authorName);
11421145
}
11431146
}
11441147

@@ -1155,6 +1158,28 @@ private void parseAuthor(XMLStreamReader reader, List<String> authorNames) throw
11551158
}
11561159
}
11571160

1161+
private void parseForeName(XMLStreamReader reader, StringBuilder authorName) throws XMLStreamException {
1162+
reader.next();
1163+
if (isCharacterXMLEvent(reader)) {
1164+
authorName.append(", ").append(reader.getText());
1165+
}
1166+
}
1167+
1168+
private StringBuilder parseLastName(XMLStreamReader reader, StringBuilder authorName) throws XMLStreamException {
1169+
reader.next();
1170+
if (isCharacterXMLEvent(reader)) {
1171+
authorName = new StringBuilder(reader.getText());
1172+
}
1173+
return authorName;
1174+
}
1175+
1176+
private void parseCollectiveName(XMLStreamReader reader, List<String> collectiveNames) throws XMLStreamException {
1177+
reader.next();
1178+
if (isCharacterXMLEvent(reader)) {
1179+
collectiveNames.add(reader.getText());
1180+
}
1181+
}
1182+
11581183
private void putIfValueNotNull(Map<Field, String> fields, Field field, String value) {
11591184
if (value != null) {
11601185
fields.put(field, value);
@@ -1181,15 +1206,15 @@ private String fixPageRange(String pageRange) {
11811206
}
11821207

11831208
private boolean isCharacterXMLEvent(XMLStreamReader reader) {
1184-
return reader.getEventType() == XMLEvent.CHARACTERS;
1209+
return reader.getEventType() == XMLStreamConstants.CHARACTERS;
11851210
}
11861211

11871212
private boolean isStartXMLEvent(XMLStreamReader reader) {
1188-
return reader.getEventType() == XMLEvent.START_ELEMENT;
1213+
return reader.getEventType() == XMLStreamConstants.START_ELEMENT;
11891214
}
11901215

11911216
private boolean isEndXMLEvent(XMLStreamReader reader) {
1192-
return reader.getEventType() == XMLEvent.END_ELEMENT;
1217+
return reader.getEventType() == XMLStreamConstants.END_ELEMENT;
11931218
}
11941219

11951220
@Override

src/main/java/org/jabref/logic/integrity/FieldCheckers.java

+3
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,9 @@ private static Multimap<Field, ValueChecker> getAllMap(BibDatabaseContext databa
4848
fieldCheckers.put(StandardField.KEY, new ValidCitationKeyChecker());
4949
fieldCheckers.put(InternalField.KEY_FIELD, new ValidCitationKeyChecker());
5050

51+
fieldCheckers.put(StandardField.TITLE, new NoURLChecker());
52+
fieldCheckers.put(StandardField.BOOKTITLE, new NoURLChecker());
53+
5154
if (databaseContext.isBiblatexMode()) {
5255
fieldCheckers.put(StandardField.DATE, new DateChecker());
5356
fieldCheckers.put(StandardField.URLDATE, new DateChecker());
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
package org.jabref.logic.integrity;
2+
3+
import java.util.Optional;
4+
5+
import org.jabref.logic.l10n.Localization;
6+
import org.jabref.logic.util.URLUtil;
7+
import org.jabref.model.strings.StringUtil;
8+
9+
public class NoURLChecker implements ValueChecker {
10+
11+
public Optional<String> checkValue(String value) {
12+
if (StringUtil.isBlank(value)) {
13+
return Optional.empty();
14+
}
15+
16+
if (URLUtil.URL_PATTERN.matcher(value).find()) {
17+
return Optional.of(Localization.lang("contains a URL"));
18+
}
19+
20+
return Optional.empty();
21+
}
22+
}

src/main/java/org/jabref/logic/util/URLUtil.java

+9
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,22 @@
77
import java.net.URLDecoder;
88
import java.nio.charset.StandardCharsets;
99
import java.util.Objects;
10+
import java.util.regex.Pattern;
1011

1112
/**
1213
* URL utilities for URLs in the JabRef logic.
1314
* <p>
1415
* For GUI-oriented URL utilities see {@link org.jabref.gui.fieldeditors.URLUtil}.
1516
*/
1617
public class URLUtil {
18+
19+
private static final String URL_REGEX = "(?i)\\b((?:https?|ftp)://[^\\s]+)";
20+
21+
/**
22+
* Pattern matches a string containing a URL with a protocol
23+
*/
24+
public static final Pattern URL_PATTERN = Pattern.compile(URL_REGEX, Pattern.CASE_INSENSITIVE);
25+
1726
private static final String URL_EXP = "^(https?|ftp)://.+";
1827
// Detect Google search URL
1928
private static final String GOOGLE_SEARCH_EXP = "^https?://(?:www\\.)?google\\.[\\.a-z]+?/url.*";

src/main/resources/l10n/JabRef_en.properties

+3-1
Original file line numberDiff line numberDiff line change
@@ -1626,16 +1626,18 @@ JabRef\ would\ not\ have\ been\ possible\ without\ the\ help\ of\ our\ contribut
16261626

16271627
HTML\ encoded\ character\ found=HTML encoded character found
16281628
booktitle\ ends\ with\ 'conference\ on'=booktitle ends with 'conference on'
1629+
contains\ a\ URL=contains a URL
16291630

16301631
incorrect\ control\ digit=incorrect control digit
16311632
incorrect\ format=incorrect format
1633+
16321634
Copied\ version\ to\ clipboard=Copied version to clipboard
16331635

16341636
Citation\ key=Citation key
16351637
Message=Message
16361638

1637-
16381639
MathSciNet\ Review=MathSciNet Review
1640+
16391641
Reset\ all=Reset all
16401642

16411643
Decryption\ not\ supported.=Decryption not supported.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
package org.jabref.logic.integrity;
2+
3+
import java.util.Optional;
4+
5+
import org.junit.jupiter.api.Test;
6+
import org.junit.jupiter.params.ParameterizedTest;
7+
import org.junit.jupiter.params.provider.CsvSource;
8+
9+
import static org.junit.jupiter.api.Assertions.assertEquals;
10+
import static org.junit.jupiter.api.Assertions.assertNotEquals;
11+
12+
public class NoURLCheckerTest {
13+
14+
private final NoURLChecker checker = new NoURLChecker();
15+
16+
@ParameterizedTest(name = "{index}. Title: \"{0}\"")
17+
@CsvSource({
18+
"Proceedings of the https://example.com/conference",
19+
"Find more at http://mywebsite.org/article",
20+
"Visit ftp://files.example.com/download",
21+
})
22+
void fieldShouldRaiseWarningForFullURLs(String title) {
23+
assertNotEquals(Optional.empty(), checker.checkValue(title));
24+
}
25+
26+
@Test
27+
void fieldShouldAcceptURLWithoutProtocol() {
28+
assertEquals(Optional.empty(), checker.checkValue("Applying Trip@dvice Recommendation Technology to www.visiteurope.com"));
29+
}
30+
}

src/test/resources/org/jabref/logic/importer/fileformat/MedlineImporterTestNbib.bib

+3-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
@article{,
2-
abstract = {Just a dummy text. And another dummy},
2+
abstract = {BACKGROUND: Just a dummy text.
3+
4+
And another dummy},
35
affiliation = {Vanderbilt U, Nashville, TN},
46
author = {Gibb, F W and Zamm itt, NaN and Beckett, G and Strachan, M W J},
57
chemicals = {Iodine Radioisotopes, Thyroxine},

src/test/resources/org/jabref/logic/importer/fileformat/MedlineImporterTestNbib.xml

+2-2
Original file line numberDiff line numberDiff line change
@@ -261,7 +261,7 @@
261261
<PublicationType UI="D016454">Review</PublicationType>
262262
<PublicationType UI="D017065">Practice Guideline</PublicationType>
263263
<Abstract>
264-
<AbstractText>just a dummy.</AbstractText>
264+
<AbstractText Label="UNLABELLED">just a dummy.</AbstractText>
265265
<CopyrightInformation>Copyright from somwhere</CopyrightInformation>
266266
</Abstract>
267267
<Sections>
@@ -369,4 +369,4 @@
369369
</PubmedBookData>
370370
</PubmedBookArticle>
371371

372-
</PubmedArticleSet>
372+
</PubmedArticleSet>

0 commit comments

Comments
 (0)