Skip to content
Snippets Groups Projects
Commit c1437256 authored by Jan Maximilian Michal's avatar Jan Maximilian Michal
Browse files

Removed status model and fixed student final bug

parent f6f90f03
No related branches found
No related tags found
No related merge requests found
......@@ -19,3 +19,4 @@ tests/report/
db.sqlite3
env-grady/
.DS_Store
reinit.sh
from django.contrib import admin
from .models import (Feedback, Student, Submission, SubmissionStatus,
SubmissionType)
from .models import (Feedback, Student, Submission, SubmissionType)
# Register your models here.
......@@ -9,4 +8,3 @@ admin.site.register(SubmissionType)
admin.site.register(Feedback)
admin.site.register(Student)
admin.site.register(Submission)
admin.site.register(SubmissionStatus)
from django.forms import (CharField, HiddenInput, IntegerField, ModelForm,
NumberInput, Textarea, ValidationError)
from django.forms import (
CharField,
HiddenInput,
ModelForm,
Textarea,
ValidationError
)
from core.models import Feedback
#<textarea cols="40" id="id_text" name="text" rows="10" required=""></textarea>
#<input id="id_score" min="0" name="score" type="number" value="0" required="">
#form-control
class FeedbackForm(ModelForm):
text = CharField(
widget=Textarea(
......
grady_says = [
"Now let's see if we can improve this with a little water, sir.",
"Won't keep you a moment, sir.",
"Grady, sir. Delbert Grady.",
"Yes, sir.",
"That's right, sir.",
"Why no, sir. I don't believe so.",
"Ah ha, it's coming off now, sir.",
"Why no, sir. I don't believe so.",
"Yes, sir. I have a wife and two daughters, sir.",
"Oh, they're somewhere around. I'm not quite sure at the moment, sir.",
"That's strange, sir. I don't haveany recollection of that at all.",
"I'm sorry to differ with you, sir, but you are the caretaker.",
"You have always been the caretaker, I should know, sir.",
"I've always been here.",
"Indeed, he is, Mr. Torrance. Avery willful boy. ",
"A rather naughty boy, if I may be so bold, sir.",
"Perhaps they need a good talking to, if you don't mind my saying so. Perhaps a bit more.",
"My girls, sir, they didn't care for the Overlook at first.",
"One of them actually stole a packet of matches and tried to burn it down.",
"But I corrected them, sir.",
"And when my wife tried to prevent me from doing my duty... so I corrected her.",
]
# -*- coding: utf-8 -*-
# Generated by Django 1.10.6 on 2017-03-21 21:28
from __future__ import unicode_literals
import core.models
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('core', '0032_auto_20170315_1609'),
]
operations = [
migrations.AddField(
model_name='submissiontype',
name='slug',
field=models.SlugField(default=core.models.random_slug, editable=False, unique=True),
),
migrations.AlterField(
model_name='feedback',
name='slug',
field=models.SlugField(default=core.models.random_slug, editable=False, unique=True),
),
migrations.AlterField(
model_name='submission',
name='slug',
field=models.SlugField(default=core.models.random_slug, editable=False, unique=True),
),
]
# -*- coding: utf-8 -*-
# Generated by Django 1.10.6 on 2017-03-22 13:04
from __future__ import unicode_literals
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('core', '0033_auto_20170321_2128'),
]
operations = [
migrations.RemoveField(
model_name='submission',
name='status',
),
migrations.DeleteModel(
name='SubmissionStatus',
),
]
......@@ -2,9 +2,10 @@ from random import sample
from string import ascii_lowercase
from django.contrib.auth.models import User
from django.db.models import Count
from django.db import models
MAX_FEEDBACK_PER_SUBMISSION = 3
MAX_FEEDBACK_PER_SUBMISSION = 1
SLUG_LENGTH = 16
......@@ -16,6 +17,7 @@ class SubmissionType(models.Model):
# Fields
name = models.CharField(max_length=50)
slug = models.SlugField(editable=False, unique=True, default=random_slug)
full_score = models.PositiveIntegerField(default=0)
task_description = models.TextField()
possible_solution = models.TextField()
......@@ -50,17 +52,13 @@ class Submission(models.Model):
# Fields
slug = models.SlugField(editable=False, unique=True, default=random_slug)
# This indicates that the student has seen his feedback
seen = models.BooleanField(default=False)
type = models.ForeignKey(
SubmissionType,
related_name='submissions'
)
status = models.OneToOneField(
'SubmissionStatus',
null=True, editable=False,
related_name='submission',
on_delete=models.CASCADE
)
text = models.TextField()
pre_corrections = models.TextField(blank=True)
final_feedback = models.OneToOneField('Feedback', null=True, blank=True)
......@@ -70,10 +68,6 @@ class Submission(models.Model):
verbose_name = "Submission"
verbose_name_plural = "Submission Set"
def save(self, *args, **kwargs):
self.status = SubmissionStatus.objects.create()
super(Submission, self).save(*args, **kwargs)
def __str__(self):
return "Submission of type '{}' from Student '{}'".format(
self.type,
......@@ -87,7 +81,7 @@ class Submission(models.Model):
return self.feedback_counter() == MAX_FEEDBACK_PER_SUBMISSION
@classmethod
def assign_tutor(cls, tutor):
def assign_tutor(cls, tutor, type_slug=None):
"""Assigns a tutor to a submission
A submission is not assigned to the specified tutor in the case
......@@ -103,49 +97,24 @@ class Submission(models.Model):
if unfinished:
return
ready = cls.objects.filter(status__status=SubmissionStatus.READY)
ready = cls.objects.annotate(Count('feedback_list')).filter(
feedback_list__count__lt=MAX_FEEDBACK_PER_SUBMISSION
)
# we do not want this tutor to correct the same submission twice
if type_slug:
ready = cls.objects.filter(type__slug=type_slug)
ready = ready.exclude(feedback_list__of_tutor=tutor)
if not ready:
return
submission = ready[0]
feedback = Feedback()
feedback.of_tutor = tutor
feedback.of_submission = submission
feedback.save()
# set the status to in progress
if submission.feedback_counter() == MAX_FEEDBACK_PER_SUBMISSION:
submission.status.status = SubmissionStatus.LIMIT_REACHED
submission.status.save()
class SubmissionStatus(models.Model):
READY, LIMIT_REACHED = range(2)
STATUS = (
(READY, 'READY'),
(LIMIT_REACHED, 'LIMIT_REACHED'),
)
# Fields
status = models.PositiveIntegerField(
choices=STATUS,
default=READY,
)
class Meta:
verbose_name = "Submission Status"
verbose_name_plural = "SubmissionStatus Set"
def __str__(self):
return "Status is {} - Count is {}".format(
self.status,
self.submission.feedback_counter()
)
class Feedback(models.Model):
# Fields
text = models.TextField()
......@@ -217,6 +186,7 @@ class Feedback(models.Model):
Arguments:
user {[type]} -- [description]
"""
self.empty = False
self.final = True
self.of_reviewer = user
self.of_submission.final_feedback = self
......@@ -234,6 +204,3 @@ class Feedback(models.Model):
self.of_reviewer = None
self.of_submission.final_feedback = None
self.save()
def unassign_tutor(self):
self.of_submission.status.status = SubmissionStatus.READY
......@@ -37,7 +37,7 @@
{# Navbar contaning: Brand - Title - Page Title <---> (Username - Logout || Login form) #}
<nav class="navbar navbar-toggleable-md navbar-light bg-faded">
<a class="navbar-brand" href="{% url 'index' %}">
<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="card my-1">
<div class="card-header" id="heading{{unique}}">
<h5 class="mb-0">
<a data-toggle="collapse" href="#collapse{{unique}}">
{{ header }}
</a>
</h5>
</div>
<a data-toggle="collapse" href="#collapse{{unique}}">
<h5 class="card-header">{{ header }}</h5>
</a>
<div id="collapse{{unique}}" class="collapse hide" role="tabpanel">
<div class="card-block m-2">
{{ content }}
......
{% extends "base.html" %}
{% block nav_title %} Editing Feedback {% endblock nav_title %}
{% block nav_title %} {{ grady_says }} {% endblock nav_title %}
{% block title %} Editing Feedback {% endblock %}
{% block title %} Editing feedback {% endblock %}
{% load staticfiles %}
......@@ -11,11 +11,9 @@
<div class="col my-2">
<div class="card mb-2">
<div class="card-header" id="SubmissionCard">
<h4>Student Submission</h4>
</div>
<h4 class="card-header">Student Submission</h4>
<div class="card-block">
<div id="student_text" class="editor-code"> {{ feedback.of_submission.text }} </div>
<div id="student_text" class="editor-code">{{feedback.of_submission.text}}</div>
</div>
</div>
......@@ -32,11 +30,9 @@
<div class="col my-2">
<div class="card">
<div class="card-header" role="tab" id="SubmissionCard">
<h4>Please provide your feedback here:</h4>
</div>
<h4 class="card-header">Please provide your feedback</h4>
<div class="card-block">
<div class="editor-code" id="tutor_text"> {{ feedback.text }} </div>
<div class="editor-code" id="tutor_text">{{feedback.text}}</div>
</div>
</div>
<form action="{% url 'FeedbackEdit' feedback.slug %}" method="post" id="form1">
......@@ -57,6 +53,7 @@
<div class="col-6">
{% if not feedback.final %}
<button type="submit" form="form1" class="btn btn-success" name="update" value="Submit">Submit</button>
<button type="submit" form="form1" class="btn btn-success" name="update" value="Next">Next</button>
<a href="{% url 'FeedbackDelete' feedback.slug %}" class="btn btn-danger" name="delete" value="Delete">Delete</a>
{% else %}
<button class="btn btn-success mx-1" value="Submit" disabled>Submit</button>
......
......@@ -17,7 +17,7 @@
<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 submission.feedback.final %}
{% if feedback.final %}
<code> {{ feedback.score }} / {{submission.type.full_score}} </code>
{% else %}
<span class="badge badge-danger">No Feedback</span>
......@@ -25,33 +25,32 @@
</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">{{ feedback.of_submission.text }}</div>
<div class="card-header">Your submission</div>
<div class="editor-code" id="textarea_submission">{{submission.text}}</div>
</div>
</div>
</div>
{% if submission.feedback.final %}
{% if feedback.final %}
<div class="col-4 my-4">
<div class="card">
<div class="card-block">
<div class="card-header">
Our feedback
</div>
<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");
var feedback_editor = ace.edit("textarea_feedback");
feedback_editor.setOptions({
readOnly: true,
})
......
......@@ -7,7 +7,29 @@
{% block body_block %}
<div class="row justify-content-center my-2">
<div class="col-6">
<div class="col-3">
<div class="card">
<h4 class="card-header">Command Center</h4>
<table class="table">
<thead>
<th>Name</th>
<th></th>
</thead>
<tbody>
{% for submission_type in submission_type_list %}
<tr>
<td class="align-middle">{{ submission_type }}</td>
<td class="align-middle"><a role="button" class="btn btn-secondary" href="{% url 'CreateFeedbackForType' submission_type.slug %}">Get</a></td>
</tr>
{% endfor %}
</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>
</div>
<div class="col-5">
<div class="row my-2 page-header">
{% if feedback_list|length == 0 %}
<h2>You havn't provided any feedback yet. Sad. Get to work!</h2>
......@@ -31,7 +53,7 @@
{% for feedback in feedback_list %}
<tr>
<td> {{ feedback.of_submission.type }} </td>
<td> {{ feedback.score}} </td>
<td> <code> {{ feedback.score }} / {{feedback.of_submission.type.full_score}} </code> </td>
<td>
{% if feedback.final %}
<a class="btn btn-secondary" href="{% url 'FeedbackEdit' feedback.slug %}"> View </a>
......@@ -46,9 +68,6 @@
</table>
{% endif %}
</div>
<div class="row">
<a role="button" class="btn btn-danger btn-xl" href="{% url 'FeedbackCreate' %}">Give me work</a>
</div>
</div>
</div>
......
......@@ -10,11 +10,13 @@ urlpatterns = [
url(r'^start/$', views.user_home, name='start'),
url(r'^finished/$', views.finished, name='end'),
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'^feedback/markfinal/(?P<feedback_slug>\w+)/$', views.markfinal_feedback, name='FeedbackMarkFinal'),
url(r'^feedback/markfinal/(?P<feedback_slug>\w+)/undo/$', views.markunfinal_feedback, name='FeedbackMarkNotFinal'),
url(r'^feedback/create/$', views.create_feedback, name='FeedbackCreate'),
url(r'^submission/view/(?P<slug>\w+)/$', views.SubmissionView.as_view(), name='SubmissionView'),
]
......
from django.contrib.auth import authenticate, login, logout
from django.contrib.auth.decorators import login_required, user_passes_test
from django.contrib.auth.models import User
from django.contrib import messages
from django.http import Http404, HttpResponse, HttpResponseRedirect
from django.shortcuts import render
from django.urls import reverse
......@@ -10,7 +11,9 @@ from django.views.generic.edit import UpdateView
from core.forms import FeedbackForm
from core.models import Feedback, Submission, SubmissionType
from core.grady_speak import grady_says
from random import choice
# Create your views here.
......@@ -78,6 +81,7 @@ def user_home(request):
@group_required('Tutors')
def tutor_view(request):
context = {
'submission_type_list': SubmissionType.objects.all(),
'feedback_list': Feedback.objects.filter(of_tutor=request.user),
}
return render(request, 'core/tutor_startpage.html', context)
......@@ -102,13 +106,14 @@ def reviewer_view(request):
return render(request, 'core/reviewer_startpage.html', context)
@group_required('Tutors', 'Reviewers')
def create_feedback(request):
Submission.assign_tutor(request.user)
@group_required('Tutors')
def create_feedback(request, type_slug=None):
# assign does nothing if tutor has unfinished feedback
Submission.assign_tutor(request.user, type_slug)
feedback = Feedback.tutor_unfinished_feedback(request.user)
if not feedback:
return HttpResponseRedirect(reverse('end'))
return HttpResponseRedirect('/feedback/edit/%s/' % feedback.slug)
return HttpResponseRedirect(reverse('start'))
return HttpResponseRedirect(reverse('FeedbackEdit', args=(feedback.slug,)))
@group_required('Tutors', 'Reviewers')
......@@ -117,7 +122,6 @@ def delete_feedback(request, feedback_slug):
instance = Feedback.objects.get(slug=feedback_slug)
if instance.of_tutor != request.user and not in_groups(request.user, ('Reviewers', )):
raise Http404
instance.unassign_tutor()
instance.delete()
return HttpResponseRedirect(reverse('start'))
......@@ -166,8 +170,15 @@ class FeedbackEdit(UpdateView):
if form.is_valid():
form.instance.empty = False
form.save()
if 'Next' in self.request.POST['update']:
return HttpResponseRedirect(reverse('CreateFeedbackForType', args=(form.instance.of_submission.type.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
class SubmissionView(DetailView):
......@@ -179,4 +190,8 @@ class SubmissionView(DetailView):
return super(SubmissionView, self).dispatch(*args, **kwargs)
def get_object(self):
return Submission.objects.get(slug=self.kwargs['slug'])
obj = Submission.objects.get(slug=self.kwargs['slug'])
if obj.final_feedback:
obj.seen = True
obj.save()
return obj
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment