Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 34 additions & 0 deletions portality/crosswalks/article_crossref_xml.py
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,7 @@ def crosswalk_article(self, record, journal):
self.extract_issue(journal, bibjson)
self.extract_pages(record, journal, bibjson)
self.extract_doi(record, journal, bibjson)
self.extract_identifiers(record, journal, bibjson)
self.extract_fulltext(record, journal, bibjson)
self.extract_article_title(record, journal, bibjson)
self.extract_authors(record, journal, bibjson)
Expand Down Expand Up @@ -284,6 +285,39 @@ def extract_doi(self, record, journal, bibjson):
if doi is not None:
bibjson.add_identifier(bibjson.DOI, doi)

def extract_identifiers(self, record, journal, bibjson):
# This is used to extract item_number such as article number, eLocator, or e-location
# and capture other identifiers such as handle, ark, doi, urn, dor and purl
# Both item_number and identifier have a type attribute which is free text.
# ToDO - Do we need to differentiate between item_number and other identifiers?
publisher_item = record.find("x:publisher_item", self.NS)
if publisher_item is not None:
ans = []
ans1 = publisher_item.findall("x:item_number", self.NS)
ans2 = publisher_item.findall("x:identifier", self.NS)
if ans1 is not None:
ans = ans + ans1
if ans2 is not None:
ans = ans + ans2
for an in ans:
typ = None
typ1 = an.attrib["item_number_type"]
typ2 = an.attrib["id_type"]
if typ1:
typ = typ1
elif typ2:
typ = typ2
if typ and typ.lower() in ["eLocator", "e-location"]:
bibjson.add_identifier(bibjson.ELOCATION, an[0].text.upper())
elif typ and typ.lower() in bibjson.IDENTIFIER_TYPES:
bibjson.add_identifier(typ.lower(), an[0].text.upper())
elif typ:
# TODO - Do we capture identifiers of other types?
bibjson.add_identifier(typ.lower(), an[0].text.upper())
else:
# TODO - Do we capture identifiers of unknown type?
bibjson.add_identifier('other', an[0].text.upper())

def extract_fulltext(self, record, journal, bibjson):
d = record.find("x:doi_data", self.NS)
ftel = _element(d, "x:resource", self.NS)
Expand Down
30 changes: 30 additions & 0 deletions portality/crosswalks/article_form.py
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,15 @@ def form2obj(cls, form, add_journal_info=True):
end = form.end.data
if end is not None and end != "":
bibjson.end_page = end
elocation = form.elocation.data
if elocation is not None and elocation != "":
bibjson.add_identifier(bibjson.ELOCATION, elocation)
for subfield in form.other_identifiers:
if (subfield.form.type.data is not None and subfield.form.type.data != "" and
subfield.form.id.data is not None and subfield.form.id.data != ""):
id_typ = subfield.form.type.data
id_val = subfield.form.id.data
bibjson.add_identifier(id_typ, id_val)

# add the journal info if requested
if add_journal_info:
Expand Down Expand Up @@ -153,4 +162,25 @@ def obj2form(cls, form, article):
form.end.data = bibjson.end_page
if bibjson.abstract:
form.abstract.data = bibjson.abstract
elocation = bibjson.get_one_identifier(bibjson.ELOCATION)
if elocation:
form.elocation.data = elocation
other_identifiers = []
for each_id in bibjson.get_identifiers():
if not each_id['type'] in bibjson.NAMED_IDENTIFIERS:
other_identifiers.append(each_id)
if other_identifiers:
for i in range(len(form.other_identifiers)):
form.other_identifiers.pop_entry()
for i in other_identifiers:
id_form = OtherIdentifierForm()
if "type" in i:
id_form.type = i["type"]
else:
id_form.type = ""
if "id" in i:
id_form.id = i["id"]
else:
id_form.id = ""
form.other_identifiers.append_entry(id_form)

71 changes: 68 additions & 3 deletions portality/forms/article_forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
from portality.forms.fields import DOAJSelectField, TagListField
from portality.forms.validate import OptionalIf, ThisOrThat, NoScriptTag, DifferentTo
from portality.lib import dates
from portality.models.v1 import bibjson
from portality.ui.messages import Messages
from portality.ui import templates

Expand Down Expand Up @@ -561,6 +562,20 @@ class AuthorForm(Form):
orcid_id = StringField("ORCID iD", [validators.Optional(), validators.Regexp(regex=regex.ORCID_COMPILED, message=ORCID_ERROR)])


class OtherIdentifierForm(Form):
"""
~~->$ OtherIdentifiers:Form~~
"""
# WTForms choices are (value, label) - value is what actually gets submitted, so it
# must stay lower-case to match bibjson.GenericBibJSON.IDENTIFIER_TYPES / add_identifier
choices = [('', 'Select type')]
choices += [(i, i.upper()) for i in bibjson.GenericBibJSON.IDENTIFIER_TYPES]
choices += [('other', 'Other')]
id_types = DOAJSelectField("Type of identifier", [validators.Optional()], choices=choices, default="" )
type = StringField("Type", [validators.Optional(), NoScriptTag()])
id = StringField("ID", [validators.Optional(), NoScriptTag()])


class ArticleForm(Form):
title = StringField("Article title <em>(required)</em>", [validators.DataRequired(), NoScriptTag()])
doi = StringField("DOI", [OptionalIf("fulltext", "You must provide the DOI or the Full-Text URL"), validators.Regexp(regex=regex.DOI_COMPILED, message=DOI_ERROR)], description="(You must provide a DOI and/or a Full-Text URL)")
Expand All @@ -583,6 +598,8 @@ class ArticleForm(Form):
number = StringField("Issue", [validators.Optional(), NoScriptTag()])
start = StringField("Start", [validators.Optional(), NoScriptTag()])
end = StringField("End", [validators.Optional(), NoScriptTag()])
elocation = StringField("eLocation ID", [validators.Optional(), NoScriptTag()])
other_identifiers = FieldList(FormField(OtherIdentifierForm), min_entries=1)

def __init__(self, *args, **kwargs):
super(ArticleForm, self).__init__(*args, **kwargs)
Expand All @@ -599,7 +616,6 @@ def set_choices(self, user=None, article_id=None):
app.logger.exception(str(e))



#########################################
# Formcontexts and factory

Expand All @@ -626,6 +642,7 @@ class MetadataForm(FormContext):
def __init__(self, source, form_data, user):
self.user = user
self.author_error = False
self.other_identifier_error = False
super(MetadataForm, self).__init__(source=source, form_data=form_data)

def _set_choices(self):
Expand Down Expand Up @@ -671,6 +688,48 @@ def _validate_authors(self):
counted += 1
return counted >= 1

def modify_other_identifiers_if_required(self, request_data):

more_ids = request_data.get("more_other_identifiers")
remove_id = None
for v in list(request.values.keys()):
if v.startswith("remove_other_identifiers"):
remove_id = v.split("-")[1]

# if the user wants more ids, add an extra entry
if more_ids:
return self.render_template(more_other_identifiers=True)

# if the user wants to remove an author, do the various back-flips required
if remove_id is not None:
return self.render_template(remove_other_identifiers=remove_id)

def _check_for_other_identifier_errors(self, **kwargs):

if "more_other_identifiers" in kwargs and kwargs["more_other_identifiers"] == True:
self.form.other_identifiers.append_entry()
if "remove_other_identifiers" in kwargs:
keep = []
while len(self.form.other_identifiers.entries) > 0:
entry = self.form.other_identifiers.pop_entry()
if entry.short_name == "other_identifiers-" + kwargs["remove_other_identifier"]:
break
else:
keep.append(entry)
while len(keep) > 0:
self.form.other_identifiers.append_entry(keep.pop().data)

def _validate_other_identifiers(self):
errors = 0
for entry in self.form.other_identifiers.entries:
typ = entry.data.get("type")
id = entry.data.get("id")
if typ is not None and typ != "" and (id is None or id == "") :
errors += 1
elif id is not None and id != "" and (typ is None or typ == ""):
errors += 1
return errors == 0

def blank_form(self):
self.form = ArticleForm()
self._set_choices()
Expand All @@ -690,6 +749,8 @@ def form2target(self):
def validate(self):
if not self._validate_authors():
self.author_error = True
if not self._validate_other_identifiers():
self.other_identifier_error = True
if not self.form.validate():
return False
return True
Expand Down Expand Up @@ -720,9 +781,11 @@ def set_template(self):

def render_template(self, **kwargs):
self._check_for_author_errors(**kwargs)
self._check_for_other_identifier_errors(**kwargs)
if "validated" in kwargs and kwargs["validated"] == True:
self.blank_form()
return render_template(self.template, form=self.form, form_context=self, author_error=self.author_error)
return render_template(self.template, form=self.form, form_context=self, author_error=self.author_error,
other_identifier_error=self.other_identifier_error)


class AdminMetadataArticleForm(MetadataForm):
Expand All @@ -737,4 +800,6 @@ def set_template(self):

def render_template(self, **kwargs):
self._check_for_author_errors(**kwargs)
return render_template(self.template, form=self.form, form_context=self, author_error=self.author_error)
self._check_for_other_identifier_errors(**kwargs)
return render_template(self.template, form=self.form, form_context=self, author_error=self.author_error,
other_identifier_error=self.other_identifier_error)
16 changes: 16 additions & 0 deletions portality/models/article.py
Original file line number Diff line number Diff line change
Expand Up @@ -749,6 +749,22 @@ def end_page(self):
def end_page(self, val):
self._set_with_struct("end_page", val)

@property
def elocation(self):
self.elocation += self.get_identifiers(self.ELOCATION)

@elocation.setter
def elocation(self, val):
self.add_identifier(self.ELOCATION, val)

@property
def other_identifiers(self):
identifiers = []
for each_id in self.get_identifiers():
if not each_id['type'] in self.NAMED_IDENTIFIERS:
identifiers.append(each_id)
return identifiers

@property
def abstract(self):
return self._get_single("abstract")
Expand Down
3 changes: 3 additions & 0 deletions portality/models/v1/bibjson.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ class GenericBibJSON(dataobj.DataObj):
P_ISSN = "pissn"
E_ISSN = "eissn"
DOI = "doi"
IDENTIFIER_TYPES = ['handle', 'ark', 'doi', 'urn', 'dor', 'purl']
ELOCATION = 'e-location'
NAMED_IDENTIFIERS = [P_ISSN, E_ISSN, DOI, ELOCATION]

# allowable values for the url types
HOMEPAGE = "homepage"
Expand Down
Loading
Loading