SciPost Code Repository

Skip to content
Snippets Groups Projects
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
models.py 17.26 KiB
from django.utils import timezone
from django.db import models
from django.contrib.auth.models import User
from django.shortcuts import get_object_or_404
from django.template import Template, Context
from django.utils.safestring import mark_safe

from .models import *

from commentaries.models import Commentary
from scipost.models import TimeStampedModel, Contributor
from submissions.models import Submission, Report
from theses.models import ThesisLink

COMMENT_CATEGORIES = (
    ('ERR', 'erratum'),
    ('REM', 'remark'),
    ('QUE', 'question'),
    ('ANS', 'answer to question'),
    ('OBJ', 'objection'),
    ('REP', 'reply to objection'),
    ('VAL', 'validation or rederivation'),
    ('LIT', 'pointer to related literature'),
    ('SUG', 'suggestion for further work'),
    )

COMMENT_STATUS = (
    (1, 'vetted'),
    (0, 'not yet vetted (pending)'),
    (-1, 'rejected (unclear)'),
    (-2, 'rejected (incorrect)'),
    (-3, 'rejected (not useful)'),
)
comment_status_dict = dict(COMMENT_STATUS)


class Comment(TimeStampedModel):
    """ A Comment is an unsollicited note, submitted by a Contributor,
    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')
    # 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_report = models.ForeignKey(Report, blank=True, null=True, on_delete=models.CASCADE)
    author = models.ForeignKey(Contributor, default=1, on_delete=models.CASCADE)
    anonymous = models.BooleanField(default=False, verbose_name='Publish anonymously')
    # Categories:
    is_cor = models.BooleanField(default=False, verbose_name='correction/erratum')
    is_rem = models.BooleanField(default=False, verbose_name='remark')
    is_que = models.BooleanField(default=False, verbose_name='question')
    is_ans = models.BooleanField(default=False, verbose_name='answer to question')
    is_obj = models.BooleanField(default=False, verbose_name='objection')
    is_rep = models.BooleanField(default=False, verbose_name='reply to objection')
    is_val = models.BooleanField(default=False, verbose_name='validation or rederivation')
    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')
    date_submitted = models.DateTimeField('date submitted')
    # Opinions
    nr_A = models.PositiveIntegerField(default=0)
    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)
    nr_D = models.PositiveIntegerField(default=0)
    in_disagreement = models.ManyToManyField(Contributor,
                                             related_name='in_disagreement', blank=True)

    def __str__ (self):
        return ('by ' + self.author.user.first_name + ' ' + self.author.user.last_name +
                ' on ' + self.date_submitted.strftime('%Y-%m-%d') + ', '   + self.comment_text[:30])


    def update_opinions(self, contributor_id, opinion):
        contributor = get_object_or_404(Contributor, pk=contributor_id)
        self.in_agreement.remove(contributor)
        self.in_notsure.remove(contributor)
        self.in_disagreement.remove(contributor)
        if opinion == 'A':
            self.in_agreement.add(contributor)
        elif opinion == 'N':
            self.in_notsure.add(contributor)
        elif opinion == 'D':
            self.in_disagreement.add(contributor)
        self.nr_A = self.in_agreement.count()
        self.nr_N = self.in_notsure.count()
        self.nr_D = self.in_disagreement.count()
        self.save()


    def opinions_as_ul(self):
        template = Template('''
        <ul class="opinionsDisplay">
        <li style="background-color: #000099">Agree {{ nr_A }}</li>
        <li style="background-color: #555555">Not sure {{ nr_N }}</li>
        <li style="background-color: #990000">Disagree {{ nr_D }}</li>
        </ul>
        ''')
        context = Context ({'nr_A': self.nr_A, 'nr_N': self.nr_N, 'nr_D': self.nr_D})
        return template.render(context)


    def opinions_as_ul_tiny(self):
        template = Template('''
        <ul class="opinionsDisplay">
        <li style="background-color: #000099; font-size: 8px; padding: 2px;">Agree {{ nr_A }}</li>
        <li style="background-color: #555555; font-size: 8px; padding: 2px;">Not sure {{ nr_N }}</li>
        <li style="background-color: #990000; font-size: 8px; padding: 2px;">Disagree {{ nr_D }}</li>
        </ul>
        ''')
        context = Context ({'nr_A': self.nr_A, 'nr_N': self.nr_N, 'nr_D': self.nr_D})
        return template.render(context)


    def print_identifier (self):
        # for display
        output = '<div class="commentid">\n'
        output += '<h3><a id="comment_id{{ id }}"></a>'
        context = Context({'id': self.id})
        if self.is_author_reply:
            output += 'Author '
        if not self.anonymous:
            output += (' <a href="/contributor/{{ author_id }}">'
                       + '{{ first_name }} {{ last_name }}</a> on ')
            context['author_id'] = self.author.id
            context['first_name'] = self.author.user.first_name
            context['last_name'] = self.author.user.last_name
        output += '{{ date_comment_submitted }}'
        context['date_comment_submitted'] = self.date_submitted.strftime("%Y-%m-%d")
        if self.in_reply_to_comment:
            output += (' (in reply to <a href="#comment_id{{ in_reply_to_comment_id }}">'
                       '{{ in_reply_to_comment_first_name }} '
                       '{{ in_reply_to_comment_last_name }} on '
                       '{{ in_reply_to_comment_date }}</a>)')
            context['in_reply_to_comment_id'] = self.in_reply_to_comment_id
            context['in_reply_to_comment_first_name'] = (self.in_reply_to_comment
                                                         .author.user.first_name)
            context['in_reply_to_comment_last_name'] = (self.in_reply_to_comment
                                                        .author.user.last_name)
            context['in_reply_to_comment_date'] = (self.in_reply_to_comment
                                                   .date_submitted.strftime("%Y-%m-%d"))
        elif self.in_reply_to_report:
            output += ' (in reply to <a href="#report_id{{ in_reply_to_report_id }}">'
            context['in_reply_to_report_id'] = self.in_reply_to_report_id
            if not self.in_reply_to_report.anonymous:
                output += '{{ in_reply_to_report_first_name }} {{ in_reply_to_report_last_name}}'
                context['in_reply_to_report_first_name'] = (self.in_reply_to_report
                                                            .author.user.first_name)
                context['in_reply_to_report_last_name'] = (self.in_reply_to_report
                                                           .author.user.last_name)
            else:
                output += 'Report {{ in_reply_to_report_id }}'
                context['in_reply_to_report_id'] = self.in_reply_to_report_id
            output += ' on {{ date_report_submitted }}</a>)'
            context['date_report_submitted'] = self.in_reply_to_report.date_submitted.strftime("%Y-%m-%d")
        output += '</h3></div>'
        template = Template(output)
        return template.render(context)


    def print_identifier_for_vetting (self):
        # for display, same as print_identifier but named even if anonymous, not linked
        output = '<div class="commentid">\n'
        output += '<h3>'
        context = Context()
        if self.is_author_reply:
            output += 'Author '
        output += ' <a href="/contributor/{{ author_id }}">{{ first_name }} {{ last_name }}</a> on '
        context['author_id'] = self.author.id
        context['first_name'] = self.author.user.first_name
        context['last_name'] = self.author.user.last_name
        output += '{{ date_submitted }}'
        context['date_submitted'] = self.date_submitted.strftime("%Y-%m-%d")
        if self.in_reply_to_comment:
            output += (' (in reply to <a href="#comment_id{{ in_reply_to_comment_id }}">'
                       '{{ in_reply_to_comment_first_name }} {{ in_reply_to_comment_last_name }} '
                       'on {{ in_reply_to_comment_date }}</a>)')
            context['in_reply_to_comment_id'] = self.in_reply_to_comment_id
            context['in_reply_to_comment_first_name'] = (self.in_reply_to_comment
                                                         .author.user.first_name)
            context['in_reply_to_comment_last_name'] = (self.in_reply_to_comment
                                                        .author.user.last_name)
            context['in_reply_to_comment_date'] = (self.in_reply_to_comment
                                                   .date_submitted.strftime("%Y-%m-%d"))
        elif self.in_reply_to_report:
            output += ' (in reply to <a href="#report_id{{ in_reply_to_report_id }}">'
            context['in_reply_to_report_id'] = self.in_reply_to_report_id
            if not self.in_reply_to_report.anonymous:
                output += '{{ in_reply_to_report_first_name }} {{ in_reply_to_report_last_name}}'
                context['in_reply_to_report_first_name'] = (self.in_reply_to_report
                                                            .author.user.first_name)
                context['in_reply_to_report_last_name'] = (self.in_reply_to_report
                                                           .author.user.last_name)
            else:
                output += 'Report {{ in_reply_to_report_id }}'
                context['in_reply_to_report_id'] = self.in_reply_to_report_id
            output += '</a> on {{ date_submitted }})'
            context['date_submitted'] = self.in_reply_to_report.date_submitted.strftime("%Y-%m-%d")
        output += '</h3></div>'
        template = Template(output)
        return template.render(context)


    def header_as_li (self):
        # for search lists
        header = '<li>'
        #header += '<div class="flex-container"><div class="flex-whitebox0">'
        header += 'Nr {{ id }}'
        context = Context({'id': self.id})
        header += ', <div class="opinionsDisplay">' + self.opinions_as_ul_tiny() + '</div>'
        if self.status <= 0:
            header += (', status: <span style="color:red">'
                       + comment_status_dict[self.status] + '</span>')
        text_cut = self.comment_text[:50]
        if len(self.comment_text) > 50:
            text_cut += '...'
        context['id'] = self.id
        context['text_cut'] = text_cut
        context['date_submitted'] = self.date_submitted.strftime("%Y-%m-%d")
        header += ': '
        if not self.anonymous:
            header += (' <a href="/contributor/{{ author_id }}">'
                       '{{ first_name }} {{ last_name }}</a>, ')
            context['author_id'] = self.author.id
            context['first_name'] = self.author.user.first_name
            context['last_name'] = self.author.user.last_name
        if self.submission is not None:
            header += ('<a href="/submission/{{ arxiv_identifier_w_vn_nr }}#comment_id{{ id }}">'
                       ' \"{{ text_cut }}\"</a><p>submitted on {{ date_submitted }}')
            header += (' in submission on <a href="/submission/{{ arxiv_identifier_w_vn_nr }}"'
                       ' class="pubtitleli">{{ submission_title }}</a> by '
                       '{{ submission_author_list }}</p>')
            context['arxiv_identifier_w_vn_nr'] = self.submission.arxiv_identifier_w_vn_nr
            context['submission_title'] = self.submission.title
            context['submission_author_list'] = self.submission.author_list
        if self.commentary is not None:
            header += ('<a href="/commentary/{{ commentary_url }}#comment_id{{ id }}">'
                       ' \"{{ text_cut }}\"</a><p>submitted on {{ date_submitted }}')
            header += (' in commentary on <a href="/commentary/{{ commentary_url }}"'
                       ' class="pubtitleli">'
                       '{{ commentary_pub_title }}</a> by {{ commentary_author_list }}</p>')
            context['commentary_url'] = self.commentary.arxiv_or_DOI_string
            context['commentary_pub_title'] = self.commentary.pub_title
            context['commentary_author_list'] = self.commentary.author_list
        if self.thesislink is not None:
            header += ('<a href="/thesis/{{ thesislink_id }}#comment_id{{ id }}">'
                       ' \"{{ text_cut }}\"</a><p>submitted on {{ date_submitted }}')
            header += (' in thesislink on <a href="/thesis/{{ thesislink_id }}" class="pubtitleli">'
                       '{{ thesislink_title }}</a> by {{ thesislink_author }}</p>')
            context['thesislink_id'] = self.thesislink.id
            context['thesislink_title'] = self.thesislink.title
            context['thesislink_author'] = self.thesislink.author
        #header += '</div></div>'
        header += '</li>'
        template = Template(header)
        return template.render(context)


    def simple_header_as_li (self):
        # for Lists
        header = '<li>'
        #header += '<div class="flex-container"><div class="flex-whitebox0">'
        context = Context({})
        text_cut = self.comment_text[:30]
        if len(self.comment_text) > 30:
            text_cut += '...'
        context['text_cut'] = text_cut
        if not self.anonymous:
            header += ' <a href="/contributor/{{ author_id }}">{{ first_name }} {{ last_name }}</a>, '
            context['author_id'] = self.author.id
            context['first_name'] = self.author.user.first_name
            context['last_name'] = self.author.user.last_name
        if self.submission is not None:
            header += ('<a href="/submission/{{ arxiv_identifier_w_vn_nr }}#comment_id{{ id }}"> '
                       '\"{{ text_cut }}\"</a>'
                       ' in submission on <a href="/submission/{{ arxiv_identifier_w_vn_nr }}" class="pubtitleli">'
                       '{{ submission_title }}</a> by {{ submission_author_list }}</p>')
            context['arxiv_identifier_w_vn_nr'] = self.submission.arxiv_identifier_w_vn_nr
            context['submission_title'] = self.submission.title
            context['submission_author_list'] = self.submission.author_list
        if self.commentary is not None:
            header += ('<a href="/commentary/{{ commentary_url }}#comment_id{{ id }}"> '
                       '\"{{ text_cut }}\"</a>'
                       ' in commentary on <a href="/commentary/{{ commentary_url }}" class="pubtitleli">'
                       '{{ commentary_pub_title }}</a> by {{ commentary_author_list }}</p>')
            context['commentary_url'] = self.commentary.arxiv_or_DOI_string
            context['commentary_pub_title'] = self.commentary.pub_title
            context['commentary_author_list'] = self.commentary.author_list
        if self.thesislink is not None:
            header += '<a href="/thesis/{{ thesislink_id }}#comment_id{{ id }}"> \"{{ text_cut }}\"</a>'
            header += (' in thesislink on <a href="/thesis/{{ thesislink_id }}" class="pubtitleli">' +
                       '{{ thesislink_title }}</a> by {{ thesislink_author }}</p>')
            context['thesislink_id'] = self.thesislink.id
            context['thesislink_title'] = self.thesislink.title
            context['thesislink_author'] = self.thesislink.author
        #header += '</div></div>'
        header += '</li>'
        template = Template(header)
        return template.render(context)


    def categories_as_ul(self):
        output = '<div class="commentcategorydisplay"><h4>Category:</h4><ul>'
        if self.is_rem:
            output += '<li>remark</li>'
        if self.is_que:
            output += '<li>question</li>'
        if self.is_ans:
            output += '<li>answer to question</li>'
        if self.is_obj:
            output += '<li>objection</li>'
        if self.is_rep:
            output += '<li>reply to objection</li>'
        if self.is_cor:
            output += '<li>correction</li>'
        if self.is_val:
            output += '<li>validation or rederivation</li>'
        if self.is_lit:
            output += '<li>pointer to related literature</li>'
        if self.is_sug:
            output += '<li>suggestion for further work</li>'
        output += '</ul></div>'
        return mark_safe(output)