From 8ba914e628869a9ac8a2f25fa522c875e5fc8e50 Mon Sep 17 00:00:00 2001
From: "J.-S. Caux" <J.S.Caux@uva.nl>
Date: Fri, 18 Mar 2016 05:23:27 +0100
Subject: [PATCH] Try to introduce better implementation of ratings

---
 commentaries/migrations/0001_initial.py       | 17 ++--
 commentaries/models.py                        |  2 +
 .../commentaries/commentary_detail.html       |  6 ++
 commentaries/views.py                         |  5 +-
 comments/forms.py                             |  2 +
 comments/migrations/0001_initial.py           | 54 +++----------
 comments/models.py                            |  2 +
 ratings/migrations/0001_initial.py            | 81 +++++++++----------
 scipost/forms.py                              |  5 ++
 scipost/models.py                             | 52 ++++++++++++
 scipost/static/scipost/SciPost.css            | 30 +++++++
 submissions/migrations/0001_initial.py        | 24 +++---
 .../submissions/submission_detail.html        |  2 +-
 13 files changed, 172 insertions(+), 110 deletions(-)

diff --git a/commentaries/migrations/0001_initial.py b/commentaries/migrations/0001_initial.py
index f021672de..238823554 100644
--- a/commentaries/migrations/0001_initial.py
+++ b/commentaries/migrations/0001_initial.py
@@ -1,9 +1,8 @@
 # -*- coding: utf-8 -*-
-# Generated by Django 1.9.1 on 2016-02-26 05:37
+# Generated by Django 1.9.1 on 2016-03-17 19:13
 from __future__ import unicode_literals
 
 from django.db import migrations, models
-import django.db.models.deletion
 import django.utils.timezone
 
 
@@ -12,7 +11,6 @@ class Migration(migrations.Migration):
     initial = True
 
     dependencies = [
-        ('scipost', '0001_initial'),
     ]
 
     operations = [
@@ -33,19 +31,16 @@ class Migration(migrations.Migration):
                 ('pub_date', models.DateField(verbose_name='date of original publication')),
                 ('pub_abstract', models.TextField(verbose_name='abstract')),
                 ('nr_clarity_ratings', models.IntegerField(default=0)),
-                ('clarity_rating', models.DecimalField(decimal_places=0, default=0, max_digits=3, null=True)),
+                ('clarity_rating', models.DecimalField(decimal_places=0, default=101, max_digits=3, null=True)),
                 ('nr_validity_ratings', models.IntegerField(default=0)),
-                ('validity_rating', models.DecimalField(decimal_places=0, default=0, max_digits=3, null=True)),
+                ('validity_rating', models.DecimalField(decimal_places=0, default=101, max_digits=3, null=True)),
                 ('nr_rigour_ratings', models.IntegerField(default=0)),
-                ('rigour_rating', models.DecimalField(decimal_places=0, default=0, max_digits=3, null=True)),
+                ('rigour_rating', models.DecimalField(decimal_places=0, default=101, max_digits=3, null=True)),
                 ('nr_originality_ratings', models.IntegerField(default=0)),
-                ('originality_rating', models.DecimalField(decimal_places=0, default=0, max_digits=3, null=True)),
+                ('originality_rating', models.DecimalField(decimal_places=0, default=101, max_digits=3, null=True)),
                 ('nr_significance_ratings', models.IntegerField(default=0)),
-                ('significance_rating', models.DecimalField(decimal_places=0, default=0, max_digits=3, null=True)),
+                ('significance_rating', models.DecimalField(decimal_places=0, default=101, max_digits=3, null=True)),
                 ('latest_activity', models.DateTimeField(default=django.utils.timezone.now)),
-                ('authors', models.ManyToManyField(blank=True, related_name='authors_com', to='scipost.Contributor')),
-                ('requested_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='requested_by', to='scipost.Contributor')),
-                ('vetted_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='scipost.Contributor')),
             ],
         ),
     ]
diff --git a/commentaries/models.py b/commentaries/models.py
index 77db82abc..b90d71eab 100644
--- a/commentaries/models.py
+++ b/commentaries/models.py
@@ -42,6 +42,8 @@ class Commentary(models.Model):
     nr_significance_ratings = models.IntegerField(default=0)
     significance_rating = models.DecimalField(default=101, max_digits=3, decimal_places=0, null=True)
 
+    rating_agg = models.OneToOneField(RatingAggregate, null=True)
+
     latest_activity = models.DateTimeField(default=timezone.now)
 
     def __str__ (self):
diff --git a/commentaries/templates/commentaries/commentary_detail.html b/commentaries/templates/commentaries/commentary_detail.html
index b4d21d6a2..3d48fc234 100644
--- a/commentaries/templates/commentaries/commentary_detail.html
+++ b/commentaries/templates/commentaries/commentary_detail.html
@@ -253,6 +253,12 @@
     {% csrf_token %}
     {% load crispy_forms_tags %}
     {% crispy form %}
+    <div class="ratingsform">
+      <ul>
+	<li>Rate this publication:</li>
+	{{ commentary_rating_form_new.as_ul }}
+      </ul>
+    </div>
   </form>
 </section>
 {% endif %}
diff --git a/commentaries/views.py b/commentaries/views.py
index 007e73c78..549af7030 100644
--- a/commentaries/views.py
+++ b/commentaries/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, RatingForm
 from ratings.forms import CommentRatingForm, AuthorReplyRatingForm, CommentaryRatingForm
 
 title_dict = dict(TITLE_CHOICES) # Convert titles for use in emails
@@ -177,9 +177,10 @@ def commentary_detail(request, commentary_id):
     comment_rating_form = CommentRatingForm()
     authorreply_rating_form = AuthorReplyRatingForm()
     commentary_rating_form = CommentaryRatingForm()
+    commentary_rating_form_new = RatingForm()
     try:
         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, 'commentary_rating_form': commentary_rating_form, 'comment_rating_form': comment_rating_form, 'authorreply_rating_form': authorreply_rating_form }
+    context = {'commentary': commentary, 'comments': comments.filter(status__gte=1).order_by('date_submitted'), 'author_replies': author_replies, 'form': form, 'commentary_rating_form': commentary_rating_form, 'commentary_rating_form_new': commentary_rating_form_new, 'comment_rating_form': comment_rating_form, 'authorreply_rating_form': authorreply_rating_form }
     return render(request, 'commentaries/commentary_detail.html', context)
diff --git a/comments/forms.py b/comments/forms.py
index 98a1ddf85..1d98b59e8 100644
--- a/comments/forms.py
+++ b/comments/forms.py
@@ -2,6 +2,8 @@ from django import *
 
 from .models import *
 
+from scipost.forms import RatingForm
+
 from crispy_forms.helper import FormHelper
 from crispy_forms.layout import Layout, Div, Field, Fieldset, HTML, Submit
 
diff --git a/comments/migrations/0001_initial.py b/comments/migrations/0001_initial.py
index 1906acc99..e8837249c 100644
--- a/comments/migrations/0001_initial.py
+++ b/comments/migrations/0001_initial.py
@@ -1,9 +1,8 @@
 # -*- coding: utf-8 -*-
-# Generated by Django 1.9.1 on 2016-02-26 05:37
+# Generated by Django 1.9.1 on 2016-03-17 19:13
 from __future__ import unicode_literals
 
 from django.db import migrations, models
-import django.db.models.deletion
 
 
 class Migration(migrations.Migration):
@@ -11,10 +10,6 @@ class Migration(migrations.Migration):
     initial = True
 
     dependencies = [
-        ('scipost', '0001_initial'),
-        ('commentaries', '0001_initial'),
-        ('submissions', '0001_initial'),
-        ('theses', '0001_initial'),
     ]
 
     operations = [
@@ -26,17 +21,15 @@ class Migration(migrations.Migration):
                 ('reply_text', models.TextField(verbose_name='')),
                 ('date_submitted', models.DateTimeField(verbose_name='date submitted')),
                 ('nr_relevance_ratings', models.IntegerField(default=0)),
-                ('relevance_rating', models.DecimalField(decimal_places=0, default=0, max_digits=3, null=True)),
+                ('relevance_rating', models.DecimalField(decimal_places=0, default=101, max_digits=3, null=True)),
                 ('nr_importance_ratings', models.IntegerField(default=0)),
-                ('importance_rating', models.DecimalField(decimal_places=0, default=0, max_digits=3, null=True)),
+                ('importance_rating', models.DecimalField(decimal_places=0, default=101, max_digits=3, null=True)),
                 ('nr_clarity_ratings', models.IntegerField(default=0)),
-                ('clarity_rating', models.DecimalField(decimal_places=0, default=0, max_digits=3, null=True)),
+                ('clarity_rating', models.DecimalField(decimal_places=0, default=101, max_digits=3, null=True)),
                 ('nr_validity_ratings', models.IntegerField(default=0)),
-                ('validity_rating', models.DecimalField(decimal_places=0, default=0, max_digits=3, null=True)),
+                ('validity_rating', models.DecimalField(decimal_places=0, default=101, max_digits=3, null=True)),
                 ('nr_rigour_ratings', models.IntegerField(default=0)),
-                ('rigour_rating', models.DecimalField(decimal_places=0, default=0, max_digits=3, null=True)),
-                ('author', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='scipost.Contributor')),
-                ('commentary', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='commentaries.Commentary')),
+                ('rigour_rating', models.DecimalField(decimal_places=0, default=101, max_digits=3, null=True)),
             ],
         ),
         migrations.CreateModel(
@@ -57,40 +50,15 @@ class Migration(migrations.Migration):
                 ('remarks_for_editors', models.TextField(blank=True, default='', verbose_name='optional remarks for the Editors only')),
                 ('date_submitted', models.DateTimeField(verbose_name='date submitted')),
                 ('nr_relevance_ratings', models.IntegerField(default=0)),
-                ('relevance_rating', models.DecimalField(decimal_places=0, default=0, max_digits=3, null=True)),
+                ('relevance_rating', models.DecimalField(decimal_places=0, default=101, max_digits=3, null=True)),
                 ('nr_importance_ratings', models.IntegerField(default=0)),
-                ('importance_rating', models.DecimalField(decimal_places=0, default=0, max_digits=3, null=True)),
+                ('importance_rating', models.DecimalField(decimal_places=0, default=101, max_digits=3, null=True)),
                 ('nr_clarity_ratings', models.IntegerField(default=0)),
-                ('clarity_rating', models.DecimalField(decimal_places=0, default=0, max_digits=3, null=True)),
+                ('clarity_rating', models.DecimalField(decimal_places=0, default=101, max_digits=3, null=True)),
                 ('nr_validity_ratings', models.IntegerField(default=0)),
-                ('validity_rating', models.DecimalField(decimal_places=0, default=0, max_digits=3, null=True)),
+                ('validity_rating', models.DecimalField(decimal_places=0, default=101, max_digits=3, null=True)),
                 ('nr_rigour_ratings', models.IntegerField(default=0)),
-                ('rigour_rating', models.DecimalField(decimal_places=0, default=0, max_digits=3, null=True)),
-                ('author', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='scipost.Contributor')),
-                ('commentary', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='commentaries.Commentary')),
-                ('in_reply_to', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='comments.Comment')),
-                ('submission', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='submissions.Submission')),
-                ('thesislink', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='theses.ThesisLink')),
+                ('rigour_rating', models.DecimalField(decimal_places=0, default=101, max_digits=3, null=True)),
             ],
         ),
-        migrations.AddField(
-            model_name='authorreply',
-            name='in_reply_to_comment',
-            field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='comments.Comment'),
-        ),
-        migrations.AddField(
-            model_name='authorreply',
-            name='in_reply_to_report',
-            field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='submissions.Report'),
-        ),
-        migrations.AddField(
-            model_name='authorreply',
-            name='submission',
-            field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='submissions.Submission'),
-        ),
-        migrations.AddField(
-            model_name='authorreply',
-            name='thesislink',
-            field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='theses.ThesisLink'),
-        ),
     ]
diff --git a/comments/models.py b/comments/models.py
index fc4679cce..0ebd5de89 100644
--- a/comments/models.py
+++ b/comments/models.py
@@ -53,6 +53,8 @@ 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')
+
+    
     # Aggregates of ratings applied to this comment:
     nr_relevance_ratings = models.IntegerField(default=0)
     relevance_rating = models.DecimalField(default=101, max_digits=3, decimal_places=0, null=True)
diff --git a/ratings/migrations/0001_initial.py b/ratings/migrations/0001_initial.py
index 0b66dd9f3..16822e84e 100644
--- a/ratings/migrations/0001_initial.py
+++ b/ratings/migrations/0001_initial.py
@@ -1,9 +1,8 @@
 # -*- coding: utf-8 -*-
-# Generated by Django 1.9.1 on 2016-02-26 05:37
+# Generated by Django 1.9.1 on 2016-03-17 19:13
 from __future__ import unicode_literals
 
 from django.db import migrations, models
-import django.db.models.deletion
 
 
 class Migration(migrations.Migration):
@@ -11,10 +10,6 @@ class Migration(migrations.Migration):
     initial = True
 
     dependencies = [
-        ('scipost', '0001_initial'),
-        ('comments', '0001_initial'),
-        ('commentaries', '0001_initial'),
-        ('submissions', '0001_initial'),
     ]
 
     operations = [
@@ -22,13 +17,11 @@ class Migration(migrations.Migration):
             name='AuthorReplyRating',
             fields=[
                 ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
-                ('relevance', models.PositiveSmallIntegerField(default=0, null=True, verbose_name=((101, '-'), (100, 'top'), (80, 'high'), (60, 'good'), (40, 'ok'), (20, 'low'), (0, 'poor')))),
-                ('importance', models.PositiveSmallIntegerField(default=0, null=True, verbose_name=((101, '-'), (100, 'top'), (80, 'high'), (60, 'good'), (40, 'ok'), (20, 'low'), (0, 'poor')))),
-                ('clarity', models.PositiveSmallIntegerField(default=0, null=True, verbose_name=((101, '-'), (100, 'top'), (80, 'high'), (60, 'good'), (40, 'ok'), (20, 'low'), (0, 'poor')))),
-                ('validity', models.PositiveSmallIntegerField(default=0, null=True, verbose_name=((101, '-'), (100, 'top'), (80, 'high'), (60, 'good'), (40, 'ok'), (20, 'low'), (0, 'poor')))),
-                ('rigour', models.PositiveSmallIntegerField(default=0, null=True, verbose_name=((101, '-'), (100, 'top'), (80, 'high'), (60, 'good'), (40, 'ok'), (20, 'low'), (0, 'poor')))),
-                ('authorreply', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='comments.AuthorReply')),
-                ('rater', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='scipost.Contributor')),
+                ('relevance', models.PositiveSmallIntegerField(choices=[(101, '-'), (100, 'top'), (80, 'high'), (60, 'good'), (40, 'ok'), (20, 'low'), (0, 'poor')], default=101)),
+                ('importance', models.PositiveSmallIntegerField(choices=[(101, '-'), (100, 'top'), (80, 'high'), (60, 'good'), (40, 'ok'), (20, 'low'), (0, 'poor')], default=101)),
+                ('clarity', models.PositiveSmallIntegerField(choices=[(101, '-'), (100, 'top'), (80, 'high'), (60, 'good'), (40, 'ok'), (20, 'low'), (0, 'poor')], default=101)),
+                ('validity', models.PositiveSmallIntegerField(choices=[(101, '-'), (100, 'top'), (80, 'high'), (60, 'good'), (40, 'ok'), (20, 'low'), (0, 'poor')], default=101)),
+                ('rigour', models.PositiveSmallIntegerField(choices=[(101, '-'), (100, 'top'), (80, 'high'), (60, 'good'), (40, 'ok'), (20, 'low'), (0, 'poor')], default=101)),
             ],
             options={
                 'abstract': False,
@@ -38,13 +31,11 @@ class Migration(migrations.Migration):
             name='CommentaryRating',
             fields=[
                 ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
-                ('clarity', models.PositiveSmallIntegerField(default=0, null=True, verbose_name=((101, '-'), (100, 'top'), (80, 'high'), (60, 'good'), (40, 'ok'), (20, 'low'), (0, 'poor')))),
-                ('validity', models.PositiveSmallIntegerField(default=0, null=True, verbose_name=((101, '-'), (100, 'top'), (80, 'high'), (60, 'good'), (40, 'ok'), (20, 'low'), (0, 'poor')))),
-                ('rigour', models.PositiveSmallIntegerField(default=0, null=True, verbose_name=((101, '-'), (100, 'top'), (80, 'high'), (60, 'good'), (40, 'ok'), (20, 'low'), (0, 'poor')))),
-                ('originality', models.PositiveSmallIntegerField(default=0, null=True, verbose_name=((101, '-'), (100, 'top'), (80, 'high'), (60, 'good'), (40, 'ok'), (20, 'low'), (0, 'poor')))),
-                ('significance', models.PositiveSmallIntegerField(default=0, null=True, verbose_name=((101, '-'), (100, 'top'), (80, 'high'), (60, 'good'), (40, 'ok'), (20, 'low'), (0, 'poor')))),
-                ('commentary', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='commentaries.Commentary')),
-                ('rater', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='scipost.Contributor')),
+                ('clarity', models.PositiveSmallIntegerField(choices=[(101, '-'), (100, 'top'), (80, 'high'), (60, 'good'), (40, 'ok'), (20, 'low'), (0, 'poor')], default=101)),
+                ('validity', models.PositiveSmallIntegerField(choices=[(101, '-'), (100, 'top'), (80, 'high'), (60, 'good'), (40, 'ok'), (20, 'low'), (0, 'poor')], default=101)),
+                ('rigour', models.PositiveSmallIntegerField(choices=[(101, '-'), (100, 'top'), (80, 'high'), (60, 'good'), (40, 'ok'), (20, 'low'), (0, 'poor')], default=101)),
+                ('originality', models.PositiveSmallIntegerField(choices=[(101, '-'), (100, 'top'), (80, 'high'), (60, 'good'), (40, 'ok'), (20, 'low'), (0, 'poor')], default=101)),
+                ('significance', models.PositiveSmallIntegerField(choices=[(101, '-'), (100, 'top'), (80, 'high'), (60, 'good'), (40, 'ok'), (20, 'low'), (0, 'poor')], default=101)),
             ],
             options={
                 'abstract': False,
@@ -54,13 +45,11 @@ class Migration(migrations.Migration):
             name='CommentRating',
             fields=[
                 ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
-                ('relevance', models.PositiveSmallIntegerField(default=0, null=True, verbose_name=((101, '-'), (100, 'top'), (80, 'high'), (60, 'good'), (40, 'ok'), (20, 'low'), (0, 'poor')))),
-                ('importance', models.PositiveSmallIntegerField(default=0, null=True, verbose_name=((101, '-'), (100, 'top'), (80, 'high'), (60, 'good'), (40, 'ok'), (20, 'low'), (0, 'poor')))),
-                ('clarity', models.PositiveSmallIntegerField(default=0, null=True, verbose_name=((101, '-'), (100, 'top'), (80, 'high'), (60, 'good'), (40, 'ok'), (20, 'low'), (0, 'poor')))),
-                ('validity', models.PositiveSmallIntegerField(default=0, null=True, verbose_name=((101, '-'), (100, 'top'), (80, 'high'), (60, 'good'), (40, 'ok'), (20, 'low'), (0, 'poor')))),
-                ('rigour', models.PositiveSmallIntegerField(default=0, null=True, verbose_name=((101, '-'), (100, 'top'), (80, 'high'), (60, 'good'), (40, 'ok'), (20, 'low'), (0, 'poor')))),
-                ('comment', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='comments.Comment')),
-                ('rater', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='scipost.Contributor')),
+                ('relevance', models.PositiveSmallIntegerField(choices=[(101, '-'), (100, 'top'), (80, 'high'), (60, 'good'), (40, 'ok'), (20, 'low'), (0, 'poor')], default=101)),
+                ('importance', models.PositiveSmallIntegerField(choices=[(101, '-'), (100, 'top'), (80, 'high'), (60, 'good'), (40, 'ok'), (20, 'low'), (0, 'poor')], default=101)),
+                ('clarity', models.PositiveSmallIntegerField(choices=[(101, '-'), (100, 'top'), (80, 'high'), (60, 'good'), (40, 'ok'), (20, 'low'), (0, 'poor')], default=101)),
+                ('validity', models.PositiveSmallIntegerField(choices=[(101, '-'), (100, 'top'), (80, 'high'), (60, 'good'), (40, 'ok'), (20, 'low'), (0, 'poor')], default=101)),
+                ('rigour', models.PositiveSmallIntegerField(choices=[(101, '-'), (100, 'top'), (80, 'high'), (60, 'good'), (40, 'ok'), (20, 'low'), (0, 'poor')], default=101)),
             ],
             options={
                 'abstract': False,
@@ -70,13 +59,11 @@ class Migration(migrations.Migration):
             name='ReportRating',
             fields=[
                 ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
-                ('relevance', models.PositiveSmallIntegerField(default=0, null=True, verbose_name=((101, '-'), (100, 'top'), (80, 'high'), (60, 'good'), (40, 'ok'), (20, 'low'), (0, 'poor')))),
-                ('importance', models.PositiveSmallIntegerField(default=0, null=True, verbose_name=((101, '-'), (100, 'top'), (80, 'high'), (60, 'good'), (40, 'ok'), (20, 'low'), (0, 'poor')))),
-                ('clarity', models.PositiveSmallIntegerField(default=0, null=True, verbose_name=((101, '-'), (100, 'top'), (80, 'high'), (60, 'good'), (40, 'ok'), (20, 'low'), (0, 'poor')))),
-                ('validity', models.PositiveSmallIntegerField(default=0, null=True, verbose_name=((101, '-'), (100, 'top'), (80, 'high'), (60, 'good'), (40, 'ok'), (20, 'low'), (0, 'poor')))),
-                ('rigour', models.PositiveSmallIntegerField(default=0, null=True, verbose_name=((101, '-'), (100, 'top'), (80, 'high'), (60, 'good'), (40, 'ok'), (20, 'low'), (0, 'poor')))),
-                ('rater', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='scipost.Contributor')),
-                ('report', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='submissions.Report')),
+                ('relevance', models.PositiveSmallIntegerField(choices=[(101, '-'), (100, 'top'), (80, 'high'), (60, 'good'), (40, 'ok'), (20, 'low'), (0, 'poor')], default=101)),
+                ('importance', models.PositiveSmallIntegerField(choices=[(101, '-'), (100, 'top'), (80, 'high'), (60, 'good'), (40, 'ok'), (20, 'low'), (0, 'poor')], default=101)),
+                ('clarity', models.PositiveSmallIntegerField(choices=[(101, '-'), (100, 'top'), (80, 'high'), (60, 'good'), (40, 'ok'), (20, 'low'), (0, 'poor')], default=101)),
+                ('validity', models.PositiveSmallIntegerField(choices=[(101, '-'), (100, 'top'), (80, 'high'), (60, 'good'), (40, 'ok'), (20, 'low'), (0, 'poor')], default=101)),
+                ('rigour', models.PositiveSmallIntegerField(choices=[(101, '-'), (100, 'top'), (80, 'high'), (60, 'good'), (40, 'ok'), (20, 'low'), (0, 'poor')], default=101)),
             ],
             options={
                 'abstract': False,
@@ -86,13 +73,25 @@ class Migration(migrations.Migration):
             name='SubmissionRating',
             fields=[
                 ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
-                ('clarity', models.PositiveSmallIntegerField(default=0, null=True, verbose_name=((101, '-'), (100, 'top'), (80, 'high'), (60, 'good'), (40, 'ok'), (20, 'low'), (0, 'poor')))),
-                ('validity', models.PositiveSmallIntegerField(default=0, null=True, verbose_name=((101, '-'), (100, 'top'), (80, 'high'), (60, 'good'), (40, 'ok'), (20, 'low'), (0, 'poor')))),
-                ('rigour', models.PositiveSmallIntegerField(default=0, null=True, verbose_name=((101, '-'), (100, 'top'), (80, 'high'), (60, 'good'), (40, 'ok'), (20, 'low'), (0, 'poor')))),
-                ('originality', models.PositiveSmallIntegerField(default=0, null=True, verbose_name=((101, '-'), (100, 'top'), (80, 'high'), (60, 'good'), (40, 'ok'), (20, 'low'), (0, 'poor')))),
-                ('significance', models.PositiveSmallIntegerField(default=0, null=True, verbose_name=((101, '-'), (100, 'top'), (80, 'high'), (60, 'good'), (40, 'ok'), (20, 'low'), (0, 'poor')))),
-                ('rater', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='scipost.Contributor')),
-                ('submission', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='submissions.Submission')),
+                ('clarity', models.PositiveSmallIntegerField(choices=[(101, '-'), (100, 'top'), (80, 'high'), (60, 'good'), (40, 'ok'), (20, 'low'), (0, 'poor')], default=101)),
+                ('validity', models.PositiveSmallIntegerField(choices=[(101, '-'), (100, 'top'), (80, 'high'), (60, 'good'), (40, 'ok'), (20, 'low'), (0, 'poor')], default=101)),
+                ('rigour', models.PositiveSmallIntegerField(choices=[(101, '-'), (100, 'top'), (80, 'high'), (60, 'good'), (40, 'ok'), (20, 'low'), (0, 'poor')], default=101)),
+                ('originality', models.PositiveSmallIntegerField(choices=[(101, '-'), (100, 'top'), (80, 'high'), (60, 'good'), (40, 'ok'), (20, 'low'), (0, 'poor')], default=101)),
+                ('significance', models.PositiveSmallIntegerField(choices=[(101, '-'), (100, 'top'), (80, 'high'), (60, 'good'), (40, 'ok'), (20, 'low'), (0, 'poor')], default=101)),
+            ],
+            options={
+                'abstract': False,
+            },
+        ),
+        migrations.CreateModel(
+            name='ThesisLinkRating',
+            fields=[
+                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+                ('clarity', models.PositiveSmallIntegerField(choices=[(101, '-'), (100, 'top'), (80, 'high'), (60, 'good'), (40, 'ok'), (20, 'low'), (0, 'poor')], default=101)),
+                ('validity', models.PositiveSmallIntegerField(choices=[(101, '-'), (100, 'top'), (80, 'high'), (60, 'good'), (40, 'ok'), (20, 'low'), (0, 'poor')], default=101)),
+                ('rigour', models.PositiveSmallIntegerField(choices=[(101, '-'), (100, 'top'), (80, 'high'), (60, 'good'), (40, 'ok'), (20, 'low'), (0, 'poor')], default=101)),
+                ('originality', models.PositiveSmallIntegerField(choices=[(101, '-'), (100, 'top'), (80, 'high'), (60, 'good'), (40, 'ok'), (20, 'low'), (0, 'poor')], default=101)),
+                ('significance', models.PositiveSmallIntegerField(choices=[(101, '-'), (100, 'top'), (80, 'high'), (60, 'good'), (40, 'ok'), (20, 'low'), (0, 'poor')], default=101)),
             ],
             options={
                 'abstract': False,
diff --git a/scipost/forms.py b/scipost/forms.py
index c7db107ca..8d9d52efb 100644
--- a/scipost/forms.py
+++ b/scipost/forms.py
@@ -87,3 +87,8 @@ class PasswordChangeForm(forms.Form):
     password_new = forms.CharField(label='New password', widget=forms.PasswordInput())
     password_verif = forms.CharField(label='Reenter new password', widget=forms.PasswordInput())
 
+
+class RatingForm(forms.ModelForm):
+    class Meta:
+        model = RatingItem
+        fields = ['relevance', 'importance', 'clarity', 'validity', 'rigour', 'originality', 'significance']
diff --git a/scipost/models.py b/scipost/models.py
index 031444c27..fba0d19ac 100644
--- a/scipost/models.py
+++ b/scipost/models.py
@@ -11,6 +11,8 @@ SCIPOST_DISCIPLINES = (
     )
 disciplines_dict = dict(SCIPOST_DISCIPLINES)
 
+
+
 CONTRIBUTOR_RANKS = (
     # ranks determine the type of Contributor:
     # 0: newly registered (unverified; not allowed to submit, comment or vote)
@@ -144,3 +146,53 @@ class Contributor(models.Model):
         return output
 
 
+#####################
+### Ratings objects
+#####################
+
+
+### RatingItems
+
+RATING_CHOICES = (
+    (101, '-'), # Only values between 0 and 100 are kept, anything outside those limits is discarded.
+    (100, 'top'), (80, 'high'), (60, 'good'), (40, 'ok'), (20, 'low'), (0, 'poor')
+    )
+
+class RatingItem(models.Model):
+    """ 
+    Base class for all ratings.
+    """
+    rater = models.ForeignKey(Contributor)
+    submission = models.ForeignKey('submissions.Submission', blank=True, null=True)
+    comment = models.ForeignKey('comments.Comment', blank=True, null=True)
+    relevance = models.PositiveSmallIntegerField(choices=RATING_CHOICES, default=101)
+    importance = models.PositiveSmallIntegerField(choices=RATING_CHOICES, default=101)
+    clarity = models.PositiveSmallIntegerField(choices=RATING_CHOICES, default=101)
+    validity = models.PositiveSmallIntegerField(choices=RATING_CHOICES, default=101)
+    rigour = models.PositiveSmallIntegerField(choices=RATING_CHOICES, default=101)
+    originality = models.PositiveSmallIntegerField(choices=RATING_CHOICES, default=101)
+    significance = models.PositiveSmallIntegerField(choices=RATING_CHOICES, default=101)
+
+
+### RatingAggregates
+
+class RatingAggregate(models.Model):
+    """
+    Aggregated ratings for an object.
+    """
+    nr = models.PositiveSmallIntegerField(default=0)
+    nr_relevance_ratings = models.IntegerField(default=0)
+    relevance_rating = models.DecimalField(default=0, max_digits=3, decimal_places=0)
+    nr_importance_ratings = models.IntegerField(default=0)
+    importance_rating = models.DecimalField(default=0, max_digits=3, decimal_places=0)
+    nr_clarity_ratings = models.IntegerField(default=0)
+    clarity_rating = models.DecimalField(default=0, max_digits=3, decimal_places=0)
+    nr_validity_ratings = models.IntegerField(default=0)
+    validity_rating = models.DecimalField(default=0, max_digits=3, decimal_places=0)
+    nr_rigour_ratings = models.IntegerField(default=0)
+    rigour_rating = models.DecimalField(default=0, max_digits=3, decimal_places=0)
+    nr_originality_ratings = models.IntegerField(default=0)
+    originality_rating = models.DecimalField(default=0, max_digits=3, decimal_places=0)
+    nr_significance_ratings = models.IntegerField(default=0)
+    significance_rating = models.DecimalField(default=0, max_digits=3, decimal_places=0)
+
diff --git a/scipost/static/scipost/SciPost.css b/scipost/static/scipost/SciPost.css
index a5a1fe8ff..6d930b090 100644
--- a/scipost/static/scipost/SciPost.css
+++ b/scipost/static/scipost/SciPost.css
@@ -133,6 +133,36 @@ hr.hr12 {
   height: 6px;
 }
 
+.ratingsform {
+  margin: 1px;
+  padding: 4px;
+  display: inline-block;
+  background-color: #204080;
+}
+.ratingsform ul {
+  display: inline-block;
+  color: #ffffff;
+  padding: 2px;
+  box-shadow: 1px 1px 3px #888888;
+}
+.ratingsform ul li {
+  display: inline-block;
+  margin: 0px;
+  padding: 0px 4px;
+}
+.ratingsform label {
+  color: #ffffff;
+  font-size: 80%;
+}
+.ratingsform input {
+  margin: 0px;
+}
+.ratingsform select {
+  margin: 0px;
+  padding: 0px;
+  height: 6px;
+}
+
 .reportid {
   display: inline-block;
   box-shadow: 5px 5px 10px #888888;
diff --git a/submissions/migrations/0001_initial.py b/submissions/migrations/0001_initial.py
index 5d377d0cb..569886c08 100644
--- a/submissions/migrations/0001_initial.py
+++ b/submissions/migrations/0001_initial.py
@@ -1,5 +1,5 @@
 # -*- coding: utf-8 -*-
-# Generated by Django 1.9.1 on 2016-02-26 05:37
+# Generated by Django 1.9.1 on 2016-03-17 19:13
 from __future__ import unicode_literals
 
 from django.db import migrations, models
@@ -32,15 +32,15 @@ class Migration(migrations.Migration):
                 ('date_invited', models.DateTimeField(blank=True, null=True, verbose_name='date invited')),
                 ('date_submitted', models.DateTimeField(verbose_name='date submitted')),
                 ('nr_relevance_ratings', models.IntegerField(default=0)),
-                ('relevance_rating', models.DecimalField(decimal_places=0, default=0, max_digits=3, null=True)),
+                ('relevance_rating', models.DecimalField(decimal_places=0, default=101, max_digits=3, null=True)),
                 ('nr_importance_ratings', models.IntegerField(default=0)),
-                ('importance_rating', models.DecimalField(decimal_places=0, default=0, max_digits=3, null=True)),
+                ('importance_rating', models.DecimalField(decimal_places=0, default=101, max_digits=3, null=True)),
                 ('nr_clarity_ratings', models.IntegerField(default=0)),
-                ('clarity_rating', models.DecimalField(decimal_places=0, default=0, max_digits=3, null=True)),
+                ('clarity_rating', models.DecimalField(decimal_places=0, default=101, max_digits=3, null=True)),
                 ('nr_validity_ratings', models.IntegerField(default=0)),
-                ('validity_rating', models.DecimalField(decimal_places=0, default=0, max_digits=3, null=True)),
+                ('validity_rating', models.DecimalField(decimal_places=0, default=101, max_digits=3, null=True)),
                 ('nr_rigour_ratings', models.IntegerField(default=0)),
-                ('rigour_rating', models.DecimalField(decimal_places=0, default=0, max_digits=3, null=True)),
+                ('rigour_rating', models.DecimalField(decimal_places=0, default=101, max_digits=3, null=True)),
                 ('author', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='scipost.Contributor')),
                 ('invited_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='invited_by', to='scipost.Contributor')),
             ],
@@ -50,7 +50,7 @@ class Migration(migrations.Migration):
             fields=[
                 ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
                 ('vetted', models.BooleanField(default=False)),
-                ('submitted_to_journal', models.CharField(choices=[('SciPost Physics Letters', 'SciPost Physics Letters'), ('SciPost Physics', 'SciPost Physics'), ('SciPost Physics Lecture Notes', 'SciPost Physics Lecture Notes')], max_length=30, verbose_name='Journal to be submitted to')),
+                ('submitted_to_journal', models.CharField(choices=[('SciPost Physics', 'SciPost Physics'), ('SciPost Physics Lecture Notes', 'SciPost Physics Lecture Notes')], max_length=30, verbose_name='Journal to be submitted to')),
                 ('discipline', models.CharField(choices=[('physics', 'Physics')], default='physics', max_length=20)),
                 ('domain', models.CharField(choices=[('E', 'Experimental'), ('T', 'Theoretical'), ('C', 'Computational'), ('ET', 'Exp. & Theor.'), ('EC', 'Exp. & Comp.'), ('TC', 'Theor. & Comp.'), ('ETC', 'Exp., Theor. & Comp.')], max_length=3)),
                 ('specialization', models.CharField(choices=[('A', 'Atomic, Molecular and Optical Physics'), ('B', 'Biophysics'), ('C', 'Condensed Matter Physics'), ('F', 'Fluid Dynamics'), ('G', 'Gravitation, Cosmology and Astroparticle Physics'), ('H', 'High-Energy Physics'), ('M', 'Mathematical Physics'), ('N', 'Nuclear Physics'), ('Q', 'Quantum Statistical Mechanics'), ('S', 'Statistical and Soft Matter Physics')], max_length=1)),
@@ -63,15 +63,15 @@ class Migration(migrations.Migration):
                 ('arxiv_link', models.URLField(verbose_name='arXiv link (including version nr)')),
                 ('submission_date', models.DateField(verbose_name='submission date')),
                 ('nr_clarity_ratings', models.IntegerField(default=0)),
-                ('clarity_rating', models.DecimalField(decimal_places=0, default=0, max_digits=3, null=True)),
+                ('clarity_rating', models.DecimalField(decimal_places=0, default=101, max_digits=3, null=True)),
                 ('nr_validity_ratings', models.IntegerField(default=0)),
-                ('validity_rating', models.DecimalField(decimal_places=0, default=0, max_digits=3, null=True)),
+                ('validity_rating', models.DecimalField(decimal_places=0, default=101, max_digits=3, null=True)),
                 ('nr_rigour_ratings', models.IntegerField(default=0)),
-                ('rigour_rating', models.DecimalField(decimal_places=0, default=0, max_digits=3, null=True)),
+                ('rigour_rating', models.DecimalField(decimal_places=0, default=101, max_digits=3, null=True)),
                 ('nr_originality_ratings', models.IntegerField(default=0)),
-                ('originality_rating', models.DecimalField(decimal_places=0, default=0, max_digits=3, null=True)),
+                ('originality_rating', models.DecimalField(decimal_places=0, default=101, max_digits=3, null=True)),
                 ('nr_significance_ratings', models.IntegerField(default=0)),
-                ('significance_rating', models.DecimalField(decimal_places=0, default=0, max_digits=3, null=True)),
+                ('significance_rating', models.DecimalField(decimal_places=0, default=101, max_digits=3, null=True)),
                 ('latest_activity', models.DateTimeField(default=django.utils.timezone.now)),
                 ('authors', models.ManyToManyField(blank=True, related_name='authors_sub', to='scipost.Contributor')),
                 ('editor_in_charge', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='editor_in_charge', to='scipost.Contributor')),
diff --git a/submissions/templates/submissions/submission_detail.html b/submissions/templates/submissions/submission_detail.html
index 795e2444e..5316997db 100644
--- a/submissions/templates/submissions/submission_detail.html
+++ b/submissions/templates/submissions/submission_detail.html
@@ -1,4 +1,4 @@
-]{% extends 'scipost/base.html' %}
+{% extends 'scipost/base.html' %}
 
 {% block pagetitle %}: submission detail{% endblock pagetitle %}
 
-- 
GitLab