Skip to content

Commit

Permalink
Merge branch 'feature/3647_export_ris' into develop
Browse files Browse the repository at this point in the history
  • Loading branch information
Steven-Eardley committed Nov 12, 2024
2 parents ae907eb + bdac4cc commit 1551ae1
Show file tree
Hide file tree
Showing 13 changed files with 477 additions and 11 deletions.
1 change: 1 addition & 0 deletions doajtest/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,7 @@ class DoajTestCase(TestCase):
@classmethod
def create_app_patch(cls):
return {
'AUTOCHECK_INCOMING': False, # old test cases design and depend on work flow of autocheck disabled
"STORE_IMPL": "portality.store.StoreLocal",
"STORE_LOCAL_DIR": paths.rel2abs(__file__, "..", "tmp", "store", "main", cls.__name__.lower()),
"STORE_TMP_DIR": paths.rel2abs(__file__, "..", "tmp", "store", "tmp", cls.__name__.lower()),
Expand Down
11 changes: 10 additions & 1 deletion doajtest/testbook/public_site/public_search.yml
Original file line number Diff line number Diff line change
Expand Up @@ -186,4 +186,13 @@ tests:
- step: click spacebar to check the filter
results:
- filter is applied

- title: Export article in RIS format
context:
role: anonymous
steps:
- step: Go to the DOAJ search page at /search/articles
results:
- Only articles are shown in the results
- step: Click on 'Export RIS' of any article
results:
- A RIS file is downloaded
43 changes: 43 additions & 0 deletions doajtest/unit/test_crosswalks_article_ris.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import unittest

from doajtest.fixtures import ArticleFixtureFactory
from portality import models
from portality.crosswalks.article_ris import ArticleRisXWalk


class TestArticleRisXWalk(unittest.TestCase):
def test_article2ris(self):
article = ArticleFixtureFactory.make_article_source()
article = models.Article(**article)
article.bibjson().abstract = "abstract"
ris = ArticleRisXWalk.article2ris(article)
assert ris.type == 'JOUR'
assert ris['T1'] == [article.data['bibjson']['title']]
assert ris.to_text().split() == """
TY - JOUR
T1 - Article Title
AU - The Author
PY - 1991
JF - The Title
PB - The Publisher
VL - 1
IS - 99
SP - 3
EP - 21
UR - http://www.example.com/article
AB - abstract
KW - word
KW - key
DO - 10.0000/SOME.IDENTIFIER
LA - EN
LA - FR
ER -
""".split()

def test_article2ris__only_title(self):
ris = ArticleRisXWalk.article2ris({"bibjson": {"title": "Article Title"}})
assert ris.to_text().split() == """
TY - JOUR
T1 - Article Title
ER -
""".split()
66 changes: 66 additions & 0 deletions doajtest/unit/test_ris.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
from unittest import TestCase

from portality.lib.ris import RisEntry


class TestRisEntry(TestCase):

def test_get_set_item(self):
test_value = 'value_a'
entry = RisEntry()
entry['A1'] = test_value
assert entry['A1'] == [test_value]

def test_append(self):
entry = RisEntry()
entry.append('A1', '1')
entry['A1'].append('2')
assert entry['A1'] == ['1', '2']

entry['A1'] = '9'
assert entry['A1'] == ['9']

def test_getitem__valid_undefined(self):
entry = RisEntry()
assert entry['A1'] == []

def test_setitem__raise_field_not_found(self):
entry = RisEntry()
with self.assertRaises(ValueError):
entry['qoidjqowijdkncoiqw'] = 'value_a'

def test_getitem__raise_field_not_found(self):
entry = RisEntry()
with self.assertRaises(ValueError):
print(entry['qoidjqowijdkncoiqw'])

def test_to_text(self):
entry = RisEntry()
entry['A1'] = 'value_a'
entry['A2'] = 'value_b'
entry['TY'] = 'JOUR'

expected = """
TY - JOUR
A1 - value_a
A2 - value_b
ER -
""".strip() + ' \n'

assert entry.to_text() == expected

def test_from_text(self):
expected = """
TY - JOUR
A1 - value_a
A2 - value_b
ER -
""".strip() + ' \n'

entry = RisEntry.from_text(expected)
assert entry.type == 'JOUR'
assert dict(entry.data) == {
'TY': ['JOUR'],
'A1': ['value_a'],
'A2': ['value_b'],
}
28 changes: 28 additions & 0 deletions doajtest/unit/test_view_doajservices.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
from doajtest.fixtures import ArticleFixtureFactory
from doajtest.helpers import DoajTestCase
from portality.crosswalks.article_ris import ArticleRisXWalk
from portality.models import Article
from portality.util import url_for


class TestDoajservices(DoajTestCase):

def test_export_article_ris(self):
article = Article(**ArticleFixtureFactory.make_article_source())
article.save(blocking=True)
Article.refresh()

ris = ArticleRisXWalk.article2ris(article).to_text()

with self.app_test.test_client() as t_client:
url = url_for('doajservices.export_article_ris', article_id=article.id, fmt='ris')
response = t_client.get(url)
assert response.status_code == 200
assert response.get_data(as_text=True) == ris

def test_export_article_ris__not_found(self):
with self.app_test.test_client() as t_client:
url = url_for('doajservices.export_article_ris',
article_id='article_id_that_does_not_exist', fmt='ris')
response = t_client.get(url)
assert response.status_code == 404
50 changes: 50 additions & 0 deletions portality/crosswalks/article_ris.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
from typing import Union

from portality import models
from portality.lib import jsonpath_utils
from portality.lib.ris import RisEntry


def extra_author_names(article) -> list:
query = '$.bibjson.author[*].name'
values = jsonpath_utils.find_values(query, article)
return sorted(set(values))


RIS_ARTICLE_MAPPING = {
'T1': '$.bibjson.title',
'AU': extra_author_names,
'PY': '$.bibjson.year',
'JF': '$.bibjson.journal.title',
'PB': '$.bibjson.journal.publisher',
'VL': '$.bibjson.journal.volume',
'IS': '$.bibjson.journal.number',
'SP': '$.bibjson.start_page',
'EP': '$.bibjson.end_page',
'UR': '$.bibjson.link[*].url',
'AB': '$.bibjson.abstract',
'KW': '$.bibjson.keywords[*]',
'DO': '$.bibjson.identifier[?(@.type == "doi")].id',
'SN': '$.bibjson.journal.issns[*]',
'LA': '$.bibjson.journal.language[*]',
}


class ArticleRisXWalk:

@classmethod
def article2ris(cls, article: Union[models.Article, dict]) -> RisEntry:
if isinstance(article, models.Article):
article = article.data

entry = RisEntry(type_of_reference='JOUR')
for tag, query in RIS_ARTICLE_MAPPING.items():
if callable(query):
values = query(article)
else:
values = jsonpath_utils.find_values(query, article)

for v in values:
entry[tag].append(v)

return entry
7 changes: 7 additions & 0 deletions portality/lib/jsonpath_utils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
from typing import Iterable

import jsonpath_ng.ext


def find_values(query: str, data: dict) -> Iterable:
return (m.value for m in jsonpath_ng.ext.parse(query).find(data))
Loading

0 comments on commit 1551ae1

Please sign in to comment.