Source code for comments.views
__copyright__ = "Copyright © Stichting SciPost (SciPost Foundation)"
__license__ = "AGPL v3"
import time
from django.contrib.auth.decorators import permission_required, login_required
from django.contrib import messages
from django.db import transaction
from django.http import HttpResponse, Http404
from django.shortcuts import get_object_or_404, render, redirect
from django.urls import reverse
from django.utils import timezone
from django.views.generic.list import ListView
from guardian.shortcuts import get_objects_for_user
import strings
from .constants import EXTENTIONS_IMAGES, EXTENTIONS_PDF
from .models import Comment
from .forms import CommentForm, VetCommentForm, CommentTextSearchForm
from .utils import validate_file_extention
from commentaries.models import Commentary
from mails.utils import DirectMailUtil
from scipost.mixins import PaginationMixin
from submissions.models import Submission, Report
from theses.models import ThesisLink
[docs]class CommentListView(PaginationMixin, ListView):
model = Comment
form = CommentTextSearchForm
paginate_by = 10
context_object_name = "comment_list"
[docs] def get_queryset(self):
"""Perform search form here already to get the right pagination numbers."""
self.form = self.form(self.request.GET)
if self.form.is_valid() and self.form.has_changed():
return self.form.search_results()
return self.model.objects.vetted().order_by("-date_submitted")
[docs] def get_context_data(self, **kwargs):
# Call the base implementation first to get a context
context = super().get_context_data(**kwargs)
# Form into the context!
context["form"] = self.form
return context
[docs]@login_required
@permission_required("scipost.can_submit_comments", raise_exception=True)
def new_comment(request, **kwargs):
"""Form view to submit new Comment."""
form = CommentForm(request.POST or None, request.FILES or None)
if form.is_valid():
object_id = int(kwargs["object_id"])
type_of_object = kwargs["type_of_object"]
if type_of_object == "thesislink":
_object = get_object_or_404(
ThesisLink.objects.open_for_commenting(), id=object_id
)
elif type_of_object == "submission":
_object = get_object_or_404(
Submission.objects.open_for_commenting(), id=object_id
)
_object.add_event_for_eic("A new comment has been added.")
elif type_of_object == "commentary":
_object = get_object_or_404(
Commentary.objects.open_for_commenting(), id=object_id
)
new_comment = form.save(commit=False)
new_comment.author = request.user.contributor
new_comment.content_object = _object
new_comment.save()
new_comment.grant_permissions()
# Mails
mail_sender = DirectMailUtil(
"commenters/inform_commenter_comment_received", comment=new_comment
)
mail_sender.send_mail()
if isinstance(new_comment.core_content_object, Submission):
mail_sender = DirectMailUtil(
"eic/inform_eic_comment_received", comment=new_comment
)
mail_sender.send_mail()
messages.success(request, strings.acknowledge_submit_comment)
return redirect(_object.get_absolute_url())
context = {"form": form}
return render(request, "comments/add_comment.html", context)
[docs]@permission_required("scipost.can_vet_comments", raise_exception=True)
def vet_submitted_comments_list(request):
"""Replace by a list page instead?"""
comments_to_vet = Comment.objects.awaiting_vetting().order_by("date_submitted")
form = VetCommentForm()
context = {"comments_to_vet": comments_to_vet, "form": form}
return render(request, "comments/vet_submitted_comments.html", context)
[docs]@login_required
@transaction.atomic
def vet_submitted_comment(request, comment_id):
# Method `get_objects_for_user` gets all Comments that are assigned to the user
# or *all* comments if user has the `scipost.can_vet_comments` permission.
comment = get_object_or_404(
(
get_objects_for_user(
request.user, "comments.can_vet_comments"
).awaiting_vetting()
),
id=comment_id,
)
form = VetCommentForm(request.POST or None)
if form.is_valid():
if form.cleaned_data["action_option"] == "1":
# Accept the comment as is
Comment.objects.filter(id=comment_id).update(
status=1, vetted_by=request.user.contributor
)
comment.refresh_from_db()
# Update `latest_activity` fields
content_object = comment.content_object
if hasattr(content_object, "latest_activity"):
content_object.__class__.objects.filter(id=content_object.id).update(
latest_activity=timezone.now()
)
content_object.refresh_from_db()
if isinstance(content_object, Submission):
# Add events to Submission and send mail to author of the Submission
content_object.add_event_for_eic("A Comment has been accepted.")
content_object.add_event_for_author("A new Comment has been added.")
if not comment.is_author_reply:
mail_sender = DirectMailUtil(
"authors/inform_authors_comment_received",
instance=content_object,
comment=comment,
)
mail_sender.send_mail()
elif isinstance(content_object, Report):
# Add events to related Submission and send mail to author of the Submission
content_object.submission.add_event_for_eic(
"A Comment has been accepted."
)
content_object.submission.add_event_for_author(
"A new Comment has been added."
)
if comment.is_author_reply:
# Email Report author: Submission authors have replied
mail_sender = DirectMailUtil(
"referees/inform_referee_authors_replied_to_report",
report=content_object,
)
mail_sender.send_mail()
else: # this is a Comment on the Report from another Contributor
# Email Report author: Contributor has commented the Report
mail_sender = DirectMailUtil(
"referees/inform_referee_contributor_commented_report",
report=content_object,
)
mail_sender.send_mail()
# Email submission authors: Contributor has commented the Report
mail_sender = DirectMailUtil(
"authors/inform_authors_contributor_commented_report",
report=content_object,
)
mail_sender.send_mail()
elif isinstance(content_object, Comment):
# This means that this Comment is part of a hierarchy of Comments.
# We thus go back to the core object
core_content_object = comment.core_content_object
if isinstance(core_content_object, Submission):
# Add events to Submission and send mail to author of the Submission
core_content_object.add_event_for_eic(
"A Comment has been accepted."
)
core_content_object.add_event_for_author(
"A new Comment has been added."
)
if not comment.is_author_reply:
mail_sender = DirectMailUtil(
"authors/inform_authors_comment_received",
instance=core_content_object,
comment=comment,
)
mail_sender.send_mail()
# In all cases, email the comment author
mail_sender = DirectMailUtil(
"commenters/inform_commenter_comment_vetted", comment=comment
)
mail_sender.send_mail()
elif form.cleaned_data["action_option"] == "2":
# The comment request is simply rejected
Comment.objects.filter(id=comment.id).update(
status=int(form.cleaned_data["refusal_reason"]),
vetted_by=request.user.contributor,
)
comment.refresh_from_db()
# Send emails
mail_sender = DirectMailUtil(
"commenters/inform_commenter_comment_rejected",
comment=comment,
email_response=form.cleaned_data["email_response_field"],
) # TODO: needs kwargs to mail template
mail_sender.send_mail()
if isinstance(comment.content_object, Submission):
# Add event if commented to Submission
comment.content_object.add_event_for_eic("A Comment has been rejected.")
elif isinstance(comment.content_object, Report):
comment.content_object.submission.add_event_for_eic(
"A Comment has been rejected."
)
messages.success(request, "Submitted Comment vetted.")
if isinstance(comment.content_object, Submission):
submission = comment.content_object
if submission.editor_in_charge == request.user.contributor:
# Redirect a EIC back to the Editorial Page
return redirect(
reverse(
"submissions:editorial_page",
args=(submission.preprint.identifier_w_vn_nr,),
)
)
elif isinstance(comment.content_object, Report):
submission = comment.content_object.submission
if submission.editor_in_charge == request.user.contributor:
# Redirect a EIC back to the Editorial Page
return redirect(
reverse(
"submissions:editorial_page",
args=(submission.preprint.identifier_w_vn_nr,),
)
)
elif request.user.has_perm("scipost.can_vet_comments"):
# Redirect vetters back to check for other unvetted comments
return redirect(reverse("comments:vet_submitted_comments_list"))
return redirect(comment.get_absolute_url())
context = {"comment": comment, "form": form}
return render(request, "comments/vet_submitted_comment.html", context)
[docs]@permission_required("scipost.can_submit_comments", raise_exception=True)
@transaction.atomic
def reply_to_comment(request, comment_id):
comment = get_object_or_404(Comment, pk=comment_id)
# Verify if this is from an author:
related_object = comment.content_object
if isinstance(related_object, Submission) or isinstance(related_object, Commentary):
is_author = related_object.authors.filter(
id=request.user.contributor.id
).exists()
elif isinstance(related_object, Report):
is_author = related_object.submission.authors.filter(
id=request.user.contributor.id
).exists()
elif isinstance(related_object, ThesisLink):
# ThesisLink
is_author = related_object.author == request.user.contributor
else:
# No idea what this could be, but just to be sure
is_author = related_object.author == request.user.contributor
form = CommentForm(request.POST or None, request.FILES or None)
if form.is_valid():
newcomment = form.save(commit=False)
newcomment.content_object = comment
newcomment.is_author_reply = is_author
newcomment.author = request.user.contributor
newcomment.save()
newcomment.grant_permissions()
mail_sender = DirectMailUtil(
"commenters/inform_commenter_comment_received", comment=newcomment
)
mail_sender.send_mail()
if isinstance(newcomment.core_content_object, Submission):
mail_sender = DirectMailUtil(
"eic/inform_eic_comment_received", comment=newcomment
)
mail_sender.send_mail()
messages.success(
request,
"<h3>Thank you for contributing a Reply</h3>"
"It will soon be vetted by an Editor.",
)
return redirect(newcomment.content_object.get_absolute_url())
context = {"comment": comment, "is_author": is_author, "form": form}
return render(request, "comments/reply_to_comment.html", context)
[docs]@permission_required("scipost.can_submit_comments", raise_exception=True)
def reply_to_report(request, report_id):
report = get_object_or_404(Report, pk=report_id)
# Verify if this is from an author:
is_author = report.submission.authors.filter(user=request.user).exists()
form = CommentForm(
request.POST or None, request.FILES or None, is_report_comment=True
)
if form.is_valid():
newcomment = form.save(commit=False)
newcomment.content_object = report
newcomment.is_author_reply = is_author
newcomment.author = request.user.contributor
newcomment.save()
newcomment.grant_permissions()
mail_sender = DirectMailUtil(
"eic/inform_eic_comment_received", comment=newcomment
)
mail_sender.send_mail()
mail_sender = DirectMailUtil(
"commenters/inform_commenter_comment_received", comment=newcomment
)
mail_sender.send_mail()
messages.success(
request,
"<h3>Thank you for contributing a Reply</h3>"
"It will soon be vetted by an Editor.",
)
return redirect(newcomment.content_object.get_absolute_url())
context = {"report": report, "is_author": is_author, "form": form}
return render(request, "comments/reply_to_report.html", context)
[docs]def attachment(request, comment_id):
"""
Open/read attachment of Comment if available.
"""
comment = get_object_or_404(
Comment.objects.exclude(file_attachment=""), pk=comment_id
)
if validate_file_extention(comment.file_attachment, EXTENTIONS_IMAGES):
content_type = "image/jpeg"
elif validate_file_extention(comment.file_attachment, EXTENTIONS_PDF):
content_type = "application/pdf"
else:
raise Http404
response = HttpResponse(comment.file_attachment.read(), content_type=content_type)
filename = "comment-attachment-%s" % comment.file_attachment.name
response["Content-Disposition"] = "filename=" + filename
return response