diff --git a/backend/core/fixtures/testdata-core.json b/backend/core/fixtures/testdata-core.json deleted file mode 100644 index 28b9bea58d4a332e87c9e0c4b7dc97402a89daea..0000000000000000000000000000000000000000 --- 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 e0c5e95cad7a721f77dcb33e8aab4d2e61deac9d..0000000000000000000000000000000000000000 --- 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 34cf27c2acc807ae2223d5c3dbe77373daa68d61..0000000000000000000000000000000000000000 --- 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 766cf783951d4692af986f8786f9e9c45ded71f6..0000000000000000000000000000000000000000 --- 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 8e2e7f1cd81a4773dae66f4408bf3a3e7640ccb9..0000000000000000000000000000000000000000 --- 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 Binary files a/backend/core/static/res/brand.png and /dev/null differ diff --git a/backend/core/templates/base.html b/backend/core/templates/base.html deleted file mode 100644 index 90c2d78effe791d50722744df82e8a3f328e4396..0000000000000000000000000000000000000000 --- 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 724f0ec9e605bc5b15f402036ebec2c9b649a2b7..0000000000000000000000000000000000000000 --- 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 e5a8917d6f64e87ac5e51557ed5ed2c36c12fccb..0000000000000000000000000000000000000000 --- 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 8bef55250c2a2720e48117eadf43786da67c4b4d..0000000000000000000000000000000000000000 --- 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 362397783a8d19310265168dee86069754c1aa49..0000000000000000000000000000000000000000 --- 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 601aa89b6a881f939fc29b0aab08d994f2f4a283..0000000000000000000000000000000000000000 --- 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 33df883846dcb4182cd4dbb2706f19ec1ae39847..0000000000000000000000000000000000000000 --- 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 d5962d95766d4cf3d2a18b41c7800aabd34c9fa3..0000000000000000000000000000000000000000 --- 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 99b20f301e42d1a07610106083903d1accb09ecc..0000000000000000000000000000000000000000 --- 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 c79f575f6e3321ba897604d6c1dd143394a65e58..0000000000000000000000000000000000000000 --- 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 3fdb2c1f378ee45949b1899d6615d355c0812b84..0000000000000000000000000000000000000000 --- 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 59f26832868b3da5e9b84b151cd713c043dabea7..0000000000000000000000000000000000000000 --- 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 57f433f05720ecc6e29f96ea93772ad86635c508..0000000000000000000000000000000000000000 --- 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 484bdd8e06323d57ae8256cd09ad8ef8f53fe145..0000000000000000000000000000000000000000 --- 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 455927dc5cb645f7150f0bca91d4a60e9d3b6b0e..0000000000000000000000000000000000000000 --- 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 cf08272e7c32364a1e96e5c3a246bd59ba0b48d7..0000000000000000000000000000000000000000 --- 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 cd016dd7f5b03e445b895b4b2149f082118e580c..0000000000000000000000000000000000000000 --- 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 52836ebf0bb4bb65d215a602108ca300b513f097..0000000000000000000000000000000000000000 --- 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 035834813224f49645ba55c1a4321003deea8709..15e51de8e805eb003811ad07d1ae463371d4df39 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 a38f0ce24b8b4117e4412455222661049ff0ebdd..0000000000000000000000000000000000000000 --- 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 1e1a7fdd12d212085b0f36a0bef223019bdd2106..0000000000000000000000000000000000000000 --- 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 db95a26d8457c2286f871350787b1fa5846f4b9b..0000000000000000000000000000000000000000 --- 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 6afd8c675c3dc4707226755f5d773e2852fedf20..0000000000000000000000000000000000000000 --- 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 24fa020f9d7cdd698d48b20319976b9ecab68a96..0000000000000000000000000000000000000000 --- 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 33243ef7a1b167e27b89f76e0514ed5d7b20f31b..0000000000000000000000000000000000000000 --- 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 8d7eff78bfe5f9a5572f091d1c2284826a87916d..0000000000000000000000000000000000000000 --- 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 9d1ae9803b5204044d8e9825b28a45b4dd3d78b1..0000000000000000000000000000000000000000 --- 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 - }