diff --git a/commentaries/forms.py b/commentaries/forms.py index fc65f77015fcbae50435bb230d9e1366cd75ae5d..c1626ab06f3d05be4a47a7401dfebaa765a2ca24 100644 --- a/commentaries/forms.py +++ b/commentaries/forms.py @@ -36,3 +36,4 @@ class CommentarySearchForm(forms.Form): pub_author = forms.CharField(max_length=100, required=False, label="Author(s)") pub_title_keyword = forms.CharField(max_length=100, label="Title", required=False) pub_abstract_keyword = forms.CharField(max_length=1000, required=False, label="Abstract") + diff --git a/commentaries/templates/commentaries/commentary_detail.html b/commentaries/templates/commentaries/commentary_detail.html index f4af2c987b372f976b6a4ba00575c1695bd2e25f..45376a36e11dcfe21ea0f28d2e58db3374e98a7e 100644 --- a/commentaries/templates/commentaries/commentary_detail.html +++ b/commentaries/templates/commentaries/commentary_detail.html @@ -79,6 +79,17 @@ {% if comment.is_sug %}<li>suggestion for further work</li>{% endif %} </ul> </div> + <br/> + <div class="opinionsDisplay"> + {% if user.is_authenticated and user.contributor.rank > 0 %} + <form action="{% url 'comments:express_opinion' comment.id %}" method="post"> + {% csrf_token %} + {{ opinion_form }} + <input type="submit" value="Submit"/> + </form> + {% endif %} + {{ comment.opinions_as_ul|safe }} + </div> </div> </div> diff --git a/commentaries/views.py b/commentaries/views.py index 5c7c913cc38ee9c3249f5f052944865e3fb1dc36..518c7f5c75b00d25958bfecc5e70c92909e9a5d3 100644 --- a/commentaries/views.py +++ b/commentaries/views.py @@ -14,7 +14,8 @@ from .forms import * from comments.models import Comment, AuthorReply from comments.forms import CommentForm -from scipost.forms import TITLE_CHOICES, AuthenticationForm +from scipost.forms import TITLE_CHOICES, AuthenticationForm, OpinionForm + title_dict = dict(TITLE_CHOICES) # Convert titles for use in emails @@ -179,5 +180,6 @@ def commentary_detail(request, commentary_id): author_replies = AuthorReply.objects.filter(commentary=commentary) except AuthorReply.DoesNotExist: author_replies = () - context = {'commentary': commentary, 'comments': comments.filter(status__gte=1).order_by('date_submitted'), 'author_replies': author_replies, 'form': form} + opinion_form = OpinionForm() + context = {'commentary': commentary, 'comments': comments.filter(status__gte=1).order_by('date_submitted'), 'author_replies': author_replies, 'form': form, 'opinion_form': opinion_form} return render(request, 'commentaries/commentary_detail.html', context) diff --git a/comments/models.py b/comments/models.py index 39e44a3ac0c1b0ba57a72f18c9891284aab99712..74a89b0071fa138a75668f0906a9bdeb9a24b800 100644 --- a/comments/models.py +++ b/comments/models.py @@ -11,7 +11,7 @@ from .models import * #from submissions.models import * from commentaries.models import Commentary -from scipost.models import Contributor +from scipost.models import Contributor, Opinion from submissions.models import Submission, Report from theses.models import ThesisLink @@ -62,11 +62,32 @@ class Comment(models.Model): comment_text = models.TextField() remarks_for_editors = models.TextField(default='', blank=True, verbose_name='optional remarks for the Editors only') date_submitted = models.DateTimeField('date submitted') - + # Opinions + nr_FA = models.PositiveIntegerField(default=0) + nr_MA = models.PositiveIntegerField(default=0) + nr_DIS = models.PositiveIntegerField(default=0) + nr_OBJ = models.PositiveIntegerField(default=0) def __str__ (self): return self.comment_text + def recalculate_nr_opinions(self): + self.nr_FA = Opinion.objects.filter(comment=self, opinion='FA').count() + self.nr_MA = Opinion.objects.filter(comment=self, opinion='MA').count() + self.nr_DIS = Opinion.objects.filter(comment=self, opinion='DIS').count() + self.nr_OBJ = Opinion.objects.filter(comment=self, opinion='OBJ').count() + self.save() + + def opinions_as_ul(self): + output = '<div class="opinionsDisplay"><ul>' + output += '<li>Fully agree: ' + str(self.nr_FA) + '</li>' + output += '<li>Mostly agree: ' + str(self.nr_MA) + '</li>' + output += '<li>Disagree: ' + str(self.nr_DIS) + '</li>' + output += '<li>Object: ' + str(self.nr_OBJ) + '</li>' + output += '</ul></div>' + return output + + def print_identifier (self): output = '<div class="commentid">\n' output += '<h3><a id="comment_id' + str(self.id) + '">' + str(self.id) + '</a>' @@ -96,7 +117,7 @@ class Comment(models.Model): header += ' in commentary on <a href="/commentaries/commentary/' + str(self.commentary.id) + '" class="pubtitleli">' + self.commentary.pub_title + '</a> by ' + self.commentary.author_list + '</p></div>' if self.thesislink is not None: header += '<a href="/theses/thesis/' + str(self.thesislink.id) + '#comment_id' + str(self.id) + '"> \"' + text_cut + '\"</a><p>submitted on ' + self.date_submitted.strftime("%Y-%m-%d") - header += ' in thesislink on <a href="/theses/thesis/' + str(self.thesislink.id) + '" class="pubtitleli">' + self.thesislink.pub_title + '</a> by ' + self.thesislink.author_list + '</p></div>' + header += ' in thesislink on <a href="/theses/thesis/' + str(self.thesislink.id) + '" class="pubtitleli">' + self.thesislink.title + '</a> by ' + self.thesislink.author + '</p></div>' header += '</div></li>' return header diff --git a/comments/urls.py b/comments/urls.py index 9312a6e2f14f955aa17b8978285b8209028acf1f..68a74fcbfa7fea3b8b3c23bdfe1255e3138091fe 100644 --- a/comments/urls.py +++ b/comments/urls.py @@ -13,4 +13,5 @@ urlpatterns = [ url(r'^author_reply_to_report/(?P<report_id>[0-9]+)$', views.author_reply_to_report, name='author_reply_to_report'), url(r'^vet_author_replies$', views.vet_author_replies, name='vet_author_replies'), url(r'^vet_author_reply_ack/(?P<reply_id>[0-9]+)$', views.vet_author_reply_ack, name='vet_author_reply_ack'), + url(r'^express_opinion/(?P<comment_id>[0-9]+)$', views.express_opinion, name='express_opinion'), ] diff --git a/comments/views.py b/comments/views.py index cbd16f44a49c25b879ab6fef72ffbcf90d1b4483..c4b43b2b635f0f7b88517cb8feed5068908f388a 100644 --- a/comments/views.py +++ b/comments/views.py @@ -12,7 +12,8 @@ from django.db.models import Avg from .models import * from .forms import * -from scipost.models import title_dict +from scipost.models import title_dict, Opinion +from scipost.forms import OpinionForm def vet_submitted_comments(request): @@ -190,3 +191,24 @@ def vet_author_reply_ack(request, reply_id): return render(request, 'comments/vet_author_reply_ack.html', context) +def express_opinion(request, comment_id): + # A contributor has expressed an opinion on a comment + contributor = request.user.contributor + comment = get_object_or_404(Comment, pk=comment_id) + if request.method == 'POST': + opinion_form = OpinionForm(request.POST) + if opinion_form.is_valid(): + # delete any previous opinion on this by this contributor + Opinion.objects.filter(rater=contributor, comment=comment).delete() + newopinion = Opinion(rater=request.user.contributor, comment=comment, opinion=opinion_form.cleaned_data['opinion']) + newopinion.save() + comment.recalculate_nr_opinions() + if comment.submission is not None: + return HttpResponseRedirect('/submissions/submission/' + str(comment.submission.id) + '/#comment_id' + str(comment.id)) + if comment.commentary is not None: + return HttpResponseRedirect('/commentaries/commentary/' + str(comment.commentary.id) + '/#comment_id' + str(comment.id)) + if comment.thesislink is not None: + return HttpResponseRedirect('/theses/thesis/' + str(comment.thesislink.id) + '/#comment_id' + str(comment.id)) + else: + # will never call this + return(render(request, 'scipost/index.html')) diff --git a/scipost/admin.py b/scipost/admin.py index db488d7cafea8ca1de0456e4d6d6e3253ba66ec1..e81d84d5fe4ba3fa9ea2d77a27dd20e1a881f3d6 100644 --- a/scipost/admin.py +++ b/scipost/admin.py @@ -3,7 +3,7 @@ from django.contrib import admin from django.contrib.auth.admin import UserAdmin from django.contrib.auth.models import User -from scipost.models import Contributor +from scipost.models import Contributor, Opinion class ContributorInline(admin.StackedInline): #class ContributorInline(admin.TabularInline): @@ -18,3 +18,5 @@ admin.site.unregister(User) admin.site.register(User, UserAdmin) #admin.site.register(Contributor) + +admin.site.register(Opinion) diff --git a/scipost/forms.py b/scipost/forms.py index 7381e0fb2b5833ad142910dae3be8a24ddd96472..fb5126aa27592b0c9d126cb52afe1e33d5ea727d 100644 --- a/scipost/forms.py +++ b/scipost/forms.py @@ -61,6 +61,10 @@ class PasswordChangeForm(forms.Form): password_verif = forms.CharField(label='Reenter new password', widget=forms.PasswordInput()) +class OpinionForm(forms.Form): + opinion = forms.ChoiceField(choices=OPINION_CHOICES, label='Your opinion on this Comment: ') + + class AssessmentForm(forms.ModelForm): class Meta: model = Assessment diff --git a/scipost/models.py b/scipost/models.py index 2d50923dd7ba6d2656086ccf921754d630ac932e..9b0a0dbe1daed821c384bffd55ec902b4f0d0bf9 100644 --- a/scipost/models.py +++ b/scipost/models.py @@ -112,6 +112,24 @@ class Assessment(models.Model): significance = models.PositiveSmallIntegerField(choices=ASSESSMENT_CHOICES, default=101) + +### Opinions + +OPINION_CHOICES = ( + ('ABS', '-'), + ('FA', 'I fully agree'), + ('MA', 'I mostly agree'), + ('DIS', 'I disagree'), + ('OBJ', 'I object to this'), +) +opinion_choices_dict = dict(OPINION_CHOICES) + +class Opinion(models.Model): + rater = models.ForeignKey(Contributor) + comment = models.ForeignKey('comments.Comment') + opinion = models.CharField(max_length=3, choices=OPINION_CHOICES, default='ABS') + + ### AssessmentAggregates class AssessmentAggregate(models.Model): diff --git a/scipost/static/scipost/SciPost.css b/scipost/static/scipost/SciPost.css index a797ca6c69e8d99556da3870a11e65795292d474..c0eefa2800334277bd2e9cbcb3d4f9ecb538c129 100644 --- a/scipost/static/scipost/SciPost.css +++ b/scipost/static/scipost/SciPost.css @@ -469,6 +469,30 @@ section form.ratingsdata ul li label { color: #ffffff; } +.opinionsDisplay { + margin: 0px 4px; + padding: 1px; + display: inline-block; + box-shadow: 1px 1px 3px #888888; + background: linear-gradient(to right,#fcfcfc, #f0f0f0); + font-size: 90%; +} +.opinionsDisplay form { + display: inline-block; +} +.opinionsDisplay ul { + border-radius: 2px; + color: #ffffff; + display: inline-block; + margin: 0px; + padding: 2px; +} +.opinionsDisplay li { + display: inline-block; + background-color: #204080; + margin: 1px 3px; + padding: 2px 4px; +} article { background-color:#eeeeee; diff --git a/submissions/templates/submissions/submission_detail.html b/submissions/templates/submissions/submission_detail.html index 0ec0f44eb568059cb8b305fb06649a3b36372444..3e0207afce63e1570f36fd802816314dc6e2aecb 100644 --- a/submissions/templates/submissions/submission_detail.html +++ b/submissions/templates/submissions/submission_detail.html @@ -168,6 +168,17 @@ {% if comment.is_sug %}<li>suggestion for further work</li>{% endif %} </ul> </div> + <br/> + <div class="opinionsDisplay"> + {% if user.is_authenticated and user.contributor.rank > 0 %} + <form action="{% url 'comments:express_opinion' comment.id %}" method="post"> + {% csrf_token %} + {{ opinion_form }} + <input type="submit" value="Submit"/> + </form> + {% endif %} + {{ comment.opinions_as_ul|safe }} + </div> </div> </div> diff --git a/submissions/views.py b/submissions/views.py index a518a5a2e3f40e8c22d3e831ce3851e0a45b035b..01f6b949f3f674df81031c128b61c800db4bf505 100644 --- a/submissions/views.py +++ b/submissions/views.py @@ -14,6 +14,7 @@ from .forms import * from comments.models import Comment, AuthorReply from scipost.models import Contributor, title_dict +from scipost.forms import OpinionForm from submissions.models import Submission from comments.forms import CommentForm @@ -153,7 +154,8 @@ def submission_detail(request, submission_id): author_replies = AuthorReply.objects.filter(submission=submission) except AuthorReply.DoesNotExist: author_replies = () - context = {'submission': submission, 'comments': comments.filter(status__gte=1).order_by('date_submitted'), 'reports': reports.filter(status__gte=1), 'author_replies': author_replies, 'form': form} + opinion_form = OpinionForm() + context = {'submission': submission, 'comments': comments.filter(status__gte=1).order_by('date_submitted'), 'reports': reports.filter(status__gte=1), 'author_replies': author_replies, 'form': form, 'opinion_form': opinion_form} return render(request, 'submissions/submission_detail.html', context) diff --git a/theses/templates/theses/thesis_detail.html b/theses/templates/theses/thesis_detail.html index 6b98eed7a48b9a6981087016c8efd4d6e2e83b0b..1f34666d714e9dea79636e4709cae428d3c17115 100644 --- a/theses/templates/theses/thesis_detail.html +++ b/theses/templates/theses/thesis_detail.html @@ -70,6 +70,17 @@ {% if comment.is_sug %}<li>suggestion for further work</li>{% endif %} </ul> </div> + <br/> + <div class="opinionsDisplay"> + {% if user.is_authenticated and user.contributor.rank > 0 %} + <form action="{% url 'comments:express_opinion' comment.id %}" method="post"> + {% csrf_token %} + {{ opinion_form }} + <input type="submit" value="Submit"/> + </form> + {% endif %} + {{ comment.opinions_as_ul|safe }} + </div> </div> </div> diff --git a/theses/views.py b/theses/views.py index 975422ebe44d1c3c37b68037407d683ae1292591..811a0766fb4fc4ced8f13aa7e0644fafe4405d83 100644 --- a/theses/views.py +++ b/theses/views.py @@ -14,7 +14,7 @@ from .forms import * from comments.models import Comment, AuthorReply from comments.forms import CommentForm -from scipost.forms import TITLE_CHOICES, AuthenticationForm +from scipost.forms import TITLE_CHOICES, AuthenticationForm, OpinionForm title_dict = dict(TITLE_CHOICES) # Convert titles for use in emails @@ -179,5 +179,6 @@ def thesis_detail(request, thesislink_id): author_replies = AuthorReply.objects.filter(thesislink=thesislink) except AuthorReply.DoesNotExist: author_replies = () - context = {'thesislink': thesislink, 'comments': comments.filter(status__gte=1).order_by('date_submitted'), 'author_replies': author_replies, 'form': form} + opinion_form = OpinionForm() + context = {'thesislink': thesislink, 'comments': comments.filter(status__gte=1).order_by('date_submitted'), 'author_replies': author_replies, 'form': form, 'opinion_form': opinion_form} return render(request, 'theses/thesis_detail.html', context)