Skip to content

Commit 0d2d1f0

Browse files
committed
Add endpoint and button for downloading exercises waiting for grading
Change exercise modal size from lg to xl Implements #1508
1 parent b3e3723 commit 0d2d1f0

9 files changed

Lines changed: 97 additions & 2 deletions

File tree

api/urls_v2.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,9 @@ def __init__(self):
6767
courses.register(r'submissiondata',
6868
exercise.api.csv.views.CourseSubmissionDataViewSet,
6969
basename='course-submissiondata')
70+
courses.register(r'pendingsubmissiondata',
71+
exercise.api.csv.views.CoursePendingSubmissionDataViewSet,
72+
basename='course-submissiondata-pending')
7073
courses.register(r'aggregatedata',
7174
exercise.api.csv.views.CourseAggregateDataViewSet,
7275
basename='course-aggregatedata')

course/api/full_serializers.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@ class CourseSerializer(CourseBriefSerializer):
9292
},
9393
)
9494
data = NestedHyperlinkedIdentityField(view_name='api:course-submissiondata-list')
95+
pending_submissions_data = NestedHyperlinkedIdentityField(view_name='api:course-submissiondata-pending-list')
9596
aggregate_data = NestedHyperlinkedIdentityField(view_name='api:course-aggregatedata-list')
9697
results_data = NestedHyperlinkedIdentityField(view_name='api:course-resultsdata-list')
9798
best_results_data = NestedHyperlinkedIdentityField(view_name='api:course-resultsdata-best-list')
@@ -117,6 +118,7 @@ class Meta(CourseBriefSerializer.Meta):
117118
'my_points',
118119
'my_data',
119120
'data',
121+
'pending_submissions_data',
120122
'aggregate_data',
121123
'results_data',
122124
'best_results_data',

exercise/api/csv/submission_sheet.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
def filter_best_submissions(
1111
submissions: Iterable[Submission],
1212
revealed_ids: Set[int],
13+
include_all_submissions: bool = False,
1314
) -> List[Submission]:
1415
best = {}
1516
forced = {}
@@ -21,7 +22,7 @@ def filter_best_submissions(
2122
best[eid] = {}
2223
forced[eid] = {}
2324

24-
if s.status == 'ready':
25+
if s.status == 'ready' or include_all_submissions:
2526
user = s.submitters.first()
2627
uid = user.id if user else 0
2728
grade = s.grade if eid in revealed_ids else 0

exercise/api/csv/views.py

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,45 @@ def get_renderer_context(self):
168168
return context
169169

170170

171+
class CoursePendingSubmissionDataViewSet(CourseSubmissionDataViewSet):
172+
"""
173+
The `pendingsubmissiondata` endpoint returns information in CSV format about the
174+
users' submissions in exercises in the course. Similar to the 'submissiondata' endpoint,
175+
but overrides the serialize_submissions method to include submissions with any status,
176+
such as waiting for grading or error.
177+
"""
178+
include_all_submissions = True
179+
def serialize_submissions(
180+
self,
181+
request: Request,
182+
queryset: QuerySet[Submission],
183+
revealed_ids: Set[int],
184+
best: bool = False
185+
) -> Response:
186+
submissions = list(queryset.order_by('exercise_id', 'id'))
187+
if best:
188+
submissions = filter_best_submissions(submissions, revealed_ids, self.include_all_submissions)
189+
190+
# Pick out a single field.
191+
field = request.GET.get('field')
192+
if field:
193+
def submitted_field(submission, name):
194+
for key,val in (submission.submission_data or []):
195+
if key == name:
196+
return val
197+
return ""
198+
vals = [submitted_field(s, field) for s in submissions]
199+
return Response([v for v in vals if v != ""])
200+
data,fields = submissions_sheet(request, submissions, revealed_ids)
201+
self.renderer_fields = fields
202+
response = Response(data)
203+
if isinstance(getattr(request, 'accepted_renderer'), CSVRenderer):
204+
response['Content-Disposition'] = 'attachment; filename="submissions.csv"'
205+
elif isinstance(getattr(request, 'accepted_renderer'), APlusJSONRenderer):
206+
response['Content-Disposition'] = 'attachment; filename="submissions.json"'
207+
return response
208+
209+
171210
class CourseAggregateDataViewSet(NestedViewSetMixin,
172211
MeUserMixin,
173212
CourseResourceMixin,

exercise/templates/exercise/staff/_submissions_table.html

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,26 @@
4040
{% endfor %}
4141
</ul>
4242
</span>
43+
<span class="dropdown">
44+
<button
45+
class="aplus-button--secondary aplus-button--xs dropdown-toggle"
46+
type="button"
47+
data-bs-toggle="dropdown"
48+
id="download-pending-data"
49+
>
50+
{% translate "DOWNLOAD_ALL_POINTS" %} <span class="caret"></span>
51+
</button>
52+
<ul class="dropdown-menu dropdown-menu-start" aria-labeledby="download-pending-data">
53+
{% get_format_info_list "json csv excel.csv" as formats %}
54+
{% for format in formats %}
55+
<li>
56+
<a class="dropdown-item" href="{% url 'api:course-submissiondata-pending-list' version=2 course_id=instance.id %}?exercise_id={{ exercise.id }}&amp;format={{ format.name }}">
57+
{{ format.verbose_name }}
58+
</a>
59+
</li>
60+
{% endfor %}
61+
</ul>
62+
</span>
4363
{% if has_files %}
4464
<span class="dropdown">
4565
<button

exercise/templates/exercise/staff/_submitters_table.html

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,26 @@
3939
{% endfor %}
4040
</ul>
4141
</span>
42+
<span class="dropdown">
43+
<button
44+
class="aplus-button--secondary aplus-button--xs dropdown-toggle"
45+
type="button"
46+
data-bs-toggle="dropdown"
47+
id="download-pending-data"
48+
>
49+
{% translate "DOWNLOAD_ALL_POINTS" %} <span class="caret"></span>
50+
</button>
51+
<ul class="dropdown-menu dropdown-menu-start" aria-labeledby="download-pending-data">
52+
{% get_format_info_list "json csv excel.csv" as formats %}
53+
{% for format in formats %}
54+
<li>
55+
<a class="dropdown-item" href="{% url 'api:course-submissiondata-pending-list' version=2 course_id=instance.id %}?exercise_id={{ exercise.id }}&amp;format={{ format.name }}">
56+
{{ format.verbose_name }}
57+
</a>
58+
</li>
59+
{% endfor %}
60+
</ul>
61+
</span>
4262
{% if has_files %}
4363
<span class="dropdown">
4464
<button

locale/en/LC_MESSAGES/django.po

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4699,6 +4699,11 @@ msgstr "Summary"
46994699
msgid "DOWNLOAD_POINTS"
47004700
msgstr "Download points"
47014701

4702+
#: exercise/templates/exercise/staff/_submissions_table.html
4703+
#: exercise/templates/exercise/staff/_submitters_table.html
4704+
msgid "DOWNLOAD_ALL_POINTS"
4705+
msgstr "Download points (include all submissions)"
4706+
47024707
#: exercise/templates/exercise/staff/_submissions_table.html
47034708
#, python-format
47044709
msgid "NUM_OF_SUBMISSIONS_DISPLAYED -- %(count)s"

locale/fi/LC_MESSAGES/django.po

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4712,6 +4712,11 @@ msgstr "Yhteenveto"
47124712
msgid "DOWNLOAD_POINTS"
47134713
msgstr "Lataa pisteet"
47144714

4715+
#: exercise/templates/exercise/staff/_submissions_table.html
4716+
#: exercise/templates/exercise/staff/_submitters_table.html
4717+
msgid "DOWNLOAD_ALL_POINTS"
4718+
msgstr "Lataa pisteet (sis. kaikki palautukset)"
4719+
47154720
#: exercise/templates/exercise/staff/_submissions_table.html
47164721
#, python-format
47174722
msgid "NUM_OF_SUBMISSIONS_DISPLAYED -- %(count)s"

templates/base.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -259,7 +259,7 @@
259259
{% endblock %}
260260
</div>
261261
<div id="page-modal" class="modal" role="dialog">
262-
<div class="modal-dialog modal-lg">
262+
<div class="modal-dialog modal-xl">
263263
<div class="modal-content">
264264
<div class="modal-progress">
265265
<div class="modal-submit-error alert alert-danger" style="display:none">

0 commit comments

Comments
 (0)