diff --git a/interface/codeview.py b/interface/codeview.py index 3ac9dae2..1712dc92 100644 --- a/interface/codeview.py +++ b/interface/codeview.py @@ -57,3 +57,17 @@ def make_dict(submission_archive): @register.filter def get_item(dictionary, key): return dictionary.get(key) + + +def table_maker(file): + return file.read().splitlines() + + +@register.filter +def with_path(things, path): + return things.filter(path=path) + + +@register.filter +def with_line(things, line): + return things.filter(line=line) diff --git a/interface/forms.py b/interface/forms.py index e2164e22..4f5d35fd 100644 --- a/interface/forms.py +++ b/interface/forms.py @@ -1,6 +1,7 @@ from django import forms from django.conf import settings from django.template.defaultfilters import filesizeformat +from .models import Comment class UploadFileForm(forms.Form): @@ -24,3 +25,13 @@ def clean_file(self): class LoginForm(forms.Form): username = forms.CharField(label="Username") password = forms.CharField(label="Password", widget=forms.PasswordInput) + + +class CommentForm(forms.ModelForm): + class Meta: + model = Comment + fields = ("text",) + + widgets = { + "text": forms.Textarea(attrs={"class": "form-control"}), + } diff --git a/interface/migrations/0023_comment.py b/interface/migrations/0023_comment.py new file mode 100644 index 00000000..e4b6f901 --- /dev/null +++ b/interface/migrations/0023_comment.py @@ -0,0 +1,28 @@ +# Generated by Django 3.0.6 on 2020-09-07 17:48 + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ('interface', '0022_auto_20200709_2326'), + ] + + operations = [ + migrations.CreateModel( + name='Comment', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('path', models.CharField(max_length=256)), + ('line', models.IntegerField(null=True)), + ('text', models.TextField(blank=True, default='', max_length=4096)), + ('created', models.DateTimeField(auto_now_add=True)), + ('submission', models.ForeignKey(null=True, on_delete=django.db.models.deletion.PROTECT, related_name='comments', to='interface.Submission')), + ('user', models.ForeignKey(null=True, on_delete=django.db.models.deletion.PROTECT, to=settings.AUTH_USER_MODEL)), + ], + ), + ] diff --git a/interface/models.py b/interface/models.py index e32df2ee..42d54a2c 100644 --- a/interface/models.py +++ b/interface/models.py @@ -213,4 +213,18 @@ def verify_jwt(self, message): return decoded_message["data"] == str(self.id) +class Comment(models.Model): + path = models.CharField(max_length=256, blank=False) + line = models.IntegerField(null=True) + submission = models.ForeignKey( + Submission, + on_delete=models.PROTECT, + null=True, + related_name="comments", + ) + user = models.ForeignKey(User, on_delete=models.PROTECT, null=True) + text = models.TextField(max_length=4096, default="", blank=True) + created = models.DateTimeField(auto_now_add=True) + + pre_save.connect(signals.update_total_score, sender=Submission) diff --git a/interface/scoring.py b/interface/scoring.py index 4f3ab082..8201f981 100644 --- a/interface/scoring.py +++ b/interface/scoring.py @@ -94,9 +94,27 @@ def compute_review_score(submission): return sum([decimal.Decimal(mark) for mark in marks]) +def compute_comments_review(submission): + total_sum = 0 + teaching_assistants = ( + submission.assignment.course.teaching_assistants.all() + ) + for comment in submission.comments.all(): + if comment.user in teaching_assistants: + marks = re.findall( + r"^([+-]\d+\.*\d*):", comment.text, re.MULTILINE, + ) + log.debug("Marks found: " + str(marks)) + total_sum += sum([decimal.Decimal(mark) for mark in marks]) + + return total_sum + + def calculate_total_score(submission): score = submission.score if submission.score else 0 - submission.review_score = compute_review_score(submission) + submission.review_score = compute_review_score( + submission + ) + compute_comments_review(submission) (penalties, holiday_start, holiday_finish) = get_penalty_info(submission) timestamp = submission.timestamp or datetime.datetime.now() diff --git a/interface/templates/interface/code_view.html b/interface/templates/interface/code_view.html index 890b5d22..9f66bab9 100644 --- a/interface/templates/interface/code_view.html +++ b/interface/templates/interface/code_view.html @@ -1,18 +1,112 @@ {% extends "interface/generics/base.html" %} + + + {% block body_content %}
- {% with dict=tree.items template="interface/tree_view.html" %} - {% include template %} - {% endwith %} +
+ {% if user in sub.assignment.course.teaching_assistants.all %} +

+ +

+ {% endif %} +
+ {% with dict=tree.items template="interface/tree_view.html" %} + {% include template %} + {% endwith %}
-
 {{ file_content }} 
+
+ {% if not file_exists %} + {{ file_content }} + {% else %} + + + + + + + + + {% for line in file_content %} + + + + + + + + {% endfor %} + +
+
{{ forloop.counter }} + {% with forloop.counter as index %} + {% if sub.comments|with_path:path|with_line:index %} +
{{ line }}
+ {% else %} +
{{ line }}
+ {% endif %} + {% endwith %} +
+
+
+ {% with forloop.counter as index %} + {% for comment in path_comments %} + {% if comment.line == index %} +
+

+ Comment {{ forloop.counter }} by {{ comment.user }} + {{ comment.created }} +

+ {{ comment.text|linebreaks }} +
+ {% endif %} + {% empty %} +

There are no comments yet.

+ {% endfor %} + {% endwith %} + {% if new_comment %} +

Your comment has been added.

+ {% else %} +
+
+
+ {% csrf_token %} + {{ form.as_p }} +
+
+ +
+
+

+
+
+
+ {% endif %} +
+
+
+ {% endif %} +
+{% include "interface/generics/review_modal.html" %} + {% endblock %} \ No newline at end of file diff --git a/interface/templates/interface/code_view_homepage.html b/interface/templates/interface/code_view_homepage.html new file mode 100644 index 00000000..2c050a54 --- /dev/null +++ b/interface/templates/interface/code_view_homepage.html @@ -0,0 +1,39 @@ +{% extends "interface/generics/base.html" %} + +{% block body_content %} + +
+
+
+ {% with dict=tree.items template="interface/tree_view.html" %} + {% include template %} + {% endwith %} +
+
+
+
+
+
+                        /^--^\     /^--^\     /^--^\
+                        \____/     \____/     \____/
+                       /      \   /      \   /      \
+                      |        | |        | |        |
+                       \__  __/   \__  __/   \__  __/
+  |^|^|^|^|^|^|^|^|^|^|^|^\ \^|^|^|^/ /^|^|^|^|^\ \^|^|^|^|^|^|^|^|^|^|^|^|
+  | | | | | | | | | | | | |\ \| | |/ /| | | | | | \ \ | | | | | | | | | | |
+  | | | | | | | | | | | | / / | | |\ \| | | | | |/ /| | | | | | | | | | | |
+  | | | | | | | | | | | | \/| | | | \/| | | | | |\/ | | | | | | | | | | | |
+  #########################################################################
+  | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | |
+  | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | |
+
+              
+
+
+
+
+
+ + + +{% endblock %} \ No newline at end of file diff --git a/interface/templates/interface/generics/review_modal.html b/interface/templates/interface/generics/review_modal.html index 69b29854..cebf0c74 100644 --- a/interface/templates/interface/generics/review_modal.html +++ b/interface/templates/interface/generics/review_modal.html @@ -8,11 +8,11 @@ diff --git a/interface/templates/interface/submission_result.html b/interface/templates/interface/submission_result.html index eea61f7c..1d247f2b 100644 --- a/interface/templates/interface/submission_result.html +++ b/interface/templates/interface/submission_result.html @@ -14,26 +14,26 @@

Submission {{ sub }} ({{ sub.state }})

{% endif %} - {% if user in sub.assignment.course.teaching_assistants.all%} -

- -

- {% endif %} - {% if user in sub.assignment.course.teaching_assistants.all %}
{% csrf_token %}
- {% endif %} + {% endif %} - {% if user in sub.assignment.course.teaching_assistants.all %} + {% if user in sub.assignment.course.teaching_assistants.all %}
{% csrf_token %}
- {% endif %} - + {% endif %} + + {% if user == sub.user or user in sub.assignment.course.teaching_assistants.all %} +
+ +
+ {% endif %} + {% if sub.state == sub.STATE_DONE %} @@ -79,6 +79,6 @@

Fortune teller

-{% include "interface/generics/review_modal.html" %} + {% endblock %} diff --git a/interface/templates/interface/tree_view.html b/interface/templates/interface/tree_view.html index 79f9aa11..dbe224e0 100644 --- a/interface/templates/interface/tree_view.html +++ b/interface/templates/interface/tree_view.html @@ -3,7 +3,13 @@