SciPost Code Repository

Skip to content
Snippets Groups Projects
Commit 91d233a2 authored by Jorran de Wit's avatar Jorran de Wit
Browse files

Auto-link Commentaries and Publications

parent ef3d291a
No related branches found
No related tags found
No related merge requests found
Showing
with 300 additions and 132 deletions
......@@ -9,6 +9,7 @@ from django.template.loader import get_template
from .models import Commentary
from .constants import COMMENTARY_PUBLISHED, COMMENTARY_PREPRINT
from comments.forms import CommentForm
from scipost.services import DOICaller, ArxivCaller
from scipost.models import Contributor
......@@ -101,7 +102,7 @@ class RequestCommentaryForm(forms.ModelForm):
super().__init__(*args, **kwargs)
def save(self, *args, **kwargs):
self.instance.parse_links_into_urls()
self.instance.parse_links_into_urls(commit=False)
if self.requested_by:
self.instance.requested_by = self.requested_by
return super().save(*args, **kwargs)
......@@ -291,3 +292,66 @@ class CommentarySearchForm(forms.Form):
title__icontains=self.cleaned_data['title'],
pub_abstract__icontains=self.cleaned_data['abstract'],
author_list__icontains=self.cleaned_data['author']).order_by('-pub_date')
class CommentSciPostPublication(CommentForm):
"""
This Form will let authors of an SciPost publication comment on their Publication
using the Commentary functionalities. It will create an Commentary page if it does not
exist yet.
It inherits from ModelForm: CommentForm and thus will, by default, return a Comment!
"""
def __init__(self, *args, **kwargs):
self.publication = kwargs.pop('publication')
self.current_user = kwargs.pop('current_user')
super().__init__(*args, **kwargs)
def save(self, commit=True):
"""
Create (vetted) Commentary page if not exist and do save actions as
per original CommentForm.
"""
if not commit:
raise AssertionError('CommentSciPostPublication can only be used with commit=True')
try:
commentary = self.publication.commentary
except Commentary.DoesNotExist:
submission = self.publication.accepted_submission
commentary = Commentary(**{
# 'vetted_by': None,
'requested_by': self.current_user.contributor,
'vetted': True,
'type': COMMENTARY_PUBLISHED,
'discipline': self.publication.discipline,
'domain': self.publication.domain,
'subject_area': self.publication.subject_area,
'title': self.publication.title,
'arxiv_identifier': submission.arxiv_identifier_w_vn_nr,
'arxiv_link': submission.arxiv_link,
'pub_DOI': self.publication.doi_string,
'metadata': self.publication.metadata,
'scipost_publication': self.publication,
'author_list': self.publication.author_list,
'journal': self.publication.in_issue.in_volume.in_journal.get_name_display(),
'pages': self.publication.in_issue.number,
'volume': self.publication.in_issue.in_volume.number,
'pub_date': self.publication.publication_date,
'pub_abstract': self.publication.abstract,
})
commentary.parse_links_into_urls(commit=False)
commentary.save()
commentary.authors.add(*self.publication.authors.all())
commentary.authors_claims.add(*self.publication.authors_claims.all())
commentary.authors_false_claims.add(*self.publication.authors_false_claims.all())
# Original saving steps
comment = super().save(commit=False)
comment.author = self.current_user.contributor
comment.is_author_reply = True
comment.content_object = commentary
comment.save()
comment.grant_permissions()
return comment
# -*- coding: utf-8 -*-
# Generated by Django 1.11.4 on 2017-11-11 10:53
from __future__ import unicode_literals
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('journals', '0052_auto_20171107_1354'),
('commentaries', '0019_auto_20170925_2124'),
]
operations = [
migrations.AddField(
model_name='commentary',
name='scipost_publication',
field=models.OneToOneField(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='commentary', to='journals.Publication'),
),
migrations.AlterField(
model_name='commentary',
name='title',
field=models.CharField(max_length=300),
),
]
......@@ -28,7 +28,9 @@ class Commentary(TimeStampedModel):
subject_area = models.CharField(max_length=10, choices=SCIPOST_SUBJECT_AREAS,
default='Phys:QP')
open_for_commenting = models.BooleanField(default=True)
title = models.CharField(max_length=300, verbose_name='title')
# Article/publication data
title = models.CharField(max_length=300)
arxiv_identifier = models.CharField(max_length=100, blank=True,
verbose_name="arXiv identifier (including version nr)")
arxiv_link = models.URLField(verbose_name='arXiv link (including version nr)', blank=True)
......@@ -41,9 +43,11 @@ class Commentary(TimeStampedModel):
arxiv_or_DOI_string = models.CharField(max_length=100,
verbose_name='string form of arxiv nr or'
' DOI for commentary url')
author_list = models.CharField(max_length=1000)
scipost_publication = models.OneToOneField('journals.Publication', null=True, blank=True,
related_name='commentary')
# Authors which have been mapped to contributors:
author_list = models.CharField(max_length=1000)
authors = models.ManyToManyField('scipost.Contributor', blank=True,
related_name='commentaries')
authors_claims = models.ManyToManyField('scipost.Contributor', blank=True,
......@@ -71,7 +75,7 @@ class Commentary(TimeStampedModel):
def get_absolute_url(self):
return reverse('commentaries:commentary', args=(self.arxiv_or_DOI_string,))
def parse_links_into_urls(self, commit=False):
def parse_links_into_urls(self, commit=True):
""" Takes the arXiv nr or DOI and turns it into the urls """
if self.pub_DOI:
self.arxiv_or_DOI_string = self.pub_DOI
......
......@@ -18,28 +18,33 @@
</td>
</tr>
{% if commentary.type == 'published' %}
<tr>
<td>Journal ref.:</td>
<td>{{commentary.journal}} {{commentary.volume}}, {{commentary.pages}}</td>
</tr>
<tr>
<td>DOI:</td>
<td>
<a href="{{commentary.pub_DOI_link}}" target="_blank">{{commentary.pub_DOI_link}}</a>
</td>
</tr>
<tr>
<td>Journal ref.:</td>
<td>{{commentary.journal}} {{commentary.volume}}{% if commentary.pages %}, {{commentary.pages}}{% endif %}</td>
</tr>
<tr>
<td>DOI:</td>
<td>
<a href="{{commentary.pub_DOI_link}}" target="_blank">{{commentary.pub_DOI_link}}</a>
</td>
</tr>
{% elif commentary.type == 'preprint' %}
<tr>
<td>arxiv Link:</td>
<td>
<a href="{{commentary.arxiv_link}}" target="_blank">{{commentary.arxiv_link}}</a>
</td>
</tr>
<tr>
<td>arxiv Link:</td>
<td>
<a href="{{commentary.arxiv_link}}" target="_blank">{{commentary.arxiv_link}}</a>
</td>
</tr>
{% endif %}
{% if commentary.pub_date %}
<tr>
<td>Date:</td>
<td>{{commentary.pub_date}}</td>
</tr>
<tr>
<td>Date:</td>
<td>{{commentary.pub_date}}</td>
</tr>
{% endif %}
</table>
{% if commentary.scipost_publication %}
<br>
<p class="my-0">Published in {{commentary.scipost_publication.in_issue.in_volume.in_journal.get_name_display}}: <a href="{{commentary.scipost_publication.get_absolute_url}}">{{commentary.scipost_publication.in_issue.in_volume.in_journal.get_abbreviation_citation}} <strong>{{commentary.scipost_publication.in_issue.in_volume.number}}</strong>, {{commentary.scipost_publication.get_paper_nr}} ({{commentary.scipost_publication.publication_date|date:'Y'}})</a></p>
{% endif %}
{% extends 'scipost/base.html' %}
{% block breadcrumb %}
<nav class="breadcrumb py-md-2 px-0">
<div class="container">
{% block breadcrumb_items %}
<a href="{% url 'commentaries:commentaries' %}" class="breadcrumb-item">Commentaries</a>
{% endblock %}
</div>
</nav>
{% endblock %}
{% extends 'journals/base_detail_page.html' %}
{% block pagetitle %}: Comment on your Publication{% endblock pagetitle %}
{% block breadcrumb_items %}
{{ block.super }}
<span class="breadcrumb-item">Comment on your Publication</span>
{% endblock %}
{% block content %}
<h1 class="highlight">Comment on your Publication</h1>
{% include 'partials/journals/publication_li_content.html' with publication=publication %}
<h3 class="mt-2">Abstract</h3>
<p>{{ publication.abstract|default:'No abstract found' }}</p>
{% url 'comments:new_comment' object_id=object_id type_of_object=type_of_object as url %}
{% include 'comments/_add_comment_form.html' with form=form url=url %}
{% endblock content %}
{% extends 'scipost/base.html' %}
{% extends 'commentaries/base.html' %}
{% load scipost_extras %}
{% block pagetitle %}: Commentary detail{% endblock pagetitle %}
{% block headsup %}
{% block breadcrumb_items %}
{{ block.super }}
<span class="breadcrumb-item">{{ commentary }}</span>
{% endblock %}
{% load scipost_extras %}
{% block content %}
{% endblock headsup %}
<h1 class="highlight">SciPost Commentary Page</h1>
{% block content %}
<h3>Original publication:</h3>
{% include 'commentaries/_commentary_summary.html' with commentary=commentary %}
<br>
<div class="row">
<div class="col-12">
<h1 class="highlight">SciPost Commentary Page (non-SciPost publications)</h1>
</div>
</div>
<div class="row">
<div class="col-12">
<h2>Original publication: </h2>
{% include 'commentaries/_commentary_summary.html' with commentary=commentary %}
</div>
</div>
<div class="row">
<div class="col-12">
<h3>Abstract:</h3>
<p>{{ commentary.pub_abstract }}</p>
</div>
</div>
<h3>Abstract:</h3>
<p>{{ commentary.pub_abstract }}</p>
{% include 'scipost/comments_block.html' with comments=commentary.comments.vetted type_of_object='Commentary' %}
......
......@@ -35,4 +35,8 @@ urlpatterns = [
name='vet_commentary_requests_submit'),
url(r'^vet_commentary_requests/(?P<commentary_id>[0-9]+)/modify$',
views.modify_commentary_request, name='modify_commentary_request'),
# Commentaries on SciPost Publications
url(r'^publications/(?P<doi_label>[a-zA-Z]+.[0-9]+.[0-9]+.[0-9]{3,})/comment$',
views.comment_on_publication, name='comment_on_publication')
]
......@@ -3,6 +3,7 @@ from django.contrib import messages
from django.contrib.auth.decorators import login_required, permission_required
from django.core.mail import EmailMessage
from django.core.urlresolvers import reverse, reverse_lazy
from django.db import transaction
from django.shortcuts import redirect
from django.template.loader import render_to_string
from django.views.generic.edit import CreateView
......@@ -12,10 +13,12 @@ from django.http import Http404
from .models import Commentary
from .forms import DOIToQueryForm, ArxivQueryForm, VetCommentaryForm, RequestCommentaryForm,\
CommentarySearchForm, RequestPublishedArticleForm, RequestArxivPreprintForm
CommentarySearchForm, RequestPublishedArticleForm, RequestArxivPreprintForm,\
CommentSciPostPublication
from comments.models import Comment
from comments.forms import CommentForm
from journals.models import Publication
from scipost.mixins import PaginationMixin
import strings
......@@ -238,3 +241,25 @@ def commentary_detail(request, arxiv_or_DOI_string):
context = {'commentary': commentary,
'author_replies': author_replies, 'form': form}
return render(request, 'commentaries/commentary_detail.html', context)
@login_required
@permission_required('scipost.can_submit_comments', raise_exception=True)
@transaction.atomic
def comment_on_publication(request, doi_label):
"""
This will let authors of an SciPost publication comment on their Publication by
automatically creating a Commentary page if not exist already.
"""
publication = get_object_or_404(Publication.objects.published(),
doi_label=doi_label, authors=request.user.contributor)
form = CommentSciPostPublication(request.POST or None, request.FILES or None,
publication=publication, current_user=request.user)
if form.is_valid():
comment = form.save()
return redirect(comment.content_object.get_absolute_url())
context = {
'publication': publication,
'form': form
}
return render(request, 'commentaries/comment_on_publication.html', context)
......@@ -12,7 +12,7 @@ class CommentForm(forms.ModelForm):
'comment_text', 'remarks_for_editors', 'file_attachment']
def __init__(self, *args, **kwargs):
super(CommentForm, self).__init__(*args, **kwargs)
super().__init__(*args, **kwargs)
self.fields['comment_text'].widget.attrs.update(
{'placeholder': 'NOTE: only serious and meaningful Comments will be accepted.'})
self.fields['remarks_for_editors'].widget.attrs.update(
......
......@@ -14,7 +14,7 @@
</script>
{% endblock %}
<form enctype="multipart/form-data" action="{{url}}" method="post">
<form enctype="multipart/form-data" {% if url %}action="{{url}}" {% endif %}method="post">
{% csrf_token %}
<div class="row">
<div class="col-md-9">
......
......@@ -39,7 +39,7 @@ class IssueManager(models.Manager):
**kwargs).order_by('-until_date').first()
class PublicationManager(models.Manager):
class PublicationQuerySet(models.QuerySet):
def get_published(self, *args, **kwargs):
try:
return self.published(*args, **kwargs)[0]
......
......@@ -11,7 +11,7 @@ from .constants import SCIPOST_JOURNALS, SCIPOST_JOURNALS_DOMAINS,\
STATUS_DRAFT, STATUS_PUBLISHED, ISSUE_STATUSES,\
CCBY4, CC_LICENSES, CC_LICENSES_URI
from .helpers import paper_nr_string, journal_name_abbrev_citation
from .managers import IssueManager, PublicationManager, JournalManager
from .managers import IssueManager, PublicationQuerySet, JournalManager
from scipost.constants import SCIPOST_DISCIPLINES, SCIPOST_SUBJECT_AREAS
from scipost.fields import ChoiceArrayField
......@@ -53,7 +53,7 @@ class Journal(models.Model):
class Volume(models.Model):
in_journal = models.ForeignKey(Journal, on_delete=models.CASCADE)
in_journal = models.ForeignKey('journals.Journal', on_delete=models.CASCADE)
number = models.PositiveSmallIntegerField()
start_date = models.DateField(default=timezone.now)
until_date = models.DateField(default=timezone.now)
......@@ -72,7 +72,7 @@ class Volume(models.Model):
class Issue(models.Model):
in_volume = models.ForeignKey(Volume, on_delete=models.CASCADE)
in_volume = models.ForeignKey('journals.Volume', on_delete=models.CASCADE)
number = models.PositiveSmallIntegerField()
start_date = models.DateField(default=timezone.now)
until_date = models.DateField(default=timezone.now)
......@@ -129,7 +129,7 @@ class Publication(models.Model):
"""
# Publication data
accepted_submission = models.OneToOneField('submissions.Submission', on_delete=models.CASCADE)
in_issue = models.ForeignKey(Issue, on_delete=models.CASCADE)
in_issue = models.ForeignKey('journals.Issue', on_delete=models.CASCADE)
paper_nr = models.PositiveSmallIntegerField()
# Core fields
......@@ -187,7 +187,7 @@ class Publication(models.Model):
latest_metadata_update = models.DateTimeField(blank=True, null=True)
latest_activity = models.DateTimeField(default=timezone.now)
objects = PublicationManager()
objects = PublicationQuerySet.as_manager()
def __str__(self):
header = (self.citation() + ', '
......
......@@ -19,94 +19,78 @@
{% block content %}
<div class="row">
<div class="col-12">
<h1 class="highlight">Add author to publication</h1>
</div>
</div>
<div class="row">
<div class="col-12">
{% include 'journals/_publication_details.html' with publication=publication %}
</div>
</div>
<h1 class="highlight">Add author to publication</h1>
{% include 'partials/journals/publication_li_content.html' with publication=publication %}
<br>
<div class="row">
<div class="col-12">
<h2 class="highlight">Add an (unregistered) author</h2>
</div>
</div>
<div class="row">
<div class="col-12">
<h3>Current list of authors as contributors:</h3>
<ul class="list-group list-group-noborder">
<ul>
{% for author in publication.authors.all %}
<li class="list-group-item py-1 pl-2">
<a href="{% url 'scipost:contributor_info' author.id %}">{{ author.user.first_name }} {{ author.user.last_name }}</a>
</li>
<li><a href="{% url 'scipost:contributor_info' author.id %}">{{ author.user.first_name }} {{ author.user.last_name }}</a></li>
{% empty %}
No unregistered authors known.
<li>No unregistered authors known.</li>
{% endfor %}
</ul>
<h3>Current list of additional authors (unregistered):</h3>
<ul class="list-group list-group-noborder">
<ul>
{% for author in publication.authors_unregistered.all %}
<li class="list-group-item py-1 pl-2">{{ author }}</li>
<li>{{ author }}</li>
{% empty %}
No unregistered authors known.
<li>No unregistered authors known.</li>
{% endfor %}
</ul>
<hr class="small">
<div class="row">
<div class="col-md-8">
<h3>Search for missing author:</h3>
<form action="{% url 'journals:add_author' publication.id %}" method="post">
{% csrf_token %}
{{form|bootstrap}}
<input class="btn btn-secondary" type="submit" value="Search">
</form>
{% if form.has_changed %}
<h3 class="mt-4">Identified as contributor:</h3>
<ul class="list-group">
{% for contributor in contributors_found %}
<li class="list-group-item p-2">
<div class="d-block w-100 font-weight-bold">{{ contributor.user.first_name }} {{ contributor.user.last_name }}</div>
<a class="d-block" href="{% url 'journals:add_author' publication_id=publication.id contributor_id=contributor.id %}">Add this Contributor as author of this Publication</a>
</li>
{% empty %}
<span class="text-danger">No Contributor with this name could be identified.</span>
{% endfor %}
</ul>
<h3 class="mt-2">Identified as existing unregistered author:</h3>
<ul class="list-group">
{% for unreg_auth in unregistered_authors_found %}
<li class="list-group-item">
<div class="d-block w-100 font-weight-bold">{{ unreg_auth }}
<a class="d-block" href="{% url 'journals:add_unregistered_author' publication_id=publication.id unregistered_author_id=unreg_auth.id %}">Add this unregistered author as author of this Publication</a>
</li>
{% empty %}
<span class="text-danger">No UnregisteredAuthor with this name could be found in the database.</span>
{% endfor %}
</ul>
<h3 class="mt-3">You can otherwise create an UnregisteredAuthor object instance and link it to this publication:</h3>
<form action="{% url 'journals:add_new_unreg_author' publication_id=publication.id %}" method="post">
{% csrf_token %}
{{ new_unreg_author_form|bootstrap }}
<input class="btn btn-secondary" type="submit" value="Add">
</form>
{% endif %}
</div>
</div>
<br>
<h2 class="highlight">Add an (unregistered) author</h2>
<h3>Search for missing author:</h3>
<form action="{% url 'journals:add_author' publication.id %}" method="post">
{% csrf_token %}
{{form|bootstrap}}
<input class="btn btn-primary" type="submit" value="Search">
</form>
{% if form.has_changed %}
<br>
<h3 class="mt-2">Identified as contributor:</h3>
<ul class="list-group">
{% for contributor in contributors_found %}
<li class="list-group-item p-2">
<div class="d-block w-100 font-weight-bold">{{ contributor.user.first_name }} {{ contributor.user.last_name }}</div>
<a class="d-block" href="{% url 'journals:add_author' publication_id=publication.id contributor_id=contributor.id %}">Add this Contributor as author of this Publication</a>
</li>
{% empty %}
<span class="text-danger">No Contributor with this name could be identified.</span>
{% endfor %}
</ul>
<h3 class="mt-2">Identified as existing unregistered author:</h3>
<ul class="list-group">
{% for unreg_auth in unregistered_authors_found %}
<li class="list-group-item">
<div class="d-block w-100 font-weight-bold">{{ unreg_auth }}
<a class="d-block" href="{% url 'journals:add_unregistered_author' publication_id=publication.id unregistered_author_id=unreg_auth.id %}">Add this unregistered author as author of this Publication</a>
</li>
{% empty %}
<span class="text-danger">No UnregisteredAuthor with this name could be found in the database.</span>
{% endfor %}
</ul>
<h3 class="mt-3">You can otherwise create an UnregisteredAuthor object instance and link it to this publication:</h3>
<form action="{% url 'journals:add_new_unreg_author' publication_id=publication.id %}" method="post">
{% csrf_token %}
{{ new_unreg_author_form|bootstrap }}
<input class="btn btn-primary" type="submit" value="Add">
</form>
{% endif %}
<br>
<h3>
<a href="{{publication.get_absolute_url}}">Return to the publication's page</a> or to the <a href="{% url 'journals:manage_metadata' %}">metadata management page</a>
<a href="{{publication.get_absolute_url}}">Return to the publication's page</a> or to the <a href="{% url 'journals:manage_metadata' %}">metadata management page</a>.
</h3>
</div>
</div>
......
{% extends 'scipost/base.html' %}
{% load staticfiles %}
{% block pagetitle %}: {{journal}}{% endblock pagetitle %}
{% block body_class %}{{block.super}} journals{% endblock %}
{% block breadcrumb %}
<nav class="breadcrumb py-md-2 px-0 hidden-sm-down">
<div class="container">
{% block breadcrumb_items %}
<a href="{% url 'journals:journals' %}" class="breadcrumb-item">Journals</a>
<a href="{% url 'scipost:publication_detail' publication.doi_label %}" class="breadcrumb-item">{{ publication.doi_label }}</a>
{% endblock %}
</div>
</nav>
{% endblock %}
......@@ -49,7 +49,14 @@
{% block content %}
{% is_edcol_admin request.user as is_edcol_admin %}
{% include 'journals/_publication_details.html' with publication=publication %}
{% include 'partials/journals/publication_summary.html' with publication=publication %}
{% if publication.commentary and publication.commentary.comments.vetted.exists %}
<h3>Post-publication commentaries</h3>
<p>
There has been commented on this Publication ({{ publication.commentary.comments.vetted.count }}), see <a href="{{ publication.commentary.get_absolute_url }}">this Publication's Commentary page</a> for details.
</p>
{% endif %}
<hr>
{% if publication.citedby|length >= 1 %}
......@@ -100,6 +107,13 @@
</div>
</div>
{% if request.user and request.user.contributor in publication.authors.all %}
<h3>Author actions</h3>
<ul>
<li><a href="{% url 'commentaries:comment_on_publication' publication.doi_label %}">Place a comment on this publication</a></li>
</ul>
{% endif %}
{% if is_edcol_admin %}
<hr>
<div class="row">
......
<h5 class="pb-0">{{publication.get_subject_area_display}}</h5>
<h3><a href="{{publication.get_absolute_url}}">{{publication.title}}</a></h3>
<p class="mt-0 mb-3">{{ publication.author_list }}</p>
<p class="mt-0 mb-2">{{ publication.author_list }}</p>
<p class="text-muted mb-0">
{{ publication.citation }} &middot; <span class="font-weight-light">published {{ publication.publication_date|date:'j F Y' }}</span>
</p>
......@@ -35,7 +35,7 @@
{% for publication in publications %}
<li class="list-group-item">
<div class="card-body px-0">
{% include 'journals/_publication_details_small.html' with publication=publication %}
{% include 'partials/journals/publication_li_content.html' with publication=publication %}
</div>
</li>
{% endfor %}
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment