Newer
Older
from django.core.management.base import BaseCommand, CommandError # noqa
from django.db import transaction
from django.core.exceptions import ObjectDoesNotExist
from django.db.models import Q
from django.db.models.functions import Length
from course.models import FlowPageVisit, FlowPageBulkFeedback
def convert_flow_page_visit(stderr, fpv):
course = fpv.flow_session.course
from course.content import (
get_course_repo, get_flow_desc,
get_flow_page_desc, instantiate_flow_page)
repo = get_course_repo(course)
flow_id = fpv.flow_session.flow_id
commit_sha = course.active_git_commit_sha.encode()
try:
flow_desc = get_flow_desc(repo, course,
flow_id, commit_sha)
except ObjectDoesNotExist:
stderr.write("warning: no flow yaml file found for '%s' in '%s'"
% (flow_id, course.identifier))
return
try:
page_desc = get_flow_page_desc(
fpv.flow_session.flow_id, flow_desc,
fpv.page_data.group_id, fpv.page_data.page_id)
except ObjectDoesNotExist:
stderr.write("warning: no page yaml desc found for "
f"'{flow_id}:{fpv.page_data.group_id}/{fpv.page_data.page_id}' "
f"in '{course.identifier}'")
page = instantiate_flow_page(
location="flow '%s', group, '%s', page '%s'"
% (flow_id,
fpv.page_data.group_id, fpv.page_data.page_id),
repo=repo, page_desc=page_desc,
commit_sha=commit_sha)
from course.page.base import PageContext
pctx = PageContext(
course=course,
repo=repo,
commit_sha=commit_sha,
flow_session=fpv.flow_session,
page_uri=None)
from course.page.upload import FileUploadQuestion
from course.page.code import CodeQuestion
if isinstance(page, FileUploadQuestion):
content, mime_type = page.get_content_from_answer_data(
fpv.answer)
from django.core.files.base import ContentFile
answer_data = page.file_to_answer_data(
pctx, ContentFile(content), mime_type)
fpv.answer = answer_data
fpv.save()
return True
elif isinstance(page, CodeQuestion):
code = page.get_code_from_answer_data(fpv.answer)
answer_data = page.code_to_answer_data(pctx, code)
fpv.answer = answer_data
fpv.save()
return True
else:
return False
assert False
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
def convert_flow_page_visits(stdout, stderr):
fpv_qset = (FlowPageVisit
.objects
.annotate(answer_len=Length("answer"))
.filter(
Q(answer__contains="base64_data")
| (
# code questions with long answer_data
Q(answer__contains="answer")
& Q(answer_len__gte=128))
)
.select_related(
"flow_session",
"flow_session__course",
"flow_session__participation",
"flow_session__participation__user",
"page_data"))
fpv_qset_iterator = iter(fpv_qset)
quit = False
total_count = 0
while not quit:
with transaction.atomic():
for i in range(200):
try:
fpv = next(fpv_qset_iterator)
except StopIteration:
quit = True
break
if convert_flow_page_visit(stderr, fpv):
total_count += 1
stdout.write("converted %d page visits..." % total_count)
stdout.write("done with visits!")
def convert_bulk_feedback(stdout, stderr):
from course.models import BULK_FEEDBACK_FILENAME_KEY, update_bulk_feedback
fbf_qset = (FlowPageBulkFeedback
.objects
.annotate(bf_len=Length("bulk_feedback"))
.filter(
~Q(bulk_feedback__contains=BULK_FEEDBACK_FILENAME_KEY)
& Q(bf_len__gte=256))
.select_related(
"page_data",
"page_data__flow_session",
"page_data__flow_session__participation",
"page_data__flow_session__participation__user"))
fbf_qset_iterator = iter(fbf_qset)
quit = False
total_count = 0
while not quit:
with transaction.atomic():
for i in range(200):
try:
fbf = next(fbf_qset_iterator)
except StopIteration:
quit = True
break
update_bulk_feedback(fbf.page_data, fbf.grade, fbf.bulk_feedback)
total_count += 1
stdout.write("converted %d bulk feedback objects..." % total_count)
stdout.write("done with bulk feedback!")
class Command(BaseCommand):
help = (
"Migrates bulk data (e.g. file upload submissions) out of the database "
"and into the storage given by RELATE_BULK_STORAGE. This command may "
"safely be interrupted and will pick up where it left off.")
def handle(self, *args, **options):
convert_bulk_feedback(self.stdout, self.stderr)
convert_flow_page_visits(self.stdout, self.stderr)
# vim: foldmethod=marker