Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

April review fixes 146 #147

Merged
merged 11 commits into from
Jul 8, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion apps/api/views/homework.py
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ class DefinitionViewSet(ModelViewSet):
queryset = Definition.objects.all()
queryset = Definition.objects.all().prefetch_related(Prefetch(
'custom_questions',
queryset=Question.objects.order_by('id')))
queryset=Question.objects.all()))
serializer_class = DefinitionSerializer
permission_classes = (DefinitionPermissionCheck,)

Expand Down
22 changes: 22 additions & 0 deletions apps/homework/migrations/0057_auto_20200507_2015.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# Generated by Django 2.2.10 on 2020-05-07 20:15

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('homework', '0056_auto_20200507_1944'),
]

operations = [
migrations.AlterModelOptions(
name='question',
options={'ordering': ('question',)},
),
migrations.AlterField(
model_name='definition',
name='description',
field=models.TextField(blank=True, null=True),
),
]
26 changes: 24 additions & 2 deletions apps/homework/models.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import os
import re
from decimal import Decimal
from urllib.parse import urlparse

Expand Down Expand Up @@ -27,7 +28,7 @@ class Definition(models.Model):
due_date = models.DateTimeField(default=None)

name = models.CharField(default=None, max_length=100, null=False, blank=False)
description = models.CharField(max_length=300, null=True, blank=True)
description = models.TextField(null=True, blank=True)
updated_at = models.DateTimeField(auto_now=True)

questions_only = models.BooleanField(default=False, null=False)
Expand Down Expand Up @@ -64,6 +65,10 @@ class Meta:
def __str__(self):
return "{}".format(self.name)

@property
def has_standard_questions(self):
return bool(self.ask_project_url) or bool(self.ask_publication_url) or bool(self.ask_method_name) or bool(self.ask_method_description)

def get_challenge_url(self):
parsed_uri = urlparse(self.challenge_url)
scheme = parsed_uri.scheme
Expand Down Expand Up @@ -139,6 +144,20 @@ class Submission(models.Model):
def __str__(self):
return "{}".format(self.github_url)

@property
def nb_viewer_format_submission_url(self):
# This property is for prepending the nbviewer domain to the Github URL for Jupyter Notebook submissions.
url = self.github_url
if self.definition.jupyter_notebook_enabled:
if type(url) == str:
if not re.match('.*ipynb$', url):
return url
if not re.match('.*github\.com.*', url):
return url
url = url.split('github.com')[-1]
return f'https://nbviewer.jupyter.org/github{url}'
return url

@property
def get_challenge_url(self):
if not self.definition.challenge_url:
Expand Down Expand Up @@ -257,7 +276,7 @@ def get_total_score(self):

def calculate_grade(self):
total, total_possible = self.get_total_score_total_possible()
self.text_grade = f"{total}/{total_possible}"
self.text_grade = f"{total}/{int(total_possible)}"
if total_possible != 0 and total is not None:
self.overall_grade = total / total_possible
self.save()
Expand Down Expand Up @@ -323,6 +342,9 @@ class Question(models.Model):
question = models.TextField()
candidate_answers = JSONField(blank=True, default=list)

class Meta:
ordering = ('question',)

def __str__(self):
return self.question

Expand Down
56 changes: 32 additions & 24 deletions apps/homework/templates/homework/forms/grade_homework.html
Original file line number Diff line number Diff line change
Expand Up @@ -32,36 +32,41 @@ <h4 class="ui header">Challenge Rules</h4>
<div class="ui relaxed celled list">
<a href="{{ definition.challenge_url }}" class="item" target="_blank" rel="noopener noreferrer">Link to challenge competition</a>
{% if submission.github_url %}
<a href="{{ submission.github_url }}" class="item" target="_blank" rel="noopener noreferrer">Link to Github repo of submission</a>
<a
href="{{ submission.nb_viewer_format_submission_url }}"
class="item"
target="_blank"
rel="noopener noreferrer"
>Link to Github repo of submission</a>
{% endif %}
<a class="ui mini blue button" href="{% url "homework:submission_detail" submission_pk=submission.pk %}">Submission Details</a>
</div>
{% endif %}

{% if definition.jupyter_notebook_enabled %}
<h4 class="ui header">Jupyter Notebook</h4>
<div class="ui relaxed celled list">
<div>Auto-Grade Score: {{ submission.jupyter_score }} / {{ definition.jupyter_notebook_highest }}</div>
{% if submission_jupyter_warnings %}
<div>Auto-Grade Warnings:</div>
<ul>
{% for warning in submission_jupyter_warnings %}
<li>{{ warning }}</li>
{% endfor %}
</ul>
{% endif %}
{% if definition.jupyter_notebook_enabled %}
<h4 class="ui header">Jupyter Notebook</h4>
<div class="ui relaxed celled list">
<div>Auto-Grade Score: {{ submission.jupyter_score }} / {{ definition.jupyter_notebook_highest }}</div>
{% if submission_jupyter_warnings %}
<div>Auto-Grade Warnings:</div>
<ul>
{% for warning in submission_jupyter_warnings %}
<li>{{ warning }}</li>
{% endfor %}
</ul>
{% endif %}

{% if submission_jupyter_errors %}
<div>Auto-Grade Errors:</div>
<ul>
{% for error in submission_jupyter_errors %}
<li>{{ error }}</li>
{% endfor %}
</ul>
{% endif %}
</div>
{% endif %}
{% if submission_jupyter_errors %}
<div>Auto-Grade Errors:</div>
<ul>
{% for error in submission_jupyter_errors %}
<li>{{ error }}</li>
{% endfor %}
</ul>
{% endif %}
</div>
{% endif %}

{% endif %}

<h4>Questions</h4>
<div class="ui relaxed celled list">
Expand All @@ -81,6 +86,9 @@ <h4>Questions</h4>
target="_blank" rel="noopener noreferrer"
>{{ submission.publication_url }}</a></li>{% endif %}
</ol>
{% if not definition.has_standard_questions %}
<p>No standard questions defined for this homework.</p>
{% endif %}
</div>
<grade-homework></grade-homework>
</div>
Expand Down
9 changes: 6 additions & 3 deletions apps/homework/templates/homework/overview.html
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
{% extends 'base.html' %}
{% load static %}
{% load homework_tags %}
{% load chagrade_tags %}

{% block title %}Welcome{% endblock %}

Expand Down Expand Up @@ -90,7 +91,7 @@ <h4 class="ui header">Submission Details:</h4>
{% if not definition.questions_only %}
{% if submission.github_url %}
<div class="item"><a
href="{{ submission.github_url }}"
href="{{ submission.nb_viewer_format_submission_url }}"
target="_blank" rel="noopener noreferrer"
class="">Github URL for Submission</a></div>
{% else %}
Expand Down Expand Up @@ -236,7 +237,9 @@ <h4 class="ui header">Submission Details:</h4>
<div class="five wide column">
<div class="ui statistic">
<div class="value">
{{ grade.text_grade }}
{% with grade.calculate_grade as g %}
{{ grade.text_grade }}
{% endwith %}
</div>
<div class="label">
Total Grade
Expand All @@ -245,7 +248,7 @@ <h4 class="ui header">Submission Details:</h4>
{% if definition.jupyter_notebook_enabled %}
<div class="ui tiny statistic">
<div class="value">
{{ grade.jupyter_notebook_grade }}/{{ definition.jupyter_notebook_highest }}
{{ grade.jupyter_notebook_grade|default:0.0 }}/{{ definition.jupyter_notebook_highest|format_as_int }}
</div>
<div class="label">
JUPYTER NOTEBOOK GRADE
Expand Down
8 changes: 7 additions & 1 deletion apps/homework/templates/homework/submission_detail.html
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,13 @@
<div class="ui header">Submission Information</div>
<div class="ui divider"></div>

<submission-detail-github class="ui grid" submission_pk="{{ submission.pk }}" hash="{{ submission.commit_hash }}" user_pk="{{ request.user.pk }}"></submission-detail-github>
<submission-detail-github
class="ui grid"
submission_pk="{{ submission.pk }}"
submission_url="{{ submission.nb_viewer_format_submission_url }}"
hash="{{ submission.commit_hash }}"
user_pk="{{ request.user.pk }}"
></submission-detail-github>
</div>
</div>

Expand Down
4 changes: 3 additions & 1 deletion apps/homework/templates/homework/submission_list.html
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,9 @@ <h4>Due Date: {{ definition.due_date }}</h4>
{% endif %}
<td>
{% if submission.github_url %}
<a class="ui mini blue icon button" href="{{ submission.github_url }}" target="_blank" rel="noopener noreferrer">
<a class="ui mini blue icon button"
href="{{ submission.nb_viewer_format_submission_url }}"
target="_blank" rel="noopener noreferrer">
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I feel like this would read a bit nicer if there was a property on the submission model that returned either github url or notebook url? in general moving logic out of templates is ideal, but can't always do it!

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Model: big
Template: smol

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

<i class="file code icon"></i>
</a>
{% else %}
Expand Down
18 changes: 18 additions & 0 deletions apps/klasses/migrations/0016_auto_20200507_2015.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Generated by Django 2.2.10 on 2020-05-07 20:15

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('klasses', '0015_auto_20200326_2135'),
]

operations = [
migrations.AlterField(
model_name='klass',
name='description',
field=models.TextField(blank=True, default='', null=True),
),
]
2 changes: 1 addition & 1 deletion apps/klasses/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ class Klass(models.Model):

title = models.CharField(max_length=60, null=False, blank=False, default="New Course")
course_number = models.SlugField(max_length=60, null=False, blank=False)
description = models.CharField(max_length=300, null=True, blank=True, default="")
description = models.TextField(null=True, blank=True, default="")

created = models.DateTimeField(editable=False, default=timezone.now, null=True, blank=True)
modified = models.DateTimeField(default=timezone.now, null=True, blank=True)
Expand Down
25 changes: 16 additions & 9 deletions apps/klasses/templates/klasses/wizard/grade_homework.html
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,17 @@ <h2 class="ui massive header" style="font-size: 56px;">Grade Homework</h2>
<div class="ui fourteen wide column message">
<div style="overflow-x: scroll;">
<h1>Students</h1>
<span>
<a href="{% url 'homework:get_grades_csv' klass_pk=klass.pk %}" class="ui blue button">Download CSV</a>
</span>
<div class="table-header-container">
<span>
<a href="{% url 'homework:get_grades_csv' klass_pk=klass.pk %}" class="ui blue button">Download CSV</a>
</span>
<div class="ui horizonatal relaxed list">
<div class="ui gray label">Not Graded</div>
<div class="ui yellow label">Grade Not Published</div>
<div class="ui green label">Grade Published</div>
<div class="ui orange label">Jupyter Notebook Needs Review</div>
</div>
</div>
<table style="display: block; overflow-x: scroll; max-height: 100vh;" class="ui sortable table" onscroll="second_row_height_adjustment()">
<thead>
<tr id="first-row">
Expand Down Expand Up @@ -87,16 +95,15 @@ <h1>Students</h1>
{% endfor %}
</tbody>
</table>
<div class="ui horizonatal relaxed list">
<div class="ui gray label">Not Graded</div>
<div class="ui yellow label">Grade Not Published</div>
<div class="ui green label">Grade Published</div>
<div class="ui orange label">Jupyter Notebook Needs Review</div>
</div>
</div>
</div>

<style>
.table-header-container {
display: flex;
justify-content: space-between;
}

.left-sticky {
position: sticky;
left: 0;
Expand Down
8 changes: 8 additions & 0 deletions apps/klasses/templatetags/chagrade_tags.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,13 @@ def format_url_with_schema(url):
return url


def format_as_int(number):
if number is not None:
return int(number)
else:
return number


def get_submission(definition_pk, student_pk):
"""Gets a submission given a definition and a student"""
try:
Expand All @@ -41,6 +48,7 @@ def format_json_array(json_array):
return outstring


register.filter('format_as_int', format_as_int)
register.filter('format_url_with_schema', format_url_with_schema)
register.filter('get_submission', get_submission)
register.filter('format_json_array', format_json_array)
2 changes: 1 addition & 1 deletion static/riotjs/student/submission_detail_github.tag
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<submission-detail-github>
<div class="{definition.questions_only ? 'sixteen' : 'six'} wide column">

<a if="{ submission.github_url }" class="ui tiny black button" href="{ submission.github_url }">Submission File</a>
<a if="{ submission.github_url }" class="ui tiny black button" href="{ opts.submission_url }" target="_blank">Submission File</a>
<p>Submitted: { format_date(submission.created) }</p>
<p if="{ !!submission.commit_hash && submission.commit_hash !== 'Commit (Optional)' }">Commit hash: { submission.commit_hash.slice(0,6) }</p>
<p if="{ submission.github_repo_name }">Repository Name: { submission.github_repo_name }</p>
Expand Down
31 changes: 17 additions & 14 deletions static/riotjs/wizard/define_homework.tag
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,18 @@
<form class="ui form" ref="form" onsubmit="{ }">
<!-- Important information -->
<div class="fields">
<div class="three wide field">

<div class="six wide required field">
<label>Name:</label>
<input type="text"
name="name"
maxlength="100"
required
ref="name"
value="{definition.name}">
</div>

<div class="twelve wide field">
<div class="ui required calendar field">
<label>
Due-Date:
Expand All @@ -18,24 +29,16 @@
</div>
</div>
</div>

<div class="three wide required field">
<label>Name:</label>
<input type="text"
name="name"
maxlength="100"
required
ref="name"
value="{definition.name}">
</div>

<div class="ten wide field">
</div>
<div class="fields">
<div class="sixteen wide field">
<label>Description:</label>
<input type="text"
<textarea type="text"
name="description"
maxlength="300"
ref="description"
value="{definition.description}">
</textarea>
</div>
</div>

Expand Down
Loading