From 9ca68496dc1c1e54b99c5c6939a773924b99e71d Mon Sep 17 00:00:00 2001 From: "robinwilliam.hundt" <robinwilliam.hundt@stud.uni-goettingen.de> Date: Thu, 9 Nov 2017 10:35:46 +0100 Subject: [PATCH] Sanitized backend Deleted templates, fixtures, static files, urls, views --- backend/core/fixtures/testdata-core.json | 88 -------- backend/core/fixtures/testdata-groups.json | 1 - backend/core/fixtures/testdata-user.json | 98 -------- backend/core/forms.py | 39 ---- backend/core/static/css/custom.css | 61 ----- backend/core/static/res/brand.png | Bin 46385 -> 0 bytes backend/core/templates/base.html | 74 ------ .../core/component/feedback_badge.html | 9 - .../core/component/feedback_card.html | 10 - .../templates/core/component/message_box.html | 25 --- .../core/component/tests_editor.html | 27 --- .../core/templates/core/feedback_form.html | 210 ------------------ backend/core/templates/core/index.html | 17 -- .../core/templates/core/r/feedback_list.html | 42 ---- .../core/templates/core/r/progress_card.html | 24 -- .../core/templates/core/r/reviewer_base.html | 55 ----- .../templates/core/r/reviewer_startpage.html | 54 ----- .../templates/core/r/single_submission.html | 89 -------- .../core/templates/core/r/student_list.html | 59 ----- .../core/r/student_submission_list.html | 58 ----- .../templates/core/r/tutor_list_card.html | 19 -- .../templates/core/s/single_submission.html | 74 ------ .../templates/core/s/student_startpage.html | 48 ---- .../templates/core/t/tutor_startpage.html | 130 ----------- backend/core/urls.py | 22 +- backend/core/views/__init__.py | 10 - backend/core/views/export_csv.py | 28 --- backend/core/views/feedback.py | 134 ----------- backend/core/views/generics.py | 58 ----- backend/core/views/index.py | 5 - backend/core/views/login.py | 64 ------ backend/core/views/submission.py | 45 ---- backend/core/views/user_startpages.py | 67 ------ 33 files changed, 2 insertions(+), 1742 deletions(-) delete mode 100644 backend/core/fixtures/testdata-core.json delete mode 100644 backend/core/fixtures/testdata-groups.json delete mode 100644 backend/core/fixtures/testdata-user.json delete mode 100644 backend/core/forms.py delete mode 100644 backend/core/static/css/custom.css delete mode 100644 backend/core/static/res/brand.png delete mode 100644 backend/core/templates/base.html delete mode 100644 backend/core/templates/core/component/feedback_badge.html delete mode 100644 backend/core/templates/core/component/feedback_card.html delete mode 100644 backend/core/templates/core/component/message_box.html delete mode 100644 backend/core/templates/core/component/tests_editor.html delete mode 100644 backend/core/templates/core/feedback_form.html delete mode 100644 backend/core/templates/core/index.html delete mode 100644 backend/core/templates/core/r/feedback_list.html delete mode 100644 backend/core/templates/core/r/progress_card.html delete mode 100644 backend/core/templates/core/r/reviewer_base.html delete mode 100644 backend/core/templates/core/r/reviewer_startpage.html delete mode 100644 backend/core/templates/core/r/single_submission.html delete mode 100644 backend/core/templates/core/r/student_list.html delete mode 100644 backend/core/templates/core/r/student_submission_list.html delete mode 100644 backend/core/templates/core/r/tutor_list_card.html delete mode 100644 backend/core/templates/core/s/single_submission.html delete mode 100644 backend/core/templates/core/s/student_startpage.html delete mode 100644 backend/core/templates/core/t/tutor_startpage.html delete mode 100644 backend/core/views/__init__.py delete mode 100644 backend/core/views/export_csv.py delete mode 100644 backend/core/views/feedback.py delete mode 100644 backend/core/views/generics.py delete mode 100644 backend/core/views/index.py delete mode 100644 backend/core/views/login.py delete mode 100644 backend/core/views/submission.py delete mode 100644 backend/core/views/user_startpages.py diff --git a/backend/core/fixtures/testdata-core.json b/backend/core/fixtures/testdata-core.json deleted file mode 100644 index 28b9bea5..00000000 --- a/backend/core/fixtures/testdata-core.json +++ /dev/null @@ -1,88 +0,0 @@ -[ - { - "fields": { - "full_score": 10, - "name": "Aufgabe 01", - "solution": "solution", - "slug": "brezmaphgocfuikw", - "description": "description" - }, - "model": "core.submissiontype", - "pk": 1 - }, - { - "fields": { - "full_score": 20, - "name": "Aufgabe 02", - "solution": "solution", - "slug": "zbjfwldsuhqgxvmn", - "description": "description" - }, - "model": "core.submissiontype", - "pk": 2 - }, - { - "fields": { - "has_logged_in": false, - "matrikel_no": "12345678", - "name": "Student 01 Vorname und Nachname", - "user": 4 - }, - "model": "core.student", - "pk": 1 - }, - { - "fields": { - "has_logged_in": false, - "matrikel_no": "87654321", - "name": "Student 02 Vorname und Nachname", - "user": 5 - }, - "model": "core.student", - "pk": 2 - }, - { - "fields": { - "seen_by_student": false, - "slug": "qgleatcwzfxsdnjr", - "student": 1, - "text": "function generate(timeout){\r\n\r\n\t$('#menu_button_img').attr('src', 'style/menu_blink.gif'); \r\n\r\n\tif(timeout == 0)\t\t\t\t\t\t\t\t\r\n\t\t$('#config_form').attr('action', $('#config_form').attr('action') + '#title'); \t\t\t\t// show directly the question\r\n\telse\r\n\t\ttimeout = 0;\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t// disable timeout\r\n\t\r\n\tsetTimeout(function(){ $('#config_form').submit(); }, timeout);\r\n\r\n}", - "type": 1 - }, - "model": "core.submission", - "pk": 1 - }, - { - "fields": { - "seen_by_student": false, - "slug": "mrthqgsloaydjfnc", - "student": 1, - "text": "function showTextEditor(){\r\n\r\n\t$('.ilc_question_Standard').hide('slow');\r\n\t$('.ilc_question_ml_Standard').hide('slow');\r\n\t$('.text_editor').show('slow');\r\n\t\r\n}\r\n\r\nfunction showConfig(){\r\n\r\n\t$('#config_wrapper').animate(\r\n\t\t{\r\n\t\t\tright: ($('#config_wrapper').css('right') == '0px' ? '-322px' : '0px')\r\n\t\t}, \r\n\t500);\r\n\r\n}", - "type": 2 - }, - "model": "core.submission", - "pk": 2 - }, - { - "fields": { - "seen_by_student": false, - "slug": "hunkgevtcfdobyxw", - "student": 2, - "text": "$(document).keydown(function(evt){\r\n\r\n\tif(evt.which == 9){\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t// #9 = TAB\r\n\t\tgenerate(0);\r\n\t\tevt.preventDefault();\r\n\t}\r\n\t\r\n});", - "type": 2 - }, - "model": "core.submission", - "pk": 3 - }, - { - "fields": { - "seen_by_student": false, - "slug": "gurvbyzxjfmhdiep", - "student": 2, - "text": "function showTextEditor(){\r\n\r\n\t$('.ilc_question_Standard').hide('slow');\r\n\t$('.ilc_question_ml_Standard').hide('slow');\r\n\t$('.text_editor').show('slow');\r\n\t\r\n}\r\n\r\nfunction showConfig(){\r\n\r\n\t$('#config_wrapper').animate(\r\n\t\t{\r\n\t\t\tright: ($('#config_wrapper').css('right') == '0px' ? '-322px' : '0px')\r\n\t\t}, \r\n\t500);\r\n\r\n}", - "type": 1 - }, - "model": "core.submission", - "pk": 4 - } -] diff --git a/backend/core/fixtures/testdata-groups.json b/backend/core/fixtures/testdata-groups.json deleted file mode 100644 index e0c5e95c..00000000 --- a/backend/core/fixtures/testdata-groups.json +++ /dev/null @@ -1 +0,0 @@ -[{"model": "auth.group", "pk": 1, "fields": {"name": "Students", "permissions": []}}, {"model": "auth.group", "pk": 2, "fields": {"name": "Reviewers", "permissions": []}}, {"model": "auth.group", "pk": 3, "fields": {"name": "Tutors", "permissions": []}}] \ No newline at end of file diff --git a/backend/core/fixtures/testdata-user.json b/backend/core/fixtures/testdata-user.json deleted file mode 100644 index 34cf27c2..00000000 --- a/backend/core/fixtures/testdata-user.json +++ /dev/null @@ -1,98 +0,0 @@ -[ - { - "fields": { - "date_joined": "2017-06-08T15:07:10.023Z", - "email": "", - "first_name": "", - "groups": [], - "is_active": true, - "is_staff": true, - "is_superuser": true, - "last_login": "2017-06-08T15:07:30.105Z", - "last_name": "", - "password": "pbkdf2_sha256$30000$hirLzfSDQ9f3$CNgyfYKEzxYHkhx3SE5gde3ZeTRsJRYmdr1AMlYIwtg=", - "user_permissions": [], - "username": "doncamillo" - }, - "model": "auth.user", - "pk": 1 - }, - { - "fields": { - "date_joined": "2017-06-08T15:27:53Z", - "email": "", - "first_name": "", - "groups": [ - 2 - ], - "is_active": true, - "is_staff": false, - "is_superuser": false, - "last_login": null, - "last_name": "", - "password": "pbkdf2_sha256$30000$GMuQITImWNbK$i1FftkDWk2fmjHyv7VThV40DzkdfzS8tbnT4uswzfRA=", - "user_permissions": [], - "username": "reviewer" - }, - "model": "auth.user", - "pk": 2 - }, - { - "fields": { - "date_joined": "2017-06-08T15:28:24.320Z", - "email": "", - "first_name": "", - "groups": [], - "is_active": true, - "is_staff": false, - "is_superuser": false, - "last_login": null, - "last_name": "", - "password": "pbkdf2_sha256$30000$JuuBxTeONPuc$Gfbo+MkZmxWJpVVOSf66Sz7Mvz/Of0WFXrosbSeQv24=", - "user_permissions": [], - "username": "tutor" - }, - "model": "auth.user", - "pk": 3 - }, - { - "fields": { - "date_joined": "2017-06-08T15:29:05Z", - "email": "", - "first_name": "", - "groups": [ - 1 - ], - "is_active": true, - "is_staff": false, - "is_superuser": false, - "last_login": null, - "last_name": "", - "password": "pbkdf2_sha256$30000$YaJGFEnSEejd$2dmLmeVFyhEZda/YWwJ/zRMvAbnULYA90IrakJsMYCw=", - "user_permissions": [], - "username": "student01" - }, - "model": "auth.user", - "pk": 4 - }, - { - "fields": { - "date_joined": "2017-06-08T15:31:44Z", - "email": "", - "first_name": "", - "groups": [ - 1 - ], - "is_active": true, - "is_staff": false, - "is_superuser": false, - "last_login": null, - "last_name": "", - "password": "pbkdf2_sha256$30000$SR5pr6OUXScN$NYQiX7J5wgjW8t4gROq46oqRPVWoGd+J1Od4ZWzkN3A=", - "user_permissions": [], - "username": "student02" - }, - "model": "auth.user", - "pk": 5 - } -] diff --git a/backend/core/forms.py b/backend/core/forms.py deleted file mode 100644 index 766cf783..00000000 --- a/backend/core/forms.py +++ /dev/null @@ -1,39 +0,0 @@ -from django.forms import CharField, ModelForm, Textarea, ValidationError - -from core.models import Feedback - - -class FeedbackForm(ModelForm): - text = CharField( - widget=Textarea( - attrs={ - 'name': 'text', - 'id': 'id_text', - } - ), - label='', - required=False, - ) - - def clean(self): - cleaned_data = super().clean() - - full_score = self.instance.of_submission.type.full_score - if not cleaned_data.get("score") <= full_score: - raise ValidationError( - "Score too high. Maximum score is %(max_score)d", - code='over_max_score', - params={'max_score': full_score}, - ) - - if not cleaned_data.get("text"): - cleaned_data["status"] = Feedback.EDITABLE - raise ValidationError( - "Feedback should not be empty", - code="is_empty", - ) - - class Meta: - model = Feedback - auto_id = False - fields = ('text', 'score', 'status') diff --git a/backend/core/static/css/custom.css b/backend/core/static/css/custom.css deleted file mode 100644 index 8e2e7f1c..00000000 --- a/backend/core/static/css/custom.css +++ /dev/null @@ -1,61 +0,0 @@ - -pre { - width: 100%; - white-space: -moz-pre-wrap; /* Mozilla, supported since 1999 */ - white-space: -pre-wrap; /* Opera */ - white-space: -o-pre-wrap; /* Opera */ - white-space: pre-wrap; /* CSS3 - Text module (Candidate Recommendation) http://www.w3.org/TR/css3-text/#white-space */ - word-wrap: break-word; /* IE 5.5+ */ -} - -.card-block{ - padding: 0; -} - -.editor { - position: relative; - top: 0; - right: 0; - bottom: 0; - left: 0; - width: auto; -} - -.editor-code { - height: 500px; -} - -.editor-pre { - height: 200px; -} - -.nopadding { - padding: 0 !important; -} - -.nopadding-right { - padding-right: 0 !important; -} - -.nomargin { - margin: 0 !important; -} - -table.dataTable { - clear:both; - margin-top: 0 !important; - margin-bottom: 0 !important; - padding: 0 !important; - border-collapse:separate !important -} - -.col-sm-12 { - padding: 0 !important; -} - -.table td.fit, -.table th.fit { - white-space: nowrap; - width: 1%; -} - diff --git a/backend/core/static/res/brand.png b/backend/core/static/res/brand.png deleted file mode 100644 index 5dfdb7913e235b0e63d195afc1d27f1b4ad04c86..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 46385 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 N002ovPDHLkV1mu|Vxa&4 diff --git a/backend/core/templates/base.html b/backend/core/templates/base.html deleted file mode 100644 index 90c2d78e..00000000 --- a/backend/core/templates/base.html +++ /dev/null @@ -1,74 +0,0 @@ -{% load staticfiles %} - -<!DOCTYPE html> -<html lang="en"> -<head> - <meta charset="utf-8"> - <meta name="viewport" content="width=device-width, initial-scale=1"> - <meta name="description" content=""> - <meta name="author" content=""> - - <title>Grady - {% block title %}Wellcome to correction hell!{% endblock %}</title> - - {# CSS includes #} - <link rel="stylesheet" href="{% static 'datatables.net-bs4/css/dataTables.bootstrap4.css' %}"> - <link rel="stylesheet" href="{% static 'bootstrap/dist/css/bootstrap.min.css' %}"> - <link rel="stylesheet" href="{% static 'css/custom.css' %}"> - - {# Importing stuff for ACE editor #} - <script src="{% static 'ace-editor-builds/src-min/ace.js' %}"></script> - <script src="{% static 'ace-editor-builds/src-min/mode-c_cpp.js' %}"></script> - - {# Load other javascript #} - <script src="{% static 'jquery/dist/jquery.min.js' %}"></script> - <script src="{% static 'popper.js/dist/umd/popper.min.js' %}"></script> - <script src="{% static 'bootstrap/dist/js/bootstrap.min.js' %}"></script> - - {# sortable table stuff #} - <script src="{% static 'datatables.net/js/jquery.dataTables.js' %}"></script> - <script src="{% static 'datatables.net-bs4/js/dataTables.bootstrap4.js' %}"></script> -</head> - -{# Navbar contaning: Brand - Title - User menu bar <---> (Username - Logout || Login form) #} -<nav class="navbar navbar-expand navbar-light bg-light"> - <a class="navbar-brand" href="{% url 'start' %}"> - <img src="{% static 'res/brand.png' %}" width="30" height="30" class="d-inline-block align-top" alt=""> - Grady - </a> - - <div class="navbar-nav mr-auto"> - {% block navbar %}Grady, Sir. Delbert Grady.{% endblock navbar %} - </div> - - {% if user.is_authenticated %} - <ul class="nav nav-pills"> - <li class="nav-item"><a class="btn mr-1 navbar-btn btn-link" href="{% url 'start' %}">{{ user.username }}</a></li> - <li class="nav-item"><a class="btn mr-1 navbar-btn btn-outline-primary" href="{% url 'logout' %}" role="button">Logout</a></li> - <li class="nav-item"><a class="btn mr-1 navbar-btn btn-outline-danger" href="https://gitlab.gwdg.de/j.michal/grady" target="_blank">Give Feedback</a></li> - </ul> - {% else %} - <form id="login_form" class="navbar-form form-inline" role="form" method="post" action="/login/"> - {% csrf_token %} - <div class="form-group mx-sm-1"> - <input type="text" class="form-control" name="username" value="" placeholder="Username" autofocus> - </div> - <div class="form-group mx-sm-1"> - <input type="password" class="form-control" name="password" value="" placeholder="Password"> - </div> - <div class="form-group mx-sm-1"> - <button type="submit" class="btn btn-primary">Login</button> - </div> - </form> - {% endif %} -</nav> - -<body> - <div class="container-fluid"> - {% block body_block %} - {% endblock %} - </div> - - {% block script_block %} - {% endblock script_block %} -</body> -</html> diff --git a/backend/core/templates/core/component/feedback_badge.html b/backend/core/templates/core/component/feedback_badge.html deleted file mode 100644 index 724f0ec9..00000000 --- a/backend/core/templates/core/component/feedback_badge.html +++ /dev/null @@ -1,9 +0,0 @@ -{% if feedback.status == feedback.EDITABLE %} - <span class="badge badge-info">{{feedback.get_status_display}}</span> -{% elif feedback.status == feedback.NEEDS_REVIEW %} - <span class="badge badge-primary">{{feedback.get_status_display}}</span> -{% elif feedback.status == feedback.ACCEPTED %} - <span class="badge badge-success">{{feedback.get_status_display}}</span> -{% elif feedback.status == feedback.OPEN %} - <span class="badge badge-warning">{{feedback.get_status_display}}</span> -{% endif %} diff --git a/backend/core/templates/core/component/feedback_card.html b/backend/core/templates/core/component/feedback_card.html deleted file mode 100644 index e5a8917d..00000000 --- a/backend/core/templates/core/component/feedback_card.html +++ /dev/null @@ -1,10 +0,0 @@ -<div class="card my-1"> - <a data-toggle="collapse" href="#collapse{{unique}}"> - <h5 class="card-header">{{ header }}</h5> - </a> - <div id="collapse{{unique}}" class="collapse {{expanded}}" role="tabpanel"> - <div class="card-block m-2"> - {{ content|safe }} - </div> - </div> -</div> diff --git a/backend/core/templates/core/component/message_box.html b/backend/core/templates/core/component/message_box.html deleted file mode 100644 index 8bef5525..00000000 --- a/backend/core/templates/core/component/message_box.html +++ /dev/null @@ -1,25 +0,0 @@ -{# This is where all the messages pop up #} -{% if messages or form.errors %} -<div class="row"> - <div class="col my-2"> - {% for message in messages %} - <div class="alert {{ message.tags }} alert-dismissible fade show" role="alert"> - <button type="button" class="close" data-dismiss="alert" aria-label="Close"> - <span aria-hidden="true">×</span> - </button> - {{message}} - </div> - {% endfor %} - {% if form %} - {% for error in form.non_field_errors %} - <div class="alert alert-danger alert-dismissible fade show" role="alert"> - <button type="button" class="close" data-dismiss="alert" aria-label="Close"> - <span aria-hidden="true">×</span> - </button> - {{error}} - </div> - {% endfor %} - {% endif %} - </div> -</div> -{% endif %} diff --git a/backend/core/templates/core/component/tests_editor.html b/backend/core/templates/core/component/tests_editor.html deleted file mode 100644 index 36239778..00000000 --- a/backend/core/templates/core/component/tests_editor.html +++ /dev/null @@ -1,27 +0,0 @@ -{# Custom feedback from the compiler #} -<div class="card my-1"> - <a data-toggle="collapse" href="#collapse4"> - <h5 class="card-header">Tester Output</h5> - </a> - <div id="collapse4" class="collapse hide" role="tabpanel"> - <div class="card-block m-2"> - <div id="tests_editor" class="editor editor-pre">{% for test in submission.tests.all %} -# {{test.name}} -{{test.annotation}} -RESULT: {{test.label}} -------------------------------------------------- -{% endfor %} - </div> - </div> - </div> - <script> - var editor_pre = ace.edit("tests_editor"); - editor_pre.setOptions({ - readOnly: true, - showGutter: false, - highlightActiveLine: false, - maxLines: Infinity, - }) - </script> -</div> - diff --git a/backend/core/templates/core/feedback_form.html b/backend/core/templates/core/feedback_form.html deleted file mode 100644 index 601aa89b..00000000 --- a/backend/core/templates/core/feedback_form.html +++ /dev/null @@ -1,210 +0,0 @@ -{% extends "base.html" %} - -{% block navbar %} {{ grady_says }} {% endblock navbar %} - -{% block title %} Editing feedback {% endblock %} - -{% load staticfiles %} - -{% block body_block %} -<div class="row"> - <div class="col my-2 nopadding-right"> - - <div class="card mb-2"> - <div class="card-header form-inline pb-1"> - <h4 class="mr-2">{{feedback.of_submission.type.name}}</h4> - <a href="{% url 'download_submissions' feedback.of_submission.slug %}" class="btn btn-sm btn-outline-primary mb-1">Download</a> - </div> - <div class="card-block"> - <div id="student_text" class="editor editor-code"></div> - </div> - </div> - - {# Custom feedback from the compiler #} - <div class="card my-1"> - <a data-toggle="collapse" href="#collapse4"> - <h5 class="card-header">Custom Feedback</h5> - </a> - <div id="collapse4" class="collapse show" role="tabpanel"> - <div class="card-block m-2"> - <div id="tests_editor" class="editor editor-pre">{% for test in feedback.of_submission.tests.all %} -# {{test.name}} -{{test.annotation}} -RESULT: {{test.label}} -------------------------------------------------- - {% endfor %}</div> - </div> - </div> - </div> - - {# A sample solution #} - <div class="card my-1"> - <a data-toggle="collapse" href="#collapse5"> - <h5 class="card-header">Sample Solution</h5> - </a> - <div id="collapse5" class="collapse show" role="tabpanel"> - <div class="card-block m-2"> - <div id="solution" class="editor editor-code">{{feedback.of_submission.type.solution}}</div> - </div> - </div> - </div> - - {% include "core/component/feedback_card.html" with unique="1" header="Description" content=feedback.of_submission.type.description expanded="hide" %} - - <div class="my-2"> - <button type="button" id="collapseAllOpen" class="btn btn-secondary">Open All</button> - <button type="button" id="collapseAllClose" class="btn btn-secondary">Close All</button> - </div> - </div> - - <div class="col my-2"> - <div class="row-auto mb-2"> - <div class="card"> - <h4 class="card-header">Please provide your feedback</h4> - <div class="card-block"> - <div class="editor editor-code" id="tutor_text" autofocus></div> - </div> - </div> - </div> - - <div class="row-auto"> - <form action="{% url 'FeedbackEdit' feedback.slug %}" method="post" id="form1"> - {% csrf_token %} - <div hidden> {{ form.text }} </div> - <div class="form-inline"> - - {# Score field #} - <div class="input-group col-5 nopadding mr-1 mb-2"> - <span class="input-group-addon">Score:</span> - <input - class="form-control" - id="id_score" - min="0" max="{{ feedback.of_submission.type.full_score }}" - name="score" - type="number" - value="{{ form.score.value }}" - required - {% if feedback.status == feedback.ACCEPTED %}readonly{% endif %}> - <span class="input-group-btn"> - <button id="assign_full_score" class="btn btn-secondary" type="button"><code>/{{ feedback.of_submission.type.full_score }}</code></button> - </span> - </div> - - {# status select #} - {% with form.fields.status as status %} - <div class="form-group mr-2 mb-2"> - <select class="custom-select" id="id_status" name="status"> - {% for val, name in status.choices %} - <option value="{{val}}" {% if val == feedback.status %}selected{% endif %}>{{name}}</option> - {% endfor %} - </select> - </div> - {% endwith %} - - <div> - {# Beware! compares status and origin #} - <button type="submit" form="form1" class="btn btn-outline-success mb-2" name="update" value="Save">Save</button> - <button type="submit" form="form1" class="btn btn-outline-success mb-2" name="update" value="Submit">Save and return</button> - - {% if feedback.status == feedback.NEEDS_REVIEW or feedback.status == feedback.EDITABLE %} - <button type="submit" onclick="set_accepted();" form="form1" class="btn btn-outline-success mb-2" name="update" value="Next">Accept, Save and Next</button> - {% endif %} - - {% if feedback.origin != feedback.MANUAL %} - <a href="{% url 'FeedbackDelete' feedback.slug %}" class="btn btn-outline-danger mb-2" name="delete" value="Delete">Delete auto feedback</a> - {% endif %} - - {% if feedback.status == feedback.ACCEPTED %} - <button class="btn btn-secondary mr-1 mb-2" value="Submit" disabled>View is read only</button> - {% endif %} - </div> - </div> - </form> - </div> - {# This is where all the messages pop up #} - {% include "core/component/message_box.html" %} - </div> -</div> -</div> -</div> - -{% endblock %} - -{% block script_block %} -<script> - - function set_accepted() { - $('#id_status')[0].value = {{feedback.ACCEPTED}}; - } - - $('#collapseAllOpen').click(function(){ - $('.collapse').collapse('show'); - }); - - $('#collapseAllClose').click(function(){ - $('.collapse').collapse('hide'); - }); - - {% if feedback.status != feedback.ACCEPTED %} - $('#assign_full_score').click(function(){ - $('#id_score')[0].value = {{ feedback.of_submission.type.full_score }}; - }) - {% endif %} - - // we need this one for the compiler erros readonly - var editor_pre = ace.edit("tests_editor"); - editor_pre.setOptions({ - readOnly: true, - showGutter: false, - highlightActiveLine: false, - maxLines: Infinity, - }) - - // we need this one for the sample solution readonly - var editor_solution = ace.edit("solution"); - editor_solution.getSession().setMode("ace/mode/c_cpp"); - editor_solution.setOptions({ - readOnly: true, - showGutter: false, - highlightActiveLine: false, - maxLines: Infinity, - }) - - // we need this one for the student readonly - var editor_student = ace.edit("student_text"); - editor_student.setValue(`{{feedback.of_submission.text|safe|escapejs}}`, -1); - editor_student.getSession().setMode("ace/mode/c_cpp"); - editor_student.setOptions({ - readOnly: true, - maxLines: Infinity, - }) - - // we need this one for the tutor - var editor_tutor = ace.edit("tutor_text"); - var textarea = $('textarea[id="id_text"]'); - editor_tutor.focus(); - editor_tutor.setValue(`{{feedback.text|safe|escapejs}}`, -1); - editor_tutor.getSession().setUseWrapMode(true) - editor_tutor.getSession().on("change", function () { - textarea.val(editor_tutor.getSession().getValue()); - }); - - editor_tutor.setOptions({'minLines': editor_student.getSession().getLength()}) - editor_tutor.setOptions({'maxLines': editor_student.getSession().getLength()}) - - editor_tutor.getSelection().on('changeCursor', function() { - cursor_pos_tutor = editor_tutor.getCursorPosition(); - cursor_pos_tutor.column = 0; - editor_student.getSelection().moveCursorToPosition(cursor_pos_tutor); - editor_student.getSelection().clearSelection(); - }) - - {% if feedback.status == feedback.ACCEPTED %} - editor_tutor.setOptions({ - readOnly: true, - }) - {% endif %} - -</script> -{% endblock script_block %} - diff --git a/backend/core/templates/core/index.html b/backend/core/templates/core/index.html deleted file mode 100644 index 33df8838..00000000 --- a/backend/core/templates/core/index.html +++ /dev/null @@ -1,17 +0,0 @@ -{% extends 'base.html' %} - -{% load staticfiles %} - -{% block nav_title %} Grady, Sir. Delbert Grady. {% endblock nav_title %} - -{% block body_block %} -<div class="row justify-content-center my-2"> - <div class="col-6"> - - {# This is where all the messages pop up #} - {% include "core/component/message_box.html" %} - - </div> -</div> - -{% endblock %} diff --git a/backend/core/templates/core/r/feedback_list.html b/backend/core/templates/core/r/feedback_list.html deleted file mode 100644 index d5962d95..00000000 --- a/backend/core/templates/core/r/feedback_list.html +++ /dev/null @@ -1,42 +0,0 @@ -<div class="card mb-2"> - <a data-toggle="collapse" href="#collapse{{unique}}"> - <h5 class="card-header">{{header}}</h5> - </a> - <div id="collapse{{unique}}" class="collapse {{expanded}}" role="tabpanel"> - <div class="card-block"> - <table id="list-id-{{unique}}" class="table nomargin"> - <thead> - <tr> - <th>Status</th> - <th>Submission Type</th> - <th>Student</th> - <th>Score</th> - <th>Auto feedback</th> - <th>Modified</th> - <th></th> - </tr> - </thead> - <tbody> - {% for feedback in feedback_list %} - <tr> - <td class="align-middle"> - {% include "core/component/feedback_badge.html" %} - </td> - <td class="align-middle"> {{ feedback.of_submission.type }} </td> - <td class="align-middle"> {{ feedback.of_submission.student }} </td> - <td class="align-middle"> <code> {{ feedback.score }} / {{ feedback.of_submission.type.full_score }} </code> </td> - <td class="align-middle"> {{ feedback.get_origin_display }} </td> - <td class="align-middle"> -- </td> - <td class="align-middle"> - {% if not feedback.origin == feedback.WAS_EMPTY %} - <a href="{% url 'FeedbackEdit' feedback.slug %}" class="btn btn-outline-primary mb-1" name="edit" value="View">View</a> - <a href="{% url 'FeedbackDelete' feedback.slug %}" class="btn btn-outline-danger mb-1" name="delete" value="Delete">Delete</a> - {% endif %} - </td> - </tr> - {% endfor %} - </tbody> - </table> - </div> - </div> -</div> diff --git a/backend/core/templates/core/r/progress_card.html b/backend/core/templates/core/r/progress_card.html deleted file mode 100644 index 99b20f30..00000000 --- a/backend/core/templates/core/r/progress_card.html +++ /dev/null @@ -1,24 +0,0 @@ -{# This just gives an overview about what has been done already #} -<div class="card mb-2"> - <h5 class="card-header">Progress</h5> - <table class="table nomargin"> - <thead> - <th>Name</th> - <th>Progress</th> - <th></th> - </thead> - <tbody> - {% for submission_type in submission_type_list %} - <tr> - <td class="align-middle">{{ submission_type }}</td> - <td class="align-middle" width="30%"> - <div class="progress"> - <div class="progress-bar" role="progressbar" style="width: {{submission_type.percentage}}%;"></div> - </div> - </td> - <td class="align-middle fit"><code>{{ submission_type.feedback_count }} / {{submission_type.submission_count}}</code></td> - </tr> - {% endfor %} - </tbody> - </table> -</div> diff --git a/backend/core/templates/core/r/reviewer_base.html b/backend/core/templates/core/r/reviewer_base.html deleted file mode 100644 index c79f575f..00000000 --- a/backend/core/templates/core/r/reviewer_base.html +++ /dev/null @@ -1,55 +0,0 @@ -{% extends "base.html" %} - -{% load staticfiles %} - -{% block navbar %} -<a class="nav-item nav-link" href="{% url 'start' %}">Feedback</a> -<a class="nav-item nav-link" href="{% url 'ReviewerSubmissionListView' %}">Submissions</a> -<a class="nav-item nav-link" href="{% url 'ReviewerStudentListView' %}">Students</a> -<div class="nav-item dropdown"> - <a class="nav-link dropdown-toggle" href="http://example.com" id="navbarDropdownMenuLink" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"> - Export - </a> - <div class="dropdown-menu" aria-labelledby="navbarDropdownMenuLink"> - <a class="dropdown-item" href="{% url 'export' %}">Download Results CSV</a> - </div> -</div> -{% endblock navbar %} - -{% block body_block %} -<div class="row my-3"> - <div class="col-3"> - {% block sidebar %} - {# This just gives an overview about what has been done already #} - {% include "core/r/progress_card.html" %} - - {# Only a list of tutors. Currently no controls available #} - {% include "core/r/tutor_list_card.html" %} - {% endblock sidebar %} - </div> - - <div class="col-9"> - {% block main %} - - {% endblock main %} - </div> -</div> - -{% endblock body_block %} - -{% block script_block %} -<script> - $(document).ready(function() { - $('[id^=list-id-]').DataTable({ - "paging": false, - "info": false, - "searching": false, - "stateSave": true, - "order": [[ 0, 'desc' ], [ 2, 'desc' ]], - "columnDefs": [ - { "orderable": false, "targets": -1 }, - ] - }); - }); -</script> -{% endblock script_block %} diff --git a/backend/core/templates/core/r/reviewer_startpage.html b/backend/core/templates/core/r/reviewer_startpage.html deleted file mode 100644 index 3fdb2c1f..00000000 --- a/backend/core/templates/core/r/reviewer_startpage.html +++ /dev/null @@ -1,54 +0,0 @@ -{% extends 'core/r/reviewer_base.html' %} - -{% load staticfiles %} - -{% block main %} -<div class="card mb-2"> - {% if feedback_list_manual|length == 0 %} - <h5 class="card-header">There is no feedback, yet. Maybe you have to kick some ass?</h5> - {% elif feedback_list_manual|length == 1 %} - <h5 class="card-header">Well, one is better than nothing</h5> - {% else %} - <h5 class="card-header">So far {{feedback_list_manual|length}} contributions were provided</h5> - {% endif %} - <div class="card-block"> - <table id="list-id-0" class="table nomargin"> - <thead> - <tr> - <th>Status</th> - <th>Submission Type</th> - <th>Student</th> - <th>Score</th> - <th>Tutor</th> - <th>Modified</th> - <th></th> - </tr> - </thead> - <tbody> - {% for feedback in feedback_list_manual %} - <tr> - <td class="align-middle fit"> - {% include "core/component/feedback_badge.html" %} - </td> - <td class="align-middle"> {{ feedback.of_submission.type }} </td> - <td class="align-middle"> {{ feedback.of_submission.student }} </td> - <td class="align-middle"> <code> {{ feedback.score }} / {{ feedback.of_submission.type.full_score }} </code> </td> - <td class="align-middle"> {{ feedback.of_tutor}} </td> - <td class="align-middle"> {{ feedback.modified | date:"m/d/y H:i"}} </td> - <td class="align-middle"> - <a href="{% url 'FeedbackEdit' feedback.slug %}" class="btn btn-outline-primary mb-1" name="edit" value="View">View</a> - <a href="{% url 'FeedbackDelete' feedback.slug %}" class="btn btn-outline-danger mb-1" name="delete" value="Delete">Delete</a> - </td> - </tr> - {% endfor %} - </tbody> - </table> - </div> -</div> - -{# This is card for empty feedback for the sake of completeness #} -{% include "core/r/feedback_list.html" with expanded="show" header="Did not compile feedback" unique="2" feedback_list=feedback_list_did_not_compile %} -{% include "core/r/feedback_list.html" with expanded="show" header="Could not link feedback" unique="3" feedback_list=feedback_list_could_not_link %} -{% include "core/r/feedback_list.html" with expanded="hide" header="Empty feedback" unique="1" feedback_list=feedback_list_empty %} - -{% endblock main %} diff --git a/backend/core/templates/core/r/single_submission.html b/backend/core/templates/core/r/single_submission.html deleted file mode 100644 index 59f26832..00000000 --- a/backend/core/templates/core/r/single_submission.html +++ /dev/null @@ -1,89 +0,0 @@ -{% extends "core/r/reviewer_base.html" %} - -{% block body_block %} - -{% with submission.feedback as feedback %} -<div class="row justify-content-center"> - <div class="col-3 my-4"> - <div class="card"> - <div class="card-block"> - <div class="card-header"> - Student Submission - </div> - <ul class="list-group list-group-flush"> - <li class="list-group-item"><strong class="mr-2">Submission Type: </strong> {{ submission.type }} </li> - <li class="list-group-item"><strong class="mr-2">Student: </strong> {{ submission.student }}</li> - <li class="list-group-item"> - <strong class="mr-2">Status: </strong> {% include "core/component/feedback_badge.html" %} - <span class="badge badge-warning ml-2">Only visible to reviewer</span> - </li> - <li class="list-group-item"> - <strong class="mr-2">Tutor: </strong> {{ feedback.of_tutor }} - <span class="badge badge-warning ml-2">Only visible to reviewer</span> - </li> - <li class="list-group-item"><strong class="mr-2">Score: </strong> - {% if feedback %} - <code> {{ feedback.score }} / {{submission.type.full_score}} </code> - <span class="badge badge-warning ml-2">Only visible to reviewer</span> - {% else %} - <span class="badge badge-danger">No Feedback</span> - {% endif %} - </li> - </ul> - </div> - <div class="card-footer"> - <a href="{% url 'create_feedback_for_submission' submission.slug %}" class="btn btn-success"> - {% if feedback %} - Edit Feedback - {% else %} - Create Feedback - {% endif %} - </a> - <button class="btn btn-outline-success" onclick="window.history.go(-1); return false;">Back</button> - </div> - </div> - </div> - - <div class="col-4 my-4"> - <div class="card"> - <div class="card-block"> - <div class="card-header">Student submission</div> - <div class="editor-code" id="textarea_submission">{{submission.text}}</div> - </div> - </div> - {% include "core/component/tests_editor.html" %} - </div> - - {% if feedback %} - <div class="col-4 my-4"> - <div class="card"> - <div class="card-block"> - <div class="card-header">Our feedback - {% if is_reviewer %} - <span class="badge badge-warning ml-2">Only visible to reviewer</span> - {% endif %} - </div> - <div class="editor-code" id="textarea_feedback">{{ feedback.text }}</div> - </div> - </div> - </div> - <script> - var feedback_editor = ace.edit("textarea_feedback"); - feedback_editor.setOptions({ - readOnly: true, - }) - </script> - {% endif %} -</div> -{% endwith %} -{% endblock body_block %} - - -{% block script_block %} -<script> - var submission_editor = ace.edit("textarea_submission"); - submission_editor.setOptions({ - readOnly: true, - }) -</script> -{% endblock script_block %} diff --git a/backend/core/templates/core/r/student_list.html b/backend/core/templates/core/r/student_list.html deleted file mode 100644 index 57f433f0..00000000 --- a/backend/core/templates/core/r/student_list.html +++ /dev/null @@ -1,59 +0,0 @@ -{% extends 'core/r/reviewer_base.html' %} - -{% load staticfiles %} - -{% block main %} - -<div class="card"> - <h5 class="card-header">Student Overview</h5> - <div class="card-block"> - <table id="list-id-submission_list" class="table nomargin"> - <thead class="rotate"> - <tr class="high"> - <th>Name</th> - <th>Username</th> - <th>Module</th> - {% for submission_type in submission_type_list %} - <th><font size="1">{{submission_type.name}}</font></th> - {% endfor %} - <th>Total score</th> - <th>Done</th> - </tr> - </thead> - <tbody> - {% for student in student_list %} - <tr> - <td class="fit">{{student.name}}</td> - <td>{{student.user.username}}</td> - <td>{{student.exam}}</td> - {% for sub in student.submissions.all %} - <td>{% if sub.feedback %} - <a href="{% url 'ReviewerSubmissionView' sub.slug %}" role="button" class="btn-link btn-sm"><code>{{sub.feedback.score}} / {{sub.type.full_score}}</code></a> - {% else %} - <a href="{% url 'ReviewerSubmissionView' sub.slug %}" role="button" class="btn btn-outline-primary btn-sm">View</a> - {% endif %} </td> - {% endfor %} - <td><code>{{student.overall_score}}</code></td> - <td>{% if student.done %}<span class="badge badge-success">yes</span>{% else %}<span class="badge badge-danger">no</span>{% endif %}</td> - </tr> - {% endfor %} - </tbody> - </table> - </div> -</div> - -{% endblock main %} - -{% block script_block %} -<script> - $(document).ready(function() { - $('[id^=list-id-]').DataTable({ - "paging": false, - "info": false, - "searching": false, - "stateSave": true, - "order": [[ 0, 'desc' ]], - }); - }); -</script> -{% endblock script_block %} diff --git a/backend/core/templates/core/r/student_submission_list.html b/backend/core/templates/core/r/student_submission_list.html deleted file mode 100644 index 484bdd8e..00000000 --- a/backend/core/templates/core/r/student_submission_list.html +++ /dev/null @@ -1,58 +0,0 @@ -{% extends 'core/r/reviewer_base.html' %} - -{% load staticfiles %} - -{% block main %} - -<div class="card"> - <h5 class="card-header">All student submissions</h5> - <div class="card-block"> - <table id="list-id-submission_list" class="table nomargin"> - <thead> - <tr> - <th></th> - <th>Task</th> - <th>Student</th> - <th>Score</th> - <th>Tutor</th> - <th></th> - </tr> - </thead> - <tbody> - {% for submission in submission_list %} - <tr> - <td class="align-middle fit"> <a href="{% url 'ReviewerSubmissionView' submission.slug %}" class="btn btn-outline-primary mb-1" name="edit" value="View">View submission</a></td> - <td class="align-middle"> {{ submission.type }} </td> - <td class="align-middle"> {{ submission.student }} </td> - <td class="align-middle fit"> - {% if submission.feedback %} - <code> {{ submission.feedback.score }} / {{ submission.type.full_score }} </code> - {% else %} - <code> no feedback </code> - {% endif %} - </td> - <td class="align-middle"> - {% if submission.feedback %} - {{submission.feedback.of_tutor}} - {% endif %} - </td> - <td class="align-middle fit"> - {% if submission.feedback %} - {% if submission.feedback.origin == submission.feedback.WAS_EMPTY %} - <button type="button" class="btn btn-secondary" disabled>was empty</button> - {% else %} - <a href="{% url 'FeedbackEdit' submission.feedback.slug %}" class="btn btn-outline-primary" name="edit" value="View">Edit Feedback</a> - <a href="{% url 'FeedbackDelete' submission.feedback.slug %}" class="btn btn-outline-danger" name="delete" value="Delete">Delete Feedback</a> - {% endif %} - {% else %} - <a href="{% url 'create_feedback_for_submission' submission.slug %}" class="btn btn-outline-success"> Create Feedback </a> - {% endif %} - </td> - </tr> - {% endfor %} - </tbody> - </table> - </div> -</div> - -{% endblock main %} diff --git a/backend/core/templates/core/r/tutor_list_card.html b/backend/core/templates/core/r/tutor_list_card.html deleted file mode 100644 index 455927dc..00000000 --- a/backend/core/templates/core/r/tutor_list_card.html +++ /dev/null @@ -1,19 +0,0 @@ -<div class="card mb-2"> - <h5 class="card-header">Tutor overview</h5> - <div class="card-block"> - <table class="table nomargin"> - <thead> - <th>Tutor</th> - <th># of feedbacks</th> - </thead> - {% for tutor in tutor_list %} - <tbody> - <tr> - <td>{{tutor.username}}</td> - <td><code>{{tutor.feedback_list__count}}</code></td> - </tr> - </tbody> - {% endfor %} - </table> - </div> -</div> diff --git a/backend/core/templates/core/s/single_submission.html b/backend/core/templates/core/s/single_submission.html deleted file mode 100644 index cf08272e..00000000 --- a/backend/core/templates/core/s/single_submission.html +++ /dev/null @@ -1,74 +0,0 @@ -{% extends "base.html" %} - -{% block nav_title %} Student Exam View {% endblock nav_title %} - -{% block body_block %} - -{% with submission.feedback as feedback %} -<div class="row justify-content-center"> - <div class="col-3 my-4"> - <div class="card"> - <div class="card-block"> - <div class="card-header"> - Student Submission - </div> - <ul class="list-group list-group-flush"> - <li class="list-group-item"><strong class="mr-2">Submission Type: </strong> {{ submission.type }} </li> - <li class="list-group-item"><strong class="mr-2">Student: </strong> {{ submission.student }}</li> - <li class="list-group-item"><strong class="mr-2">Score: </strong> - {% if feedback and feedback.status == feedback.ACCEPTED %} - <code> {{ feedback.score }} / {{submission.type.full_score}} </code> - {% else %} - <span class="badge badge-danger">No Feedback</span> - {% endif %} - </li> - </ul> - </div> - <div class="card-footer"> - <a href="{% url 'start' %}" class="btn btn-success">Back</a> - </div> - </div> - </div> - - <div class="col-4 my-4"> - <div class="card"> - <div class="card-block"> - <div class="card-header">Your submission</div> - <div class="editor-code" id="textarea_submission">{{submission.text}}</div> - </div> - </div> - {% include "core/component/tests_editor.html" %} - </div> - - {% if feedback %} - {% if feedback.status == feedback.ACCEPTED %} - <div class="col-4 my-4"> - <div class="card"> - <div class="card-block"> - <div class="card-header">Our feedback - </div> - <div class="editor-code" id="textarea_feedback">{{ feedback.text }}</div> - </div> - </div> - </div> - <script> - var feedback_editor = ace.edit("textarea_feedback"); - feedback_editor.setOptions({ - readOnly: true, - }) - </script> - {% endif %} - {% endif %} -</div> -{% endwith %} -{% endblock body_block %} - - -{% block script_block %} -<script> - var submission_editor = ace.edit("textarea_submission"); - submission_editor.setOptions({ - readOnly: true, - }) -</script> -{% endblock script_block %} diff --git a/backend/core/templates/core/s/student_startpage.html b/backend/core/templates/core/s/student_startpage.html deleted file mode 100644 index cd016dd7..00000000 --- a/backend/core/templates/core/s/student_startpage.html +++ /dev/null @@ -1,48 +0,0 @@ -{% extends 'base.html' %} - -{% load staticfiles %} - -{% block navbar %} Student Exam View {% endblock navbar %} - -{% block body_block %} -<div class="row justify-content-center"> - <div class="col-6"> - <div class="row my-3"> - <h2>Submissions of {{ student.name }}</h2> - </div> - - <div class="row my-2"> - <table class="table"> - <thead> - <th></th> - <th>Submission Type</th> - <th>Score</th> - <th></th> - </thead> - <tbody> - {% for submission in student.submissions.all %} - <tr class="align-middle"> - <td class="align-middle"> - {% if submission.seen_by_student %} - <span class="badge badge-success">Seen</span> - {% endif %} - </td> - <td class="align-middle">{{ submission.type }}</td> - <td class="align-middle"> - {% with submission.feedback as feedback %} - {% if feedback and feedback.status == feedback.ACCEPTED %} - <code> {{ feedback.score }} / {{submission.type.full_score}} </code> - {% else %} - <span class="badge badge-danger">No Feedback</span> - {% endif %} - {% endwith %} - </td> - <td class="align-middle"><a class="btn btn-primary" href="{% url 'StudentSubmissionView' submission.slug %}">View</a></td> - </tr> - {% endfor %} - </tbody> - </table> - </div> - </div> -</div> -{% endblock body_block %} diff --git a/backend/core/templates/core/t/tutor_startpage.html b/backend/core/templates/core/t/tutor_startpage.html deleted file mode 100644 index 52836ebf..00000000 --- a/backend/core/templates/core/t/tutor_startpage.html +++ /dev/null @@ -1,130 +0,0 @@ -{% extends 'base.html' %} - -{% load staticfiles %} - -{% block navbar %} Ready for an exam, commander? {% endblock navbar %} - -{% block body_block %} - -<div class="row justify-content-center my-3"> - <div class="col-5 nopadding"> - - {# This is a control panel where new work can be requested #} - <div class="card mb-2"> - <h4 class="card-header">Overview</h4> - <table class="table nomargin"> - <thead> - <th></th> - <th>Name</th> - <th>Progress</th> - <th></th> - </thead> - <tbody> - {% for submission_type in submission_type_list %} - <tr> - <td class="align-middle"><a role="button" class="btn btn-secondary {% if submission_type.percentage == 100 %}disabled{% endif %}" href="{% url 'CreateFeedbackForType' submission_type.slug %}">Get</a></td> - <td class="align-middle fit">{{ submission_type }}</td> - <td class="align-middle" width="70%"> - <div class="progress"> - <div class="progress-bar" role="progressbar" style="width: {{submission_type.percentage}}%;"></div> - </div> - </td> - <td class="align-middle fit"><code>{{ submission_type.feedback_count }} / {{submission_type.submission_count}}</code></td> - </tr> - {% endfor %} - </tbody> - </table> - <table class="table nomargin"> - <tbody> - <tr> - <td class="fit"><strong>Your contribution:</strong></td> - <td colspan="6"><code>{% if tutor.feedback_list.all|length > 0 %} {{tutor.feedback_list.all|length}} {% else %} None. Sad. {% endif %}</code></td> - </tr> - </tbody> - </table> - <div class="card-footer text-muted"> - <a role="button" class="btn btn-outline-danger" href="{% url 'CreateFeedback' %}">Just give me anything</a> - </div> - </div> - - {# Open feedback will be displayed here #} - {% if feedback_open_list %} - <div class="card mb-2"> - <h4 class="card-header">Open Feedback</h4> - <table class="table nomargin"> - <thead> - <th>Task</th> - <th>Tutor</th> - <th></th> - </thead> - <tbody> - {% for feedback in feedback_open_list %} - <tr> - <td class="align-middle"> {{ feedback.of_submission.type }} </td> - <td class="align-middle"> {{ feedback.of_tutor }} </td> - <td class="align-middle"><a class="btn btn-secondary" href="{% url 'FeedbackEdit' feedback.slug %}"> Assign </a></td> - </tr> - {% endfor %} - </tbody> - </table> - </div> - {% endif %} - - {# This is where all the messages pop up #} - {% include "core/component/message_box.html" %} - - </div> - <div class="col-6"> - {# The big table where the tutor can see what s/he actually did #} - <div class="row-auto nomargin justify-content-center"> - <table id="list-id-tutoren" class="table"> - <thead> - <tr> - <th>Status</th> - <th>Submission Type</th> - <th>Score</th> - <th>Modified</th> - <th></th> - </tr> - </thead> - <tbody> - {% for feedback in tutor.feedback_list.all %} - <tr> - <td> - {% include "core/component/feedback_badge.html" %} - </td> - <td> {{ feedback.of_submission.type }} </td> - <td> <code> {{ feedback.score }} / {{feedback.of_submission.type.full_score}} </code> </td> - <td> {{ feedback.modified | date:"H:i"}} </td> - <td> - {% if feedback.status == feedback.ACCEPTED %} - <a class="btn btn-secondary" href="{% url 'FeedbackEdit' feedback.slug %}"> View </a> - {% else %} - <a class="btn btn-primary" href="{% url 'FeedbackEdit' feedback.slug %}"> Edit </a> - {% endif %} - </td> - </tr> - {% endfor %} - </tbody> - </table> - </div> - </div> -</div> -{% endblock body_block %} - -{% block script_block %} -<script> - $(document).ready(function() { - $('#list-id-tutoren').DataTable({ - "paging": false, - "info": false, - "searching": false, - "stateSave": true, - "order": [[ 0, 'desc' ], [ 3, 'desc' ]], - "columnDefs": [ - { "orderable": false, "targets": -1 }, - ] - }); - }); -</script> -{% endblock script_block %} diff --git a/backend/core/urls.py b/backend/core/urls.py index 03583481..15e51de8 100644 --- a/backend/core/urls.py +++ b/backend/core/urls.py @@ -1,34 +1,16 @@ from django.conf.urls import url from django.contrib.staticfiles.urls import staticfiles_urlpatterns +from rest_framework.urlpatterns import format_suffix_patterns from core import views urlpatterns = [ - url(r'^$', views.IndexView.as_view(), name='index'), - url(r'^login/$', views.Login.as_view(), name='login'), - url(r'^logout/$', views.Logout.as_view(), name='logout'), - url(r'^start/$', views.user_home, name='start'), - - url(r'^feedback/create/$', views.create_feedback, name='CreateFeedback'), - url(r'^feedback/create/(?P<type_slug>\w+)/$', views.create_feedback, name='CreateFeedbackForType'), - url(r'^feedback/edit/(?P<feedback_slug>\w+)/$', views.FeedbackEdit.as_view(), name='FeedbackEdit'), - url(r'^feedback/delete/(?P<feedback_slug>\w+)/$', views.delete_feedback, name='FeedbackDelete'), - - url(r'^r/student/list/$', views.ReviewerStudentListView.as_view(), name='ReviewerStudentListView'), - url(r'^r/submission/list/$', views.ReviewerSubmissionListView.as_view(), name='ReviewerSubmissionListView'), - url(r'^r/submission/view/(?P<slug>\w+)/$', views.ReviewerSubmissionView.as_view(), name='ReviewerSubmissionView'), - url(r'^r/submission/create-feedback-for/(?P<slug>\w+)/$', views.create_feedback_for_submission, name='create_feedback_for_submission'), - url(r'^r/submission/download/(?P<slug>\w+)/$', views.download_submissions, name='download_submissions'), - - url(r'^s/submission/view/(?P<slug>\w+)/$', views.StudentSubmissionView.as_view(), name='StudentSubmissionView'), - - url(r'^csv/$', views.export_csv, name='export'), - url(r'^api/student/$', views.StudentApiView.as_view()), url(r'^api/submission/$', views.SubmissionApiView.as_view()), url(r'^api/feedback/$', views.FeedbackApiView.as_view()), ] urlpatterns += staticfiles_urlpatterns() +urlpatterns = format_suffix_patterns(urlpatterns, allowed=['json', 'html']) diff --git a/backend/core/views/__init__.py b/backend/core/views/__init__.py deleted file mode 100644 index a38f0ce2..00000000 --- a/backend/core/views/__init__.py +++ /dev/null @@ -1,10 +0,0 @@ -from .login import * -from .feedback import * -from .generics import * - -from .submission import * -from .user_startpages import * -from .index import * -from .export_csv import * - -from .api import * diff --git a/backend/core/views/export_csv.py b/backend/core/views/export_csv.py deleted file mode 100644 index 1e1a7fdd..00000000 --- a/backend/core/views/export_csv.py +++ /dev/null @@ -1,28 +0,0 @@ -import csv - -from django.http import HttpResponse - -from core.custom_annotations import group_required -from core.models import Student, SubmissionType - - -@group_required('Reviewers') -def export_csv(request): - # Create the HttpResponse object with the appropriate CSV header. - response = HttpResponse(content_type='text/csv') - response['Content-Disposition'] = 'attachment; filename="grady_results.csv"' - - writer = csv.writer(response) - writer.writerow(['Matrikel', 'Username', 'Name', 'Sum'] + - [s.name for s in SubmissionType.objects.all().order_by('name')]) - - for student in Student.get_overall_score_annotated_submission_list(): - writer.writerow([ - student.matrikel_no, - student.user.username, - student.name, - student.overall_score, - *student.score_per_submission().values() - ]) - - return response diff --git a/backend/core/views/feedback.py b/backend/core/views/feedback.py deleted file mode 100644 index db95a26d..00000000 --- a/backend/core/views/feedback.py +++ /dev/null @@ -1,134 +0,0 @@ -from random import choice - -from django.contrib import messages -from django.http import Http404, HttpResponse, HttpResponseRedirect -from django.urls import reverse -from django.utils.decorators import method_decorator -from django.views.generic.edit import UpdateView - -from core.custom_annotations import group_required, in_groups -from core.forms import FeedbackForm -from core.grady_speak import grady_says -from core.models import Feedback, Submission, SubmissionType - - -@group_required('Tutors') -def create_feedback(request, type_slug=None): - # assign does nothing if tutor has unfinished feedback - assigned = Submission.assign_tutor(request.user, type_slug) - feedback = Feedback.tutor_unfinished_feedback(request.user) - if not feedback: - if type_slug: - messages.info(request, "No more submissions of type '%s' available." % - SubmissionType.objects.get(slug=type_slug)) - else: - messages.success( - request, "Well done! There is no more work to do.") - return HttpResponseRedirect(reverse('start')) - elif not assigned: - messages.info( - request, "You have got unfinished business. Please finish this task first.") - return HttpResponseRedirect(reverse('FeedbackEdit', args=(feedback.slug,))) - - -@group_required('Reviewers') -def create_feedback_for_submission(request, slug): - - submission = Submission.objects.get(slug=slug) - - if not hasattr(submission, 'feedback'): - submission.feedback = Feedback() - - submission.feedback.of_reviewer = request.user - submission.feedback.of_tutor = request.user - submission.feedback.of_submission = submission - - submission.feedback.save() - submission.save() - - return HttpResponseRedirect(reverse('FeedbackEdit', args=(submission.feedback.slug,))) - - -@group_required('Reviewers') -def delete_feedback(request, feedback_slug): - """ Hook to ensure object is owned by request.user. """ - instance = Feedback.objects.get(slug=feedback_slug) - instance.delete() - return HttpResponseRedirect(reverse('start')) - - -class FeedbackEdit(UpdateView): - - """docstring for FeedbackCreate""" - - form_class = FeedbackForm - template_name = 'core/feedback_form.html' - success_url = '/start/' - - @method_decorator(group_required('Tutors', 'Reviewers')) - def dispatch(self, *args, **kwargs): - return super(FeedbackEdit, self).dispatch(*args, **kwargs) - - def get_object(self): - instance = Feedback.objects.get(slug=self.kwargs['feedback_slug']) - if instance.of_tutor == self.request.user or in_groups(self.request.user, ('Reviewers', )): - return instance - elif instance.status == Feedback.OPEN: - instance.reassign_to_tutor(self.request.user) - return instance - elif not (instance.of_tutor == self.request.user or in_groups(self.request.user, ('Reviewers', ))): - messages.error( - self.request, "Get your hands of somebody else's feedback!") - raise Http404 - - def form_valid(self, form): - """ - If the form is valid, redirect to the supplied URL. - """ - if form.is_valid(): - form.instance.text = self.request.POST['text'] - if form.instance.status == Feedback.ACCEPTED: - form.instance.finalize_feedback(self.request.user) - else: - form.instance.unfinalize_feedback() - - # ugly needs patch - if 'Next' in self.request.POST['update']: - if in_groups(self.request.user, ('Reviewers',)): - - needs_review = Feedback.objects.filter( - status=Feedback.NEEDS_REVIEW, - of_submission__type=form.instance.of_submission.type - ) - - if needs_review: - return HttpResponseRedirect(reverse('FeedbackEdit', args=(needs_review[0].slug,))) - - else: # in_groups(self.request.user, ('Tutor',)): - return HttpResponseRedirect(reverse('CreateFeedbackForType', args=(form.instance.of_submission.type.slug,))) - - elif 'Save' in self.request.POST['update']: - return HttpResponseRedirect(reverse('FeedbackEdit', args=(form.instance.slug,))) - - return HttpResponseRedirect(self.get_success_url()) - - def get_context_data(self, **kwargs): - context = super(FeedbackEdit, self).get_context_data(**kwargs) - context['grady_says'] = choice(grady_says) - return context - - -@group_required('Reviewers', 'Tutors') -def download_submissions(request, slug): - submission = Submission.objects.get(slug=slug) - - if not (submission.feedback.of_tutor == request.user or in_groups(request.user, ('Reviewers', ))): - messages.error(request, "Get your hands of somebody else's feedback!") - return HttpResponseRedirect(reverse('start')) - - response = HttpResponse(content_type='text/plain') - response['Content-Disposition'] = 'attachment; filename="%s_%s.c"' % ( - submission.type.name, submission.slug) - response.write(submission.text) - - return response diff --git a/backend/core/views/generics.py b/backend/core/views/generics.py deleted file mode 100644 index 6afd8c67..00000000 --- a/backend/core/views/generics.py +++ /dev/null @@ -1,58 +0,0 @@ -from django.utils.decorators import method_decorator -from django.views.generic import DetailView, ListView, View - -from core.custom_annotations import group_required -from core.models import SubmissionType, get_annotated_tutor_list - - -class StudentView(View): - - @method_decorator(group_required('Students',)) - def dispatch(self, *args, **kwargs): - return super().dispatch(*args, **kwargs) - - -class StudentListView(StudentView, ListView): - pass - - -class StudentDetailView(StudentView, DetailView): - pass - - -class TutorView(View): - - @method_decorator(group_required('Tutors',)) - def dispatch(self, *args, **kwargs): - return super().dispatch(*args, **kwargs) - - -class TutorListView(TutorView, ListView): - pass - - -class TutorDetailView(TutorView, DetailView): - pass - - -class ReviewerView(View): - - @method_decorator(group_required('Reviewers',)) - def dispatch(self, *args, **kwargs): - return super().dispatch(*args, **kwargs) - - -class ReviewerListView(ReviewerView, ListView): - - def get_context_data(self, **kwargs): - context = super().get_context_data(**kwargs) - - return { - 'submission_type_list': SubmissionType.get_annotated_feedback_count(), - 'tutor_list': get_annotated_tutor_list(), - **context, - } - - -class ReviewerDetailView(ReviewerView, DetailView): - pass diff --git a/backend/core/views/index.py b/backend/core/views/index.py deleted file mode 100644 index 24fa020f..00000000 --- a/backend/core/views/index.py +++ /dev/null @@ -1,5 +0,0 @@ -from django.views.generic import TemplateView - - -class IndexView(TemplateView): - template_name = 'core/index.html' diff --git a/backend/core/views/login.py b/backend/core/views/login.py deleted file mode 100644 index 33243ef7..00000000 --- a/backend/core/views/login.py +++ /dev/null @@ -1,64 +0,0 @@ -from django.contrib import messages -from django.contrib.auth import authenticate, login -from django.contrib.auth.views import LoginView, LogoutView -from django.http import HttpResponseRedirect -from django.urls import reverse, reverse_lazy - -from core.custom_annotations import in_groups - - -def is_student(user): - return in_groups(user, ('Students',)) - -def is_deactivated_student(user) -> bool: - """Checks if the user is linked to a student and if the field user - has_logged_in is True or not. Obviously a superuser should not be a student. - - Args: - user (User object): The original user of some request. - - Returns: - bool: True if user is a student and has already logged in - """ - if user.is_superuser: - return False - - if in_groups(user, ('Students',)): - return user.student.has_logged_in - -class Login(LoginView): - - success_url = reverse_lazy('start') - template_name = 'core/index.html' - - def get(self, request): - return HttpResponseRedirect(reverse('index')) - - def form_valid(self, form): - username = form.cleaned_data['username'] - password = form.cleaned_data['password'] - - user = authenticate(username=username, password=password) - - if user is not None and user.is_active and not is_deactivated_student(user): - login(self.request, user) - - # disable the user if s/he is a student - if is_student(user) and not user.is_superuser: - user.student.disable() - - print(self.get_success_url()) - return HttpResponseRedirect(self.get_success_url()) - - # Handle all the errors separately - if is_deactivated_student(user) or not user.is_active: - messages.warning(self.request, "Your Grady account has been deactivated.") - elif not user: - # Bad login details were provided. So we can't log the user in. - print("Invalid login details: {0}, {1}".format(username, password)) - messages.error(self.request, "Invalid login details supplied.") - - return super().form_invalid(form) - -class Logout(LogoutView): - next_page = reverse_lazy('index') diff --git a/backend/core/views/submission.py b/backend/core/views/submission.py deleted file mode 100644 index 8d7eff78..00000000 --- a/backend/core/views/submission.py +++ /dev/null @@ -1,45 +0,0 @@ -from django.views.generic import DetailView - -from core.custom_annotations import in_groups -from core.models import Feedback, Student, Submission -from core.views.generics import (ReviewerDetailView, ReviewerListView, - StudentView) - - -class StudentSubmissionView(StudentView, DetailView): - - template_name = 'core/s/single_submission.html' - model = Submission - - def get_object(self): - obj = Submission.objects.get(slug=self.kwargs['slug']) - if in_groups(self.request.user, ('Students', )) and hasattr(obj, 'feedback') and obj.feedback.status == Feedback.ACCEPTED: - obj.seen_by_student = True - obj.save() - return obj - - -class ReviewerSubmissionView(ReviewerDetailView): - - model = Submission - template_name = 'core/r/single_submission.html' - - def get_object(self): - return Submission.objects.get(slug=self.kwargs['slug']) - - -class ReviewerSubmissionListView(ReviewerListView): - - model = Submission - template_name = 'core/r/student_submission_list.html' - context_object_name = 'submission_list' - - -class ReviewerStudentListView(ReviewerListView): - - model = Student - template_name = 'core/r/student_list.html' - context_object_name = 'student_list' - - def get_queryset(self): - return self.model.get_overall_score_annotated_submission_list() diff --git a/backend/core/views/user_startpages.py b/backend/core/views/user_startpages.py deleted file mode 100644 index 9d1ae980..00000000 --- a/backend/core/views/user_startpages.py +++ /dev/null @@ -1,67 +0,0 @@ -from django.contrib.auth.decorators import login_required -from django.contrib.auth.models import User -from django.http import HttpResponseRedirect -from django.urls import reverse - -from core.custom_annotations import in_groups -from core.models import Feedback, Student, SubmissionType -from core.views.generics import (ReviewerListView, StudentDetailView, - TutorDetailView) - - -@login_required(login_url='/') -def user_home(request): - if in_groups(request.user, ('Students', )): - return StudentStartPage.as_view()(request) - elif in_groups(request.user, ('Tutors', )): - return TutorStartPage.as_view()(request) - elif in_groups(request.user, ('Reviewers', )): - return ReviewerFeedbackListView.as_view()(request) - else: - return HttpResponseRedirect(reverse('index')) - - -class TutorStartPage(TutorDetailView): - - model = User - template_name = 'core/t/tutor_startpage.html' - context_object_name = 'tutor' - - def get_object(self): - return self.request.user - - def get_context_data(self, **kwargs): - context = super().get_context_data(**kwargs) - - return { - 'submission_type_list': SubmissionType.get_annotated_feedback_count(), - 'feedback_open_list': Feedback.get_open_feedback(self.get_object()), - **context - } - - -class StudentStartPage(StudentDetailView): - - model = Student - template_name = 'core/s/student_startpage.html' - - def get_object(self): - return self.request.user.student - - -class ReviewerFeedbackListView(ReviewerListView): - """ This is the de facto startpage of the reviewer accounts""" - - model = Feedback - template_name = 'core/r/reviewer_startpage.html' - - def get_context_data(self, **kwargs): - context = super().get_context_data(**kwargs) - - return { - 'feedback_list_manual': self.model.objects.filter(origin=Feedback.MANUAL), - 'feedback_list_empty': self.model.objects.filter(origin=Feedback.WAS_EMPTY), - 'feedback_list_did_not_compile': self.model.objects.filter(origin=Feedback.DID_NOT_COMPILE), - 'feedback_list_could_not_link': self.model.objects.filter(origin=Feedback.COULD_NOT_LINK), - **context - } -- GitLab