diff --git a/SciPost_v1/settings.py b/SciPost_v1/settings.py index e999aaf861ad93644bac8aac6fa39b8d4a61a69c..9c9c14867438a7d096c4c664dcf8975f8434dd0d 100644 --- a/SciPost_v1/settings.py +++ b/SciPost_v1/settings.py @@ -107,6 +107,11 @@ SHELL_PLUS_POST_IMPORTS = ( ('theses.factories', ('ThesisLinkFactory')), ('comments.factories', ('CommentFactory')), ('submissions.factories', ('SubmissionFactory', 'EICassignedSubmissionFactory')), + ('commentaries.factories', + ('EmptyCommentaryFactory', + 'VettedCommentaryFactory', + 'UnvettedCommentaryFactory', + 'UnpublishedVettedCommentaryFactory',)), ) MATHJAX_ENABLED = True diff --git a/commentaries/factories.py b/commentaries/factories.py index 18e72a7b59715315a717f78316e9011ea1f34477..31f1354fa2c7c811daccdbfa7bd9a27cdf55850f 100644 --- a/commentaries/factories.py +++ b/commentaries/factories.py @@ -1,11 +1,11 @@ import factory -from .models import Commentary, COMMENTARY_TYPES - from scipost.constants import DISCIPLINE_PHYSICS, SCIPOST_SUBJECT_AREAS from scipost.factories import ContributorFactory from journals.models import SCIPOST_JOURNALS_DOMAINS +from common.helpers import random_arxiv_identifier_with_version_number +from .models import Commentary, COMMENTARY_TYPES class CommentaryFactory(factory.django.DjangoModelFactory): class Meta: @@ -18,12 +18,16 @@ class CommentaryFactory(factory.django.DjangoModelFactory): discipline = DISCIPLINE_PHYSICS domain = SCIPOST_JOURNALS_DOMAINS[0][0] subject_area = SCIPOST_SUBJECT_AREAS[0][1][0][0] - pub_title = factory.Sequence(lambda n: "Commentary %d" % n) + pub_title = factory.Faker('bs') pub_DOI = '10.1103/PhysRevB.92.214427' - arxiv_identifier = '1610.06911v1' + arxiv_identifier = factory.Sequence(lambda n: random_arxiv_identifier_with_version_number()) author_list = factory.Faker('name') pub_abstract = factory.Faker('text') + @factory.post_generation + def create_urls(self, create, extracted, **kwargs): + self.parse_links_into_urls(commit=create) + class EmptyCommentaryFactory(CommentaryFactory): pub_DOI = None @@ -34,5 +38,9 @@ class VettedCommentaryFactory(CommentaryFactory): vetted = True -class UnVettedCommentaryFactory(CommentaryFactory): +class UnpublishedVettedCommentaryFactory(VettedCommentaryFactory): + pub_DOI = '' + + +class UnvettedCommentaryFactory(CommentaryFactory): vetted = False diff --git a/commentaries/templates/commentaries/commentaries.html b/commentaries/templates/commentaries/commentaries.html index 8414ca91ab9e0cbd56269e503f245f572b909d4c..d555bd005778f7f47c1417d24c707efb0efbb062 100644 --- a/commentaries/templates/commentaries/commentaries.html +++ b/commentaries/templates/commentaries/commentaries.html @@ -11,7 +11,6 @@ {% block content %} -{# <section>#} <div class="row"> <div class="col-md-4"> <div class="panel page-header-panel"> diff --git a/commentaries/templates/commentaries/commentary_detail.html b/commentaries/templates/commentaries/commentary_detail.html index e468065f95c17ca29d3c3cf5d850192aa9fbd558..b9c5fcd2f9a3691477692d54a4441d17f4b8c913 100644 --- a/commentaries/templates/commentaries/commentary_detail.html +++ b/commentaries/templates/commentaries/commentary_detail.html @@ -58,32 +58,6 @@ {% include 'scipost/comments_block.html' %} - -{% if user.is_authenticated and commentary.open_for_commenting and perms.scipost.can_submit_comments %} -<hr> - -<div class="row"> - <div class="col-12"> - <div class="panel"> - <h2>Contribute a Comment:</h2> - </div> - </div> -</div> -<div class="row"> - <div class="col-12"> - <form enctype="multipart/form-data" action="{% url 'commentaries:commentary' arxiv_or_DOI_string=commentary.arxiv_or_DOI_string %}" method="post"> - {% csrf_token %} - {% load crispy_forms_tags %} - {% crispy form %} - </form> - </div> - <div class="col-12"> - <h3>Preview of your comment:</h3> - <p id="preview-comment_text"></p> - </div> -</div> - -{% endif %} - +{% include 'comments/new_comment.html' with object_id=commentary.id type_of_object='commentary' open_for_commenting=commentary.open_for_commenting %} {% endblock content %} diff --git a/commentaries/test_forms.py b/commentaries/test_forms.py index 8a81d2abb6dd2c55da24c687e78ccde109544c71..cec31d3071f2944cc61a8c0cebb785adb186f27f 100644 --- a/commentaries/test_forms.py +++ b/commentaries/test_forms.py @@ -3,7 +3,7 @@ from django.test import TestCase from common.helpers import model_form_data from scipost.factories import UserFactory -from .factories import VettedCommentaryFactory, UnVettedCommentaryFactory +from .factories import VettedCommentaryFactory, UnvettedCommentaryFactory from .forms import RequestCommentaryForm, VetCommentaryForm from .models import Commentary @@ -12,7 +12,7 @@ class TestVetCommentaryForm(TestCase): fixtures = ['permissions', 'groups'] def setUp(self): - self.commentary = UnVettedCommentaryFactory.create() + self.commentary = UnvettedCommentaryFactory.create() self.user = UserFactory() self.form_data = { 'action_option': VetCommentaryForm.ACTION_ACCEPT, diff --git a/commentaries/test_views.py b/commentaries/test_views.py index d724770ab2f0f57b8229618661ef257897fcfdd1..50d6850fd46c2b7166370a078492a227e04dcda5 100644 --- a/commentaries/test_views.py +++ b/commentaries/test_views.py @@ -1,10 +1,10 @@ from django.core.urlresolvers import reverse from django.contrib.auth.models import Group -from django.test import TestCase +from django.test import TestCase, Client from scipost.factories import ContributorFactory -from .factories import UnVettedCommentaryFactory, VettedCommentaryFactory +from .factories import UnvettedCommentaryFactory, VettedCommentaryFactory, UnpublishedVettedCommentaryFactory from .forms import CommentarySearchForm from .models import Commentary @@ -83,7 +83,7 @@ class VetCommentaryRequestsTest(TestCase): self.assertEquals(response.context['commentary_to_vet'], None) # Unvetted Commentaries do exist! - UnVettedCommentaryFactory() + UnvettedCommentaryFactory() response = self.client.get(self.view_url) self.assertTrue(type(response.context['commentary_to_vet']) is Commentary) @@ -108,3 +108,19 @@ class BrowseCommentariesTest(TestCase): self.assertTrue(response.context['commentary_browse_list'].count() >= 1) # The search form is passed trough the view... self.assertTrue(type(response.context['form']) is CommentarySearchForm) + + +class CommentaryDetailTest(TestCase): + fixtures = ['permissions', 'groups'] + + def setUp(self): + self.client = Client() + self.commentary = UnpublishedVettedCommentaryFactory() + self.target = reverse( + 'commentaries:commentary', + kwargs={'arxiv_or_DOI_string': self.commentary.arxiv_or_DOI_string} + ) + + def test_status_code_200(self): + response = self.client.get(self.target) + self.assertEqual(response.status_code, 200) diff --git a/commentaries/views.py b/commentaries/views.py index 339bab4f935cf0a3bcaefbf36a682982be70c215..1ae2de1ceffbf60e70bfde80aa58b16db5149c22 100644 --- a/commentaries/views.py +++ b/commentaries/views.py @@ -299,45 +299,10 @@ def browse(request, discipline, nrweeksback): def commentary_detail(request, arxiv_or_DOI_string): commentary = get_object_or_404(Commentary, arxiv_or_DOI_string=arxiv_or_DOI_string) comments = commentary.comment_set.all() - if request.method == 'POST': - form = CommentForm(request.POST, request.FILES) - if form.is_valid(): - author = Contributor.objects.get(user=request.user) - newcomment = Comment(commentary=commentary, author=author, - is_rem=form.cleaned_data['is_rem'], - is_que=form.cleaned_data['is_que'], - is_ans=form.cleaned_data['is_ans'], - is_obj=form.cleaned_data['is_obj'], - is_rep=form.cleaned_data['is_rep'], - is_val=form.cleaned_data['is_val'], - is_lit=form.cleaned_data['is_lit'], - is_sug=form.cleaned_data['is_sug'], - file_attachment=form.cleaned_data['file_attachment'], - comment_text=form.cleaned_data['comment_text'], - remarks_for_editors=form.cleaned_data['remarks_for_editors'], - date_submitted=timezone.now(), - ) - newcomment.save() - author.nr_comments = Comment.objects.filter(author=author).count() - author.save() - context = {'ack_header': 'Thank you for contributing a Comment.', - 'ack_message': 'It will soon be vetted by an Editor.', - 'followup_message': 'Back to the ', - 'followup_link': reverse( - 'commentaries:commentary', - kwargs={ - 'arxiv_or_DOI_string': newcomment.commentary.arxiv_or_DOI_string - } - ), - 'followup_link_label': ' Commentary page you came from' - } - return render(request, 'scipost/acknowledgement.html', context) - else: - form = CommentForm() + form = CommentForm() try: - author_replies = Comment.objects.filter(commentary=commentary, - is_author_reply=True, - status__gte=1) + author_replies = Comment.objects.filter( + commentary=commentary, is_author_reply=True, status__gte=1) except Comment.DoesNotExist: author_replies = () context = {'commentary': commentary, diff --git a/comments/managers.py b/comments/managers.py new file mode 100644 index 0000000000000000000000000000000000000000..7b71d0454d88ad178a94393c21cc5b310ce23960 --- /dev/null +++ b/comments/managers.py @@ -0,0 +1,5 @@ +from django.db import models + +class CommentManager(models.Manager): + def vetted(self): + return self.filter(status__gte=1) diff --git a/comments/models.py b/comments/models.py index e449d2a7382c0b0054082c1772ac5f46cf689b64..3851d0737a0a93519a09ae986e63be0dad6498f5 100644 --- a/comments/models.py +++ b/comments/models.py @@ -10,6 +10,8 @@ from scipost.models import TimeStampedModel, Contributor from submissions.models import Submission, Report from theses.models import ThesisLink +from .managers import CommentManager + COMMENT_CATEGORIES = ( ('ERR', 'erratum'), ('REM', 'remark'), @@ -37,19 +39,24 @@ class Comment(TimeStampedModel): on a particular publication or in reply to an earlier Comment. """ status = models.SmallIntegerField(default=0) - vetted_by = models.ForeignKey(Contributor, blank=True, null=True, - on_delete=models.CASCADE, - related_name='comment_vetted_by') - file_attachment = models.FileField(upload_to='uploads/comments/%Y/%m/%d/', blank=True, - validators=[validate_file_extension, - validate_max_file_size]) + vetted_by = models.ForeignKey( + Contributor, + blank=True, + null=True, + on_delete=models.CASCADE, + related_name='comment_vetted_by' + ) + file_attachment = models.FileField( + upload_to='uploads/comments/%Y/%m/%d/', blank=True, + validators=[validate_file_extension, + validate_max_file_size] + ) # a Comment is either for a Commentary or Submission or a ThesisLink. commentary = models.ForeignKey(Commentary, blank=True, null=True, on_delete=models.CASCADE) submission = models.ForeignKey(Submission, blank=True, null=True, on_delete=models.CASCADE) thesislink = models.ForeignKey(ThesisLink, blank=True, null=True, on_delete=models.CASCADE) is_author_reply = models.BooleanField(default=False) - in_reply_to_comment = models.ForeignKey('self', blank=True, null=True, - on_delete=models.CASCADE) + in_reply_to_comment = models.ForeignKey('self', blank=True, null=True, on_delete=models.CASCADE) in_reply_to_report = models.ForeignKey(Report, blank=True, null=True, on_delete=models.CASCADE) author = models.ForeignKey(Contributor, on_delete=models.CASCADE) anonymous = models.BooleanField(default=False, verbose_name='Publish anonymously') @@ -64,19 +71,20 @@ class Comment(TimeStampedModel): is_lit = models.BooleanField(default=False, verbose_name='pointer to related literature') is_sug = models.BooleanField(default=False, verbose_name='suggestion for further work') comment_text = models.TextField() - remarks_for_editors = models.TextField(default='', blank=True, - verbose_name='optional remarks for the Editors only') + remarks_for_editors = models.TextField(default='', blank=True, verbose_name='optional remarks for the Editors only') date_submitted = models.DateTimeField('date submitted') # Opinions nr_A = models.PositiveIntegerField(default=0) - in_agreement = models.ManyToManyField(Contributor, - related_name='in_agreement', blank=True) + in_agreement = models.ManyToManyField(Contributor, related_name='in_agreement', blank=True) nr_N = models.PositiveIntegerField(default=0) - in_notsure = models.ManyToManyField(Contributor, - related_name='in_notsure', blank=True) + in_notsure = models.ManyToManyField(Contributor, related_name='in_notsure', blank=True) nr_D = models.PositiveIntegerField(default=0) - in_disagreement = models.ManyToManyField(Contributor, - related_name='in_disagreement', blank=True) + in_disagreement = models.ManyToManyField( + Contributor, + related_name='in_disagreement', + blank=True + ) + objects = CommentManager() def __str__(self): return ('by ' + self.author.user.first_name + ' ' + self.author.user.last_name + diff --git a/comments/templates/comments/new_comment.html b/comments/templates/comments/new_comment.html new file mode 100644 index 0000000000000000000000000000000000000000..80f19afad8798a122d2dd5873019c139d02849ec --- /dev/null +++ b/comments/templates/comments/new_comment.html @@ -0,0 +1,27 @@ +{% if user.is_authenticated and open_for_commenting and perms.scipost.can_submit_comments %} +<hr /> + +<div class="row"> + <div class="col-12"> + <div class="panel"> + <h2>Contribute a Comment:</h2> + </div> + </div> +</div> +<div class="row"> + <div class="col-12"> + <form enctype="multipart/form-data" + action="{% url 'comments:new_comment' object_id=object_id type_of_object=type_of_object %}" + method="post"> + {% csrf_token %} + {% load crispy_forms_tags %} + {% crispy form %} + </form> + </div> + <div class="col-12"> + <h3>Preview of your comment:</h3> + <p id="preview-comment_text"></p> + </div> +</div> + +{% endif %} diff --git a/comments/test_views.py b/comments/test_views.py new file mode 100644 index 0000000000000000000000000000000000000000..e1824139a5c2dd7def2f41ae2f6c6fd742914e41 --- /dev/null +++ b/comments/test_views.py @@ -0,0 +1,126 @@ +from django.test import TestCase, RequestFactory, Client +from django.urls import reverse, reverse_lazy +from django.contrib.auth.models import Group +from django.contrib.messages.storage.fallback import FallbackStorage +from django.core.exceptions import PermissionDenied + +from scipost.factories import ContributorFactory +from theses.factories import ThesisLinkFactory +from submissions.factories import EICassignedSubmissionFactory +from commentaries.factories import UnpublishedVettedCommentaryFactory + +from .factories import CommentFactory +from .forms import CommentForm +from .models import Comment +from .views import new_comment + +from common.helpers import model_form_data + + +class TestNewComment(TestCase): + fixtures = ['groups', 'permissions'] + + def install_messages_middleware(self, request): + # I don't know what the following three lines do, but they help make a RequestFactory + # work with the messages middleware + setattr(request, 'session', 'session') + messages = FallbackStorage(request) + setattr(request, '_messages', messages) + + def test_submitting_comment_on_thesislink_creates_comment_and_redirects(self): + """ Valid Comment gets saved """ + + contributor = ContributorFactory() + thesislink = ThesisLinkFactory() + valid_comment_data = model_form_data(CommentFactory.build(), CommentForm) + target = reverse('comments:new_comment', kwargs={'object_id': thesislink.id, 'type_of_object': 'thesislink'}) + + comment_count = Comment.objects.filter(author=contributor).count() + self.assertEqual(comment_count, 0) + + request = RequestFactory().post(target, valid_comment_data) + self.install_messages_middleware(request) + request.user = contributor.user + response = new_comment(request, object_id=thesislink.id, type_of_object='thesislink') + + comment_count = Comment.objects.filter(author=contributor).count() + self.assertEqual(comment_count, 1) + + response.client = Client() + expected_redirect_link = reverse('theses:thesis', kwargs={'thesislink_id': thesislink.id}) + self.assertRedirects(response, expected_redirect_link) + + def test_submitting_comment_on_submission_creates_comment_and_redirects(self): + contributor = ContributorFactory() + submission = EICassignedSubmissionFactory() + submission.open_for_commenting = True + submission.save() + valid_comment_data = model_form_data(CommentFactory.build(), CommentForm) + target = reverse( + 'comments:new_comment', + kwargs={'object_id': submission.id, 'type_of_object': 'submission'}, + ) + + comment_count = Comment.objects.filter(author=contributor).count() + self.assertEqual(comment_count, 0) + + request = RequestFactory().post(target, valid_comment_data) + self.install_messages_middleware(request) + request.user = contributor.user + response = new_comment(request, object_id=submission.id, type_of_object='submission') + + comment_count = Comment.objects.filter(author=contributor).count() + self.assertEqual(comment_count, 1) + + response.client = Client() + expected_redirect_link = reverse( + 'submissions:submission', + kwargs={'arxiv_identifier_w_vn_nr': submission.arxiv_identifier_w_vn_nr} + ) + self.assertRedirects(response, expected_redirect_link) + + + def test_submitting_comment_on_commentary_creates_comment_and_redirects(self): + """ Valid Comment gets saved """ + + contributor = ContributorFactory() + commentary = UnpublishedVettedCommentaryFactory() + valid_comment_data = model_form_data(CommentFactory.build(), CommentForm) + target = reverse('comments:new_comment', kwargs={'object_id': commentary.id, 'type_of_object': 'commentary'}) + + comment_count = Comment.objects.filter(author=contributor).count() + self.assertEqual(comment_count, 0) + + request = RequestFactory().post(target, valid_comment_data) + self.install_messages_middleware(request) + request.user = contributor.user + response = new_comment(request, object_id=commentary.id, type_of_object='commentary') + + comment_count = commentary.comment_set.count() + self.assertEqual(comment_count, 1) + + response.client = Client() + expected_redirect_link = reverse( + 'commentaries:commentary', kwargs={'arxiv_or_DOI_string': commentary.arxiv_or_DOI_string}) + self.assertRedirects(response, expected_redirect_link) + + + def test_submitting_comment_on_submission_that_is_not_open_for_commenting_should_be_impossible(self): + contributor = ContributorFactory() + submission = EICassignedSubmissionFactory() + submission.open_for_commenting = False + submission.save() + valid_comment_data = model_form_data(CommentFactory.build(), CommentForm) + target = reverse( + 'comments:new_comment', + kwargs={'object_id': submission.id, 'type_of_object': 'submission'}, + ) + + comment_count = Comment.objects.filter(author=contributor).count() + self.assertEqual(comment_count, 0) + + request = RequestFactory().post(target, valid_comment_data) + self.install_messages_middleware(request) + request.user = contributor.user + with self.assertRaises(PermissionDenied): + response = new_comment(request, object_id=submission.id, type_of_object='submission') diff --git a/comments/urls.py b/comments/urls.py index b417f028aa127ff3d16f325d953216416131e4a9..3d1747ee28e087ff4a52d0da5cd0a794032fc935 100644 --- a/comments/urls.py +++ b/comments/urls.py @@ -10,4 +10,5 @@ urlpatterns = [ url(r'^vet_submitted_comment_ack/(?P<comment_id>[0-9]+)$', views.vet_submitted_comment_ack, name='vet_submitted_comment_ack'), url(r'^express_opinion/(?P<comment_id>[0-9]+)$', views.express_opinion, name='express_opinion'), url(r'^express_opinion/(?P<comment_id>[0-9]+)/(?P<opinion>[AND])$', views.express_opinion, name='express_opinion'), + url(r'^new_comment/(?P<type_of_object>[a-z]+)/(?P<object_id>[0-9]+)$', views.new_comment, name='new_comment') ] diff --git a/comments/views.py b/comments/views.py index 254206ca81d8248a8dadc41049646b1566b4ba8d..ce859b86553018a6788aee4a82472c71cfa388f8 100644 --- a/comments/views.py +++ b/comments/views.py @@ -1,17 +1,79 @@ from django.utils import timezone -from django.shortcuts import get_object_or_404, render +from django.shortcuts import get_object_or_404, render, redirect from django.contrib.auth.decorators import permission_required +from django.contrib import messages from django.core.mail import EmailMessage from django.core.urlresolvers import reverse -from django.http import HttpResponseRedirect +from django.core.exceptions import PermissionDenied +from django.http import HttpResponseRedirect, Http404 + +import strings from .models import Comment from .forms import CommentForm, VetCommentForm, comment_refusal_dict from scipost.models import Contributor, title_dict +from theses.models import ThesisLink from submissions.utils import SubmissionUtils -from submissions.models import Report +from submissions.models import Submission, Report +from commentaries.models import Commentary + +@permission_required('scipost.can_submit_comments', raise_exception=True) +def new_comment(request, **kwargs): + if request.method == "POST": + form = CommentForm(request.POST) + if form.is_valid(): + author = Contributor.objects.get(user=request.user) + object_id = int(kwargs["object_id"]) + type_of_object = kwargs["type_of_object"] + new_comment = Comment( + author=author, + is_rem=form.cleaned_data['is_rem'], + is_que=form.cleaned_data['is_que'], + is_ans=form.cleaned_data['is_ans'], + is_obj=form.cleaned_data['is_obj'], + is_rep=form.cleaned_data['is_rep'], + is_val=form.cleaned_data['is_val'], + is_lit=form.cleaned_data['is_lit'], + is_sug=form.cleaned_data['is_sug'], + file_attachment=form.cleaned_data['file_attachment'], + comment_text=form.cleaned_data['comment_text'], + remarks_for_editors=form.cleaned_data['remarks_for_editors'], + date_submitted=timezone.now(), + ) + if type_of_object == "thesislink": + thesislink = ThesisLink.objects.get(id=object_id) + if not thesislink.open_for_commenting: + raise PermissionDenied + new_comment.thesislink = thesislink + redirect_link = reverse('theses:thesis', kwargs={"thesislink_id":thesislink.id}) + elif type_of_object == "submission": + submission = Submission.objects.get(id=object_id) + if not submission.open_for_commenting: + raise PermissionDenied + new_comment.submission = submission + redirect_link = reverse( + 'submissions:submission', + kwargs={"arxiv_identifier_w_vn_nr": submission.arxiv_identifier_w_vn_nr} + ) + elif type_of_object == "commentary": + commentary = Commentary.objects.get(id=object_id) + if not commentary.open_for_commenting: + raise PermissionDenied + new_comment.commentary = commentary + redirect_link = reverse( + 'commentaries:commentary', kwargs={'arxiv_or_DOI_string': commentary.arxiv_or_DOI_string} + ) + new_comment.save() + author.nr_comments = Comment.objects.filter(author=author).count() + author.save() + messages.add_message( + request, messages.SUCCESS, strings.acknowledge_submit_comment) + return redirect(redirect_link) + else: + # This view is only accessible by POST request + raise Http404 @permission_required('scipost.can_vet_comments', raise_exception=True) def vet_submitted_comments(request): diff --git a/common/helpers/__init__.py b/common/helpers/__init__.py index d91d1905c12f9529071e5406d04f90cd16891b0f..d1875920b99074217a6ce3d80fa10128bd4e568a 100644 --- a/common/helpers/__init__.py +++ b/common/helpers/__init__.py @@ -1,3 +1,6 @@ +import random +import string + def model_form_data(model, form_class, form_kwargs={}): ''' Returns a dict that can be used to instantiate a form object. @@ -25,6 +28,14 @@ def model_form_data(model, form_class, form_kwargs={}): form_fields = list(form_class(**form_kwargs).fields.keys()) return filter_keys(model_data, form_fields) +def random_arxiv_identifier_with_version_number(): + return random_arxiv_identifier_without_version_number() + "v0" + +def random_arxiv_identifier_without_version_number(): + return random_digits(4) + "." + random_digits(5) + +def random_digits(n): + return "".join(random.choice(string.digits) for _ in range(n)) def filter_keys(dictionary, keys_to_keep): # Field is empty if not on model. diff --git a/scipost/factories.py b/scipost/factories.py index 27ebc93ef459df1de461cf65af874680d0ecbb48..e32c408deb837497d49cfbffff1e8e8c49b76b23 100644 --- a/scipost/factories.py +++ b/scipost/factories.py @@ -12,7 +12,7 @@ class ContributorFactory(factory.django.DjangoModelFactory): title = "MR" user = factory.SubFactory('scipost.factories.UserFactory', contributor=None) - status = 1 + status = 1 # normal user vetted_by = factory.SubFactory('scipost.factories.ContributorFactory', vetted_by=None) diff --git a/strings/__init__.py b/strings/__init__.py index f51088e3aeecb9d059e14d341717c77936519e6c..acb0df6ceafab9bb8a85bae4049a9ccb7fdc8cec 100644 --- a/strings/__init__.py +++ b/strings/__init__.py @@ -7,6 +7,9 @@ acknowledge_request_commentary = ( "Your request will soon be handled by an Editor. <br>" "Thank you for your request for a Commentary Page." ) +acknowledge_submit_comment = ( + "Thank you for contributing a Comment. It will soon be vetted by an Editor." +) # Arxiv response is not valid arxiv_caller_errormessages = { diff --git a/submissions/factories.py b/submissions/factories.py index 7f07c30523a94c2ec6c33b0b423a47cb62bd756f..1abdf6974e4c7caa28ae6ebcb49a9eb1096df83a 100644 --- a/submissions/factories.py +++ b/submissions/factories.py @@ -1,8 +1,7 @@ import factory -import random -import string from scipost.factories import ContributorFactory +from common.helpers import random_arxiv_identifier_with_version_number from .models import Submission @@ -18,21 +17,10 @@ class SubmissionFactory(factory.django.DjangoModelFactory): abstract = factory.Faker('text') arxiv_link = factory.Faker('uri') arxiv_identifier_w_vn_nr = factory.Sequence(lambda n: random_arxiv_identifier_with_version_number()) - arxiv_identifier_wo_vn_nr = factory.LazyAttribute(lambda obj: obj.arxiv_identifier_w_vn_nr[0:-2]) domain = 'E' class EICassignedSubmissionFactory(SubmissionFactory): status = 'EICassigned' editor_in_charge = factory.SubFactory(ContributorFactory) - - - -def random_arxiv_identifier_with_version_number(): - return random_arxiv_identifier_without_version_number() + "v0" - -def random_arxiv_identifier_without_version_number(): - return random_digits(4) + "." + random_digits(5) - -def random_digits(n): - return "".join(random.choice(string.digits) for _ in range(n)) + open_for_commenting = True diff --git a/submissions/templates/submissions/submission_detail.html b/submissions/templates/submissions/submission_detail.html index 68750602f0e9eddaf708bac9af84bef5b2d2d317..3e793e6ced6e4fdf739845e90fc5ef1584e0fb95 100644 --- a/submissions/templates/submissions/submission_detail.html +++ b/submissions/templates/submissions/submission_detail.html @@ -205,7 +205,7 @@ <p> <a target="_blank" href="{{ reply.file_attachment.url }}"> {% if reply.file_attachment|is_image %} - <img class="attachment attachment-comment" src="{{ reply.file_attachment.url }}"> + <img class="attachment attachment-comment" src="{{ reply.file_attachment.url }}"> {% else %} {{ reply.file_attachment|filename }}<br><small>{{ reply.file_attachment.size|filesizeformat }}</small> {% endif %} @@ -304,37 +304,8 @@ {% endif %} - - {% include 'scipost/comments_block.html' %} -{% if user.is_authenticated and submission.open_for_commenting and perms.scipost.can_submit_comments %} -<hr> -<div id="contribute_comment"> - <div class="row"> - <div class="col-12"> - <div class="panel"> - <h2>Contribute a Comment:</h2> - </div> - </div> - </div> - <div class="row"> - <div class="col-12"> - <form enctype="multipart/form-data" action="{% url 'submissions:submission' arxiv_identifier_w_vn_nr=submission.arxiv_identifier_w_vn_nr %}" method="post"> - {% csrf_token %} - {% load crispy_forms_tags %} - {% crispy form %} - </form> - </div> - </div> - - <div class="row"> - <div class="col-12"> - <h3>Preview of your comment:</h3> - <p id="preview-comment_text"></p> - </div> - </div> -</div> -{% endif %} +{% include 'comments/new_comment.html' with object_id=submission.id type_of_object='submission' open_for_commenting=submission.open_for_commenting %} {% endblock content %} diff --git a/submissions/test_views.py b/submissions/test_views.py index 5eef315b06ebc633dbb967284d7d0336a8073e17..bb177e9292a3dc57e2c9a01a91c3a161e47ffb89 100644 --- a/submissions/test_views.py +++ b/submissions/test_views.py @@ -3,6 +3,8 @@ from django.test import Client from submissions.views import * import django.core.urlresolvers +from .factories import EICassignedSubmissionFactory + class PrefillUsingIdentifierTest(TestCase): fixtures = ['permissions', 'groups', 'contributors'] @@ -45,3 +47,19 @@ class SubmitManuscriptTest(TestCase): {**params, **extras}) self.assertEqual(response.status_code, 200) + + +class SubmissionDetailTest(TestCase): + fixtures = ['permissions', 'groups'] + + def setUp(self): + self.client = Client() + self.submission = EICassignedSubmissionFactory() + self.target = reverse( + 'submissions:submission', + kwargs={'arxiv_identifier_w_vn_nr': self.submission.arxiv_identifier_w_vn_nr} + ) + + def test_status_code_200(self): + response = self.client.get(self.target) + self.assertEqual(response.status_code, 200) diff --git a/submissions/views.py b/submissions/views.py index f69b23d8c9e75518494648553fe98f18d87bdf63..2681da5f9dfafd7d11f42ee3bb6f18a085af8dc5 100644 --- a/submissions/views.py +++ b/submissions/views.py @@ -285,41 +285,8 @@ def submission_detail(request, arxiv_identifier_w_vn_nr): other_versions = Submission.objects.filter( arxiv_identifier_wo_vn_nr=submission.arxiv_identifier_wo_vn_nr ).exclude(pk=submission.id) - if request.method == 'POST': - form = CommentForm(request.POST, request.FILES) - if form.is_valid(): - author = Contributor.objects.get(user=request.user) - newcomment = Comment( - submission=submission, - author=author, - is_rem=form.cleaned_data['is_rem'], - is_que=form.cleaned_data['is_que'], - is_ans=form.cleaned_data['is_ans'], - is_obj=form.cleaned_data['is_obj'], - is_rep=form.cleaned_data['is_rep'], - is_val=form.cleaned_data['is_val'], - is_lit=form.cleaned_data['is_lit'], - is_sug=form.cleaned_data['is_sug'], - file_attachment=form.cleaned_data['file_attachment'], - comment_text=form.cleaned_data['comment_text'], - remarks_for_editors=form.cleaned_data['remarks_for_editors'], - date_submitted=timezone.now(), - ) - newcomment.save() - author.nr_comments = Comment.objects.filter(author=author).count() - author.save() - context = {'ack_header': 'Thank you for contributing a Comment.', - 'ack_message': 'It will soon be vetted by an Editor.', - 'followup_message': 'Back to the ', - 'followup_link': reverse( - 'submissions:submission', - kwargs={'arxiv_identifier_w_vn_nr': newcomment.submission.arxiv_identifier_w_vn_nr} - ), - 'followup_link_label': ' Submission page you came from' - } - return render(request, 'scipost/acknowledgement.html', context) - else: - form = CommentForm() + + form = CommentForm() reports = submission.report_set.all() try: diff --git a/theses/templates/theses/thesis_detail.html b/theses/templates/theses/thesis_detail.html index f355fc701ff43ee369ebbfe9f8fc5d13e60f7270..edde03144f188effb6c6fad2c30bf6783b4ac6b9 100644 --- a/theses/templates/theses/thesis_detail.html +++ b/theses/templates/theses/thesis_detail.html @@ -50,30 +50,6 @@ {% include 'scipost/comments_block.html' %} -{% if user.is_authenticated and thesislink.open_for_commenting and perms.scipost.can_submit_comments %} -<hr /> - -<div class="row"> - <div class="col-12"> - <div class="panel"> - <h2>Contribute a Comment:</h2> - </div> - </div> -</div> -<div class="row"> - <div class="col-12"> - <form enctype="multipart/form-data" action="{% url 'theses:thesis' thesislink_id=thesislink.id %}" method="post"> - {% csrf_token %} - {% load crispy_forms_tags %} - {% crispy form %} - </form> - </div> - <div class="col-12"> - <h3>Preview of your comment:</h3> - <p id="preview-comment_text"></p> - </div> -</div> - -{% endif %} +{% include 'comments/new_comment.html' with object_id=thesislink.id type_of_object='thesislink' open_for_commenting=thesislink.open_for_commenting %} {% endblock content %} diff --git a/theses/test_views.py b/theses/test_views.py index b5ee851bcf04cd742cfc21c0f7c33a3976019550..8f6d5f202018e73ecbec408158447ede95c0cc6b 100644 --- a/theses/test_views.py +++ b/theses/test_views.py @@ -30,24 +30,6 @@ class TestThesisDetail(TestCase): response = client.post(target) self.assertEqual(response.status_code, 200) - def test_submitting_comment_creates_comment(self): - """ Valid Comment gets saved """ - - contributor = ContributorFactory() - thesislink = ThesisLinkFactory() - valid_comment_data = model_form_data(CommentFactory.build(), CommentForm) - target = reverse('theses:thesis', kwargs={'thesislink_id': thesislink.id}) - - comment_count = Comment.objects.filter(author=contributor).count() - self.assertEqual(comment_count, 0) - - request = RequestFactory().post(target, valid_comment_data) - request.user = contributor.user - response = thesis_detail(request, thesislink_id=thesislink.id) - - comment_count = Comment.objects.filter(author=contributor).count() - self.assertEqual(comment_count, 1) - class TestRequestThesisLink(TestCase): fixtures = ['groups', 'permissions'] @@ -186,7 +168,7 @@ class TestTheses(TestCase): response = self.client.get(self.target) search_results = response.context["search_results"] recent_theses = response.context["recent_theses"] - self.assertEqual(search_results.exists(), False) + self.assertEqual(search_results, []) self.assertEqual(recent_theses.exists(), True) def test_search_query_on_author(self): diff --git a/theses/views.py b/theses/views.py index b000a467910850a4be93dde39ab4db7acc7036d6..87d39a7f6d182336dc43c3e32c1de106acd1bdc7 100644 --- a/theses/views.py +++ b/theses/views.py @@ -131,48 +131,12 @@ def browse(request, discipline, nrweeksback): def thesis_detail(request, thesislink_id): thesislink = get_object_or_404(ThesisLink, pk=thesislink_id) - comments = thesislink.comment_set.all() - if request.method == 'POST': - form = CommentForm(request.POST) - if form.is_valid(): - author = Contributor.objects.get(user=request.user) - new_comment = Comment( - thesislink=thesislink, - author=author, - is_rem=form.cleaned_data['is_rem'], - is_que=form.cleaned_data['is_que'], - is_ans=form.cleaned_data['is_ans'], - is_obj=form.cleaned_data['is_obj'], - is_rep=form.cleaned_data['is_rep'], - is_val=form.cleaned_data['is_val'], - is_lit=form.cleaned_data['is_lit'], - is_sug=form.cleaned_data['is_sug'], - comment_text=form.cleaned_data['comment_text'], - remarks_for_editors=form.cleaned_data['remarks_for_editors'], - date_submitted=timezone.now(), - ) - new_comment.save() - author.nr_comments = Comment.objects.filter(author=author).count() - author.save() - context = { - 'ack_header': 'Thank you for contributing a Comment.', - 'ack_message': 'It will soon be vetted by an Editor.', - 'followup_message': 'Back to the ', - 'followup_link': reverse( - 'theses:thesis', - kwargs={'thesislink_id': new_comment.thesislink.id} - ), - 'followup_link_label': ' Thesis Link page you came from' - } - return render(request, 'scipost/acknowledgement.html', context) - else: - form = CommentForm() + form = CommentForm() + + comments = thesislink.comment_set + author_replies = comments.filter(is_author_reply=True) - try: - author_replies = Comment.objects.filter(thesislink=thesislink, is_author_reply=True) - except Comment.DoesNotExist: - author_replies = () context = {'thesislink': thesislink, - 'comments': comments.filter(status__gte=1).order_by('date_submitted'), + 'comments': comments.vetted().order_by('date_submitted'), 'author_replies': author_replies, 'form': form} return render(request, 'theses/thesis_detail.html', context)