Newer
Older
from django.contrib.postgres.fields import JSONField
from django.db import models
from django.template import Template, Context
from django.utils import timezone
from scipost.constants import SCIPOST_DISCIPLINES, SCIPOST_SUBJECT_AREAS
from scipost.models import ChoiceArrayField, Contributor
class UnregisteredAuthor(models.Model):
first_name = models.CharField(max_length=100)
last_name = models.CharField(max_length=100)
def __str__(self):
return self.last_name + ', ' + self.first_name
SCIPOST_JOURNALS = (
('SciPost Physics Select', 'SciPost Physics Select'),
('SciPost Physics', 'SciPost Physics'),
('SciPost Physics Lecture Notes', 'SciPost Physics Lecture Notes'),
journals_dict = dict(SCIPOST_JOURNALS)
class JournalNameError(Exception):
def __init__(self, name):
self.name = name
def __str__(self):
return self.name
def journal_name_abbrev_citation(journal_name):
if journal_name == 'SciPost Physics':
return 'SciPost Phys.'
elif journal_name == 'SciPost Physics Select':
return 'SciPost Phys. Sel.'
elif journal_name == 'SciPost Physics Lecture Notes':
return 'SciPost Phys. Lect. Notes'
else:
raise JournalNameError(journal_name)
def journal_name_abbrev_doi(journal_name):
if journal_name == 'SciPost Physics':
elif journal_name == 'SciPost Physics Select':
elif journal_name == 'SciPost Physics Lecture Notes':
return 'SciPostPhysLectNotes'
else:
raise JournalNameError(journal_name)
class PaperNumberError(Exception):
def __init__(self, nr):
self.nr = nr
def __str__(self):
return self.nr
def paper_nr_string(nr):
if nr < 10:
return '00' + str(nr)
elif nr < 100:
return '0' + str(nr)
elif nr < 1000:
return str(nr)
else:
raise PaperNumberError(nr)
class PaperNumberingError(Exception):
def __init__(self, nr):
self.nr = nr
def __str__(self):
return self.nr
SCIPOST_JOURNALS_SUBMIT = ( # Same as SCIPOST_JOURNALS, but SP Select deactivated
('SciPost Physics', 'SciPost Physics'),
('SciPost Physics Lecture Notes', 'SciPost Physics Lecture Notes'),
journals_submit_dict = dict(SCIPOST_JOURNALS_SUBMIT)
SCIPOST_JOURNALS_DOMAINS = (
('E', 'Experimental'),
('T', 'Theoretical'),
('C', 'Computational'),
('ET', 'Exp. & Theor.'),
('EC', 'Exp. & Comp.'),
('TC', 'Theor. & Comp.'),
('ETC', 'Exp., Theor. & Comp.'),
journals_domains_dict = dict(SCIPOST_JOURNALS_DOMAINS)
SCIPOST_JOURNALS_SPECIALIZATIONS = (
('A', 'Atomic, Molecular and Optical Physics'),
('B', 'Biophysics'),
('C', 'Condensed Matter Physics'),
('F', 'Fluid Dynamics'),
('G', 'Gravitation, Cosmology and Astroparticle Physics'),
('H', 'High-Energy Physics'),
('M', 'Mathematical Physics'),
('N', 'Nuclear Physics'),
('Q', 'Quantum Statistical Mechanics'),
('S', 'Statistical and Soft Matter Physics'),
)
journals_spec_dict = dict(SCIPOST_JOURNALS_SPECIALIZATIONS)
class Journal(models.Model):
name = models.CharField(max_length=100, choices=SCIPOST_JOURNALS,
unique=True)
doi_string = models.CharField(max_length=200, blank=True, null=True)
issn = models.CharField(max_length=16, default='2542-4653')
def __str__(self):
return self.name
class Volume(models.Model):
in_journal = models.ForeignKey(Journal, on_delete=models.CASCADE)
number = models.PositiveSmallIntegerField(unique=True)
start_date = models.DateField(default=timezone.now)
until_date = models.DateField(default=timezone.now)
doi_string = models.CharField(max_length=200, blank=True, null=True)
def __str__(self):
return str(self.in_journal) + ' Vol. ' + str(self.number)
class Issue(models.Model):
in_volume = models.ForeignKey(Volume, on_delete=models.CASCADE)
number = models.PositiveSmallIntegerField()
start_date = models.DateField(default=timezone.now)
until_date = models.DateField(default=timezone.now)
doi_string = models.CharField(max_length=200, blank=True, null=True)
# absolute path on filesystem: (JOURNALS_DIR)/journal/vol/issue/
path = models.CharField(max_length=200)
class Meta:
unique_together = ('number', 'in_volume')
def __str__(self):
text = str(self.in_volume) + ' issue ' + str(self.number)
if self.start_date.month == self.until_date.month:
text += ' (' + self.until_date.strftime('%B') + ' ' + self.until_date.strftime('%Y') + ')'
else:
text += (' (' + self.start_date.strftime('%B') + '-' + self.until_date.strftime('%B') +
' ' + self.until_date.strftime('%Y') + ')')
text = 'up to {{ until_month }} {{ year }}'
template = Template(text)
context = Context({'until_month': self.start_date.strftime('%B'),
'year': self.until_date.strftime('%Y')})
return template.render(context)
class Publication(models.Model):
accepted_submission = models.OneToOneField('submissions.Submission', on_delete=models.CASCADE)
in_issue = models.ForeignKey(Issue, on_delete=models.CASCADE)
paper_nr = models.PositiveSmallIntegerField()
discipline = models.CharField(max_length=20, choices=SCIPOST_DISCIPLINES, default='physics')
domain = models.CharField(max_length=3, choices=SCIPOST_JOURNALS_DOMAINS)
subject_area = models.CharField(max_length=10, choices=SCIPOST_SUBJECT_AREAS,
verbose_name='Primary subject area', default='Phys:QP')
secondary_areas = ChoiceArrayField(models.CharField(max_length=10,
choices=SCIPOST_SUBJECT_AREAS),
blank=True, null=True)
title = models.CharField(max_length=300)
author_list = models.CharField(max_length=1000, verbose_name="author list")
# Authors which have been mapped to contributors:
authors = models.ManyToManyField(Contributor, blank=True, related_name='authors_pub')
authors_unregistered = models.ManyToManyField(UnregisteredAuthor, blank=True,
related_name='authors_unregistered')
first_author = models.ForeignKey(Contributor, blank=True, null=True, on_delete=models.CASCADE)
first_author_unregistered = models.ForeignKey(UnregisteredAuthor, blank=True, null=True,
on_delete=models.CASCADE,
related_name='first_author_unregistered')
authors_claims = models.ManyToManyField(Contributor, blank=True,
related_name='authors_pub_claims')
authors_false_claims = models.ManyToManyField(Contributor, blank=True,
related_name='authors_pub_false_claims')
abstract = models.TextField()
pdf_file = models.FileField(upload_to='UPLOADS/PUBLICATIONS/%Y/%m/', max_length=200)
metadata = JSONField(default={}, blank=True, null=True)
metadata_xml = models.TextField(blank=True, null=True) # for Crossref deposit
BiBTeX_entry = models.TextField(blank=True, null=True)
doi_label = models.CharField(max_length=200, blank=True, null=True) # Used for file name
doi_string = models.CharField(max_length=200, blank=True, null=True)
submission_date = models.DateField(verbose_name='submission date')
acceptance_date = models.DateField(verbose_name='acceptance date')
publication_date = models.DateField(verbose_name='publication date')
latest_activity = models.DateTimeField(default=timezone.now)
citedby = JSONField(default={}, blank=True, null=True)
header = (self.citation() + ', '
+ self.title[:30] + ' by ' + self.author_list[:30]
+ ', published ' + self.publication_date.strftime('%Y-%m-%d'))
return header
return (journal_name_abbrev_citation(self.in_issue.in_volume.in_journal.name)
+ ' ' + str(self.in_issue.in_volume.number)
+ ', ' + paper_nr_string(self.paper_nr)
+ ' (' + self.publication_date.strftime('%Y') + ')')
def citation_for_web(self):
citation = ('{{ abbrev }} <strong>{{ volume_nr }}</strong>'
', {{ paper_nr }} ({{ year }})')
template = Template(citation)
context = Context(
{'abbrev': journal_name_abbrev_citation(self.in_issue.in_volume.in_journal.name),
'volume_nr': str(self.in_issue.in_volume.number),
'issue_nr': str(self.in_issue.number),
'paper_nr': paper_nr_string(self.paper_nr),
'year': self.publication_date.strftime('%Y'), })
return template.render(context)
def citation_for_web_linked(self):
citation = ('<a href="{% url \'scipost:publication_detail\' doi_string=doi_string %}">'
'{{ abbrev }} <strong>{{ volume_nr }}</strong>'
', {{ paper_nr }} ({{ year }})')
template = Template(citation)
context = Context(
{'doi_string': self.doi_string,
'abbrev': journal_name_abbrev_citation(self.in_issue.in_volume.in_journal.name),
'volume_nr': str(self.in_issue.in_volume.number),
'issue_nr': str(self.in_issue.number),
'paper_nr': paper_nr_string(self.paper_nr),
'year': self.publication_date.strftime('%Y'), })
return template.render(context)
header = ('<li class="publicationHeader">'
'<p class="publicationTitle"><a href="{% url \'scipost:publication_detail\' doi_string=doi_string %}">{{ title }}</a></p>'
'<p class="publicationAuthors">{{ author_list }}</p>'
'<p class="publicationReference">{{ citation }} '
'| published {{ pub_date }}</p>'
'<p class="publicationAbstract">{{ abstract }}</p>'
'<ul class="publicationClickables">'
'<li><button class="toggleAbstractButton">Toggle abstract</button></li>'
'<li class="publicationPDF"><a href="{% url \'scipost:publication_pdf\' doi_string=doi_string %}" target="_blank">pdf</a></li>'
'</ul>'
'</li>')
template = Template(header)
context = Context({
'doi_string': self.doi_string,
'title': self.title,
'author_list': self.author_list,
'citation': self.citation,
'pub_date': self.publication_date.strftime('%d %B %Y'),
'abstract': self.abstract,
})
return template.render(context)
This method is called from the publication_detail template.
It provides all the details for a publication.
"""
pub_details = (
'<p class="publicationTitle"><a href="{% url \'scipost:publication_detail\' doi_string=doi_string %}">{{ title }}</a></p>'
'<p class="publicationAuthors">{{ author_list }}</p>'
'<p class="publicationReference">{{ citation }} '
'| published {{ pub_date}}</p>'
'<ul class="publicationClickables">'
'<li>doi: {{ doi_string }}</li>'
'<li class="publicationPDF">'
'<a href="{% url \'scipost:publication_pdf\' doi_string=doi_string %}" target="_blank">pdf</a>'
'</li>'
'<li><a href="#openModal">BiBTeX</a></li>'
'<li><a href="{% url \'submissions:submission\' arxiv_identifier_w_vn_nr='
'arxiv_identifier_w_vn_nr %}">Submissions/Reports</a></li>'
'</ul><br/><hr class="hr6"/>'
'<h3>Abstract:</h3>'
'<p class="publicationAbstract">{{ abstract }}</p>'
'<div id="openModal" class="modalDialog"><div>'
'<a href="#close" title="Close" class="close">X</a>'
'<h2>BiBTeX</h2><p>{{ BiBTeX|linebreaks }}</p></div></div>'
)
template = Template(pub_details)
context = Context({
'title': self.title,
'author_list': self.author_list,
'citation': self.citation_for_web,
'pub_date': self.publication_date.strftime('%d %B %Y'),
'abstract': self.abstract,
'doi_string': self.doi_string,
'BiBTeX': self.BiBTeX_entry,
'arxiv_identifier_w_vn_nr': self.accepted_submission.arxiv_identifier_w_vn_nr
})
return template.render(context)
def citations_as_ul(self):
output = '<ul>'
context = Context({})
nr = 0
for cit in self.citedby:
output += '<li>{{ auth_' + str(nr) + ' }}'
context['auth_' + str(nr)] = (cit['first_author_given_name']
+ ' ' + cit['first_author_surname'])
if cit['multiauthors']:
output += ' <em>et al.</em>'
output += (', <em>{{ title_' + str(nr) + ' }}</em>, <br/>'
'{{ journal_abbrev_' + str(nr) + ' }}')
context['title_' + str(nr)] = cit['article_title']
context['journal_abbrev_' + str(nr)] = cit['journal_abbreviation']
if cit['volume']:
context['volume_' + str(nr)] = cit['volume']
output += ' <strong>{{ volume_' + str(nr) + ' }}</strong>'
output += ', '
if cit['first_page']:
output += '{{ first_page_' + str(nr) + ' }}'
context['first_page_' + str(nr)] = cit['first_page']
elif cit['item_number']:
output += '{{ item_number_' + str(nr) + ' }}'
context['item_number_' + str(nr)] = cit['item_number']
output += (' ({{ year_' + str(nr) + ' }}) '
'<a href="https://doi.org/{{ doi_' + str(nr) + ' }}" '
'target="_blank">[Crossref]</a>')
context['year_' + str(nr)] = cit['year']
context['doi_' + str(nr)] = cit['doi']
output += '</li>'
nr += 1
output += '</ul>'
template = Template(output)
return template.render(context)
class Deposit(models.Model):
"""
Each time a Crossref deposit is made for a Publication,
a Deposit object instance is created containing the Publication's
current version of the metadata_xml field.
All deposit history is thus contained here.
"""
publication = models.ForeignKey(Publication, on_delete=models.CASCADE)
doi_batch_id = models.CharField(max_length=40, default='')
metadata_xml = models.TextField(blank=True, null=True)
deposition_date = models.DateTimeField(default=timezone.now)
def __str__(self):
return (self.deposition_date.strftime('%Y-%m-%D') +
' for ' + self.publication.doi_string)