Skip to content

Commit 05352f6

Browse files
committed
literature: display authors with no hepnames records
* INSPIR-3163 ui: display bai in author profile * INSPIR-2735 * Needs reindexing of literature
1 parent abd26cd commit 05352f6

File tree

26 files changed

+540
-365
lines changed

26 files changed

+540
-365
lines changed

backend/inspirehep/records/marshmallow/authors/ui.py

Lines changed: 13 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,9 @@
55
# inspirehep is free software; you can redistribute it and/or modify it under
66
# the terms of the MIT License; see LICENSE file for more details.
77

8-
from inspire_utils.record import get_values_for_schema
98
from marshmallow import fields
109

11-
from ..utils import get_facet_author_name_for_author
10+
from ..utils import get_facet_author_name_for_author, get_id_for_schema
1211
from .base import AuthorsPublicSchema
1312
from .common import PositionSchemaV1
1413

@@ -38,17 +37,21 @@ def get_facet_author_name(self, data):
3837
return get_facet_author_name_for_author(data)
3938
return facet_author_name
4039

41-
def get_twitter(self, data):
42-
return self.get_id_for_schema(data, "TWITTER")
40+
@staticmethod
41+
def get_twitter(data):
42+
return get_id_for_schema(data, "TWITTER")
4343

44-
def get_linkedin(self, data):
45-
return self.get_id_for_schema(data, "LINKEDIN")
44+
@staticmethod
45+
def get_linkedin(data):
46+
return get_id_for_schema(data, "LINKEDIN")
4647

47-
def get_orcid(self, data):
48-
return self.get_id_for_schema(data, "ORCID")
48+
@staticmethod
49+
def get_orcid(data):
50+
return get_id_for_schema(data, "ORCID")
4951

50-
def get_bai(self, data):
51-
return self.get_id_for_schema(data, "INSPIRE BAI")
52+
@staticmethod
53+
def get_bai(data):
54+
return get_id_for_schema(data, "INSPIRE BAI")
5255

5356
@staticmethod
5457
def get_current_public_emails(data):
@@ -59,12 +62,6 @@ def get_current_public_emails(data):
5962
if not email.get("hidden") and email.get("current")
6063
]
6164

62-
@staticmethod
63-
def get_id_for_schema(data, schema):
64-
ids = data.get("ids", [])
65-
ids_for_schema = get_values_for_schema(ids, schema)
66-
return ids_for_schema[0] if ids_for_schema else None
67-
6865
@staticmethod
6966
def get_should_display_positions(data):
7067
positions = data.get("positions")

backend/inspirehep/records/marshmallow/literature/common/author.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111
from inspire_utils.name import generate_name_variations
1212
from marshmallow import Schema, fields, missing, pre_dump
1313

14+
from inspirehep.records.marshmallow.utils import get_id_for_schema
15+
1416

1517
class AuthorSchemaV1(Schema):
1618

@@ -29,6 +31,11 @@ class AuthorSchemaV1(Schema):
2931
uuid = fields.Raw()
3032
first_name = fields.Method("get_first_name", default=missing)
3133
last_name = fields.Method("get_last_name", default=missing)
34+
bai = fields.Method("get_bai", dump_only=True)
35+
36+
@staticmethod
37+
def get_bai(data):
38+
return get_id_for_schema(data, "INSPIRE BAI") or missing
3239

3340
def get_first_name(self, data):
3441
names = data.get("full_name", "").split(",", 1)

backend/inspirehep/records/marshmallow/utils.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
# the terms of the MIT License; see LICENSE file for more details.
77

88
from inspire_utils.name import ParsedName
9-
from inspire_utils.record import get_value
9+
from inspire_utils.record import get_value, get_values_for_schema
1010

1111

1212
def get_display_name_for_author_name(author_name):
@@ -22,3 +22,9 @@ def get_facet_author_name_for_author(author):
2222
return f"{author_control_number}_{author_preferred_name}"
2323

2424
return f"{author_control_number}_{get_display_name_for_author_name(get_value(author, 'name.value'))}"
25+
26+
27+
def get_id_for_schema(data, schema):
28+
ids = data.get("ids", [])
29+
ids_for_schema = get_values_for_schema(ids, schema)
30+
return ids_for_schema[0] if ids_for_schema else None

backend/tests/integration/records/indexer/test_indexer_literature/es_1630825.json

Lines changed: 1 addition & 1 deletion
Large diffs are not rendered by default.

backend/tests/unit/records/marshmallow/literature/common/test_author.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,24 @@ def test_author_without_last_name():
3838
assert expected == json.loads(result)
3939

4040

41+
def test_author_with_bai():
42+
schema = AuthorSchemaV1()
43+
44+
dump = {
45+
"full_name": "Frank Castle",
46+
"ids": [{"schema": "INSPIRE BAI", "value": "Frank.Castle.1"}],
47+
}
48+
expected = {
49+
"full_name": "Frank Castle",
50+
"first_name": "Frank Castle",
51+
"bai": "Frank.Castle.1",
52+
"ids": [{"schema": "INSPIRE BAI", "value": "Frank.Castle.1"}],
53+
}
54+
result = schema.dumps(dump).data
55+
56+
assert expected == json.loads(result)
57+
58+
4159
def test_author_with_with_inspire_roles():
4260
schema = AuthorSchemaV1()
4361
dump = {"full_name": "Smith, John", "inspire_roles": ["author"]}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import React from 'react';
2+
import PropTypes from 'prop-types';
3+
import { Link } from 'react-router-dom';
4+
import { getLiteratureSearchUrlForAuthorBAI } from '../../common/utils';
5+
6+
function AuthorBAI({ bai }) {
7+
return (
8+
<span>
9+
Author Identifier:{' '}
10+
<Link to={getLiteratureSearchUrlForAuthorBAI(bai)}>{bai}</Link>
11+
</span>
12+
);
13+
}
14+
15+
AuthorBAI.propTypes = {
16+
bai: PropTypes.string.isRequired,
17+
};
18+
19+
export default AuthorBAI;
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import React from 'react';
2+
import { shallow } from 'enzyme';
3+
import AuthorBAI from '../AuthorBAI';
4+
5+
describe('AuthorBAI', () => {
6+
it('renders', () => {
7+
const wrapper = shallow(<AuthorBAI bai="F.Marchetto.1" />);
8+
expect(wrapper).toMatchSnapshot();
9+
});
10+
});
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
// Jest Snapshot v1, https://goo.gl/fbAQLP
2+
3+
exports[`AuthorBAI renders 1`] = `
4+
<span>
5+
Author Identifier:
6+
7+
<Link
8+
replace={false}
9+
to="/literature?q=a%20F.Marchetto.1"
10+
>
11+
F.Marchetto.1
12+
</Link>
13+
</span>
14+
`;

ui/src/authors/containers/DetailPageContainer.jsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ import EditRecordAction from '../../common/components/EditRecordAction';
3939
import DeletedAlert from '../../common/components/DeletedAlert';
4040
import UserSettingsAction from '../components/UserSettingsAction';
4141
import withRouteActionsDispatcher from '../../common/withRouteActionsDispatcher';
42+
import AuthorBAI from '../components/AuthorBAI';
4243

4344
function renderNumberOfCiteablePapers(value) {
4445
return (
@@ -95,6 +96,7 @@ function DetailPage({
9596
const orcid = metadata.get('orcid');
9697
const emails = metadata.get('email_addresses');
9798
const deleted = metadata.get('deleted', false);
99+
const bai = metadata.get('bai');
98100

99101
const metaDescription = useMemo(() => getAuthorMetaDescription(metadata), [
100102
metadata,
@@ -157,6 +159,7 @@ function DetailPage({
157159
<Col xs={24} lg={12} className="mb3">
158160
<ArxivCategoryList arxivCategories={arxivCategories} />
159161
<ExperimentList experiments={experiments} />
162+
{bai && <AuthorBAI bai={bai} />}
160163
</Col>
161164
<Col xs={24} lg={12}>
162165
{shouldDisplayPositions && (

ui/src/common/__tests__/utils.test.js

Lines changed: 39 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import pluralizeUnlessSingle, {
2121
downloadTextAsFile,
2222
addOrdinalSuffix,
2323
makeCompliantMetaDescription,
24+
getAuthorName,
2425
} from '../utils';
2526

2627
describe('utils', () => {
@@ -313,7 +314,7 @@ describe('utils', () => {
313314
error: {
314315
status: 500,
315316
foo: 'bar',
316-
}
317+
},
317318
};
318319
expect(result).toEqual(expected);
319320
});
@@ -328,7 +329,7 @@ describe('utils', () => {
328329
const expected = {
329330
error: {
330331
status: 500,
331-
}
332+
},
332333
};
333334
expect(result).toEqual(expected);
334335
});
@@ -341,7 +342,7 @@ describe('utils', () => {
341342
const expected = {
342343
error: {
343344
status: 'network',
344-
}
345+
},
345346
};
346347
expect(result).toEqual(expected);
347348
});
@@ -614,21 +615,51 @@ describe('utils', () => {
614615

615616
describe('makeCompliantMetaDescription', () => {
616617
it('strips html tags and truncates to 160 chars', () => {
617-
const input = 'Lorem <strong>ipsum</strong> dolor sit <a href="/link">amet</a>, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.';
618-
const expectedOutput = 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nos...'
619-
const output = makeCompliantMetaDescription(input)
618+
const input =
619+
'Lorem <strong>ipsum</strong> dolor sit <a href="/link">amet</a>, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.';
620+
const expectedOutput =
621+
'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nos...';
622+
const output = makeCompliantMetaDescription(input);
620623
expect(output).toEqual(expectedOutput);
621624
});
622625

623626
it('does not do anything if input does not include any html tags and shorter than 160 chars', () => {
624627
const input = 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.';
625-
const output = makeCompliantMetaDescription(input)
628+
const output = makeCompliantMetaDescription(input);
626629
expect(output).toEqual(input);
627630
});
628631

629632
it('returns empty if undefine is passed', () => {
630-
const output = makeCompliantMetaDescription(undefined)
633+
const output = makeCompliantMetaDescription(undefined);
631634
expect(output).toEqual('');
632635
});
633636
});
637+
638+
describe('getAuthorName', () => {
639+
it('returns first name and last name', () => {
640+
const author = fromJS({
641+
full_name: 'Name, Full',
642+
first_name: 'Full',
643+
last_name: 'Name',
644+
});
645+
const output = getAuthorName(author);
646+
expect(output).toEqual('Full Name');
647+
});
648+
it('returns full name if first name is missing', () => {
649+
const author = fromJS({
650+
full_name: 'Name, Full',
651+
last_name: 'Name',
652+
});
653+
const output = getAuthorName(author);
654+
expect(output).toEqual('Name, Full');
655+
});
656+
it('returns first name if last name is missing', () => {
657+
const author = fromJS({
658+
full_name: 'Name, Full',
659+
first_name: 'Name',
660+
});
661+
const output = getAuthorName(author);
662+
expect(output).toEqual('Name ');
663+
});
664+
});
634665
});

0 commit comments

Comments
 (0)