Newer
Older
from django.db import models
from django.contrib.auth.models import User
from django.utils.timezone import now
from django.core.urlresolvers import reverse
from django.core.exceptions import ValidationError
class user_status:
requested = "requested"
active = "active"
USER_STATUS_CHOICES = (
(user_status.requested, "Requested"),
(user_status.active, "Active"),
)
user = models.OneToOneField(User, db_index=True)
status = models.CharField(max_length=50,
choices=USER_STATUS_CHOICES)
registration_key = models.CharField(max_length=50,
null=True, unique=True, db_index=True)
key_time = models.DateTimeField(default=now)
class Meta:
verbose_name_plural = "user statuses"
ordering = ("key_time",)
# }}}
identifier = models.CharField(max_length=200, unique=True,
help_text="A URL identifier. Alphanumeric with dashes, "
db_index=True)
git_source = models.CharField(max_length=200, blank=True,
help_text="A Git URL from which to pull course updates")
ssh_private_key = models.CharField(max_length=2000, blank=True,
help_text="An SSH private key to use for Git authentication")
enrollment_approval_required = models.BooleanField(
default=False)
enrollment_required_email_suffix = models.CharField(
max_length=200, blank=True, null=True)
course_robot_email_address = models.EmailField()
course_xmpp_id = models.CharField(max_length=200, blank=True)
course_xmpp_password = models.CharField(max_length=200, blank=True)
active_git_commit_sha = models.CharField(max_length=200, null=False,
blank=False)
participants = models.ManyToManyField(User,
through='Participation')
def __unicode__(self):
return self.identifier
def get_absolute_url(self):
return reverse("course.views.course_page", args=(self.identifier,))
# }}}
class TimeMark(models.Model):
"""A time mark is an identifier that can be used in datespecs in lecture content.
"""
course = models.ForeignKey(Course)
kind = models.CharField(max_length=50,
help_text="Should be lower_case_with_underscores, no spaces allowed.")
ordinal = models.IntegerField(blank=True, null=True)
time = models.DateTimeField()
class Meta:
ordering = ("course", "time")
# {{{ participation
instructor = "instructor"
teaching_assistant = "ta"
student = "student"
PARTICIPATION_ROLE_CHOICES = (
(participation_role.instructor, "Instructor"),
(participation_role.teaching_assistant, "Teaching Assistant"),
(participation_role.student, "Student"),
requested = "requested"
active = "active"
dropped = "dropped"
(participation_status.requested, "Requested"),
(participation_status.active, "Active"),
(participation_status.dropped, "Dropped"),
)
class Participation(models.Model):
user = models.ForeignKey(User)
course = models.ForeignKey(Course)
enroll_time = models.DateTimeField(default=now)
role = models.CharField(max_length=50,
temporary_role = models.CharField(max_length=50,
choices=PARTICIPATION_ROLE_CHOICES, null=True, blank=True)
time_factor = models.DecimalField(
max_digits=10, decimal_places=2,
default=1)
preview_git_commit_sha = models.CharField(max_length=200, null=True,
blank=True)
def __unicode__(self):
return "%s in %s as %s" % (
self.user, self.course, self.role)
class Meta:
unique_together = (("user", "course"),)
class InstantFlowRequest(models.Model):
course = models.ForeignKey(Course)
flow_id = models.CharField(max_length=200)
start_time = models.DateTimeField(default=now)
end_time = models.DateTimeField()
# {{{ flow visit tracking
class flow_visit_state:
in_progress = "in_progress"
expired = "expired"
completed = "completed"
FLOW_VISIT_STATE_CHOICES = (
(flow_visit_state.in_progress, "In progress"),
(flow_visit_state.expired, "Expired"),
(flow_visit_state.completed, "Completed"),
)
participation = models.ForeignKey(Participation, null=True, blank=True)
active_git_commit_sha = models.CharField(max_length=200)
start_time = models.DateTimeField(default=now)
completion_time = models.DateTimeField(null=True, blank=True)
state = models.CharField(max_length=50, choices=FLOW_VISIT_STATE_CHOICES)
class Meta:
ordering = ("participation",)
class FlowPageData(models.Model):
flow_visit = models.ForeignKey(FlowVisit)
group_id = models.CharField(max_length=200)
data = JSONField(null=True, blank=True)
class Meta:
unique_together = (("flow_visit", "ordinal"),)
verbose_name_plural = "flow page data"
def __unicode__(self):
return "Data for %s's visit %d to '%s/%s' in '%s'" % (
self.flow_visit.participation.user,
self.flow_visit.id,
self.group_id,
self.page_id,
self.flow_visit.flow_id)
class FlowPageVisit(models.Model):
page_data = models.ForeignKey(FlowPageData, db_index=True)
visit_time = models.DateTimeField(default=now, db_index=True)
# }}}
# {{{ flow access
class flow_permission:
# access flow start page
view = "view"
# review past attempts
view_past = "view_past"
# start new for-credit visit
start_credit = "start_credit"
# start new not-for-credit visit
start_no_credit = "start_no_credit"
# see correct answer
see_correct_answer = "see_correct_answer"
FLOW_PERMISSION_CHOICES = (
(flow_permission.view, "View flow start page"),
(flow_permission.view_past, "Review past attempts"),
(flow_permission.start_credit, "Start for-credit visit"),
(flow_permission.start_no_credit, "Start not-for-credit visit"),
(flow_permission.see_correct_answer, "See correct answer"),
)
class FlowAccessException(models.Model):
participation = models.ForeignKey(Participation, db_index=True)
flow_id = models.CharField(max_length=200, blank=False, null=False)
expiration = models.DateTimeField(blank=True, null=True)
stipulations = JSONField(blank=True, null=True)
creator = models.ForeignKey(User, null=True)
creation_time = models.DateTimeField(default=now, db_index=True)
def __unicode__(self):
return "Access exception for '%s' to '%s' in '%s'" % (
self.participation.user, self.flow_id,
self.participation.course)
class FlowAccessExceptionEntry(models.Model):
exception = models.ForeignKey(FlowAccessException,
related_name="entries")
permission = models.CharField(max_length=50,
choices=FLOW_PERMISSION_CHOICES)
def __unicode__(self):
return self.permission
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
# }}}
# {{{ grading
class GradingOpportunity(models.Model):
course = models.ForeignKey(Course)
identifier = models.CharField(max_length=200, blank=False, null=False,
help_text="A symbolic name for this grade. "
"lower_case_with_underscores, no spaces.")
name = models.CharField(max_length=200, blank=False, null=False,
help_text="A human-readable identifier for the grade.")
flow_id = models.CharField(max_length=200, blank=True, null=True,
help_text="Flow identifier that this grading opportunity "
"is linked to, if any")
max_points = models.DecimalField(max_digits=10, decimal_places=2)
due_time = models.DateTimeField(default=None, blank=True, null=True)
class Meta:
verbose_name_plural = "grading opportunities"
ordering = ("course", "due_time", "identifier")
def __unicode__(self):
return "%s in %s" % (self.name, self.course)
class grade_state_change_types:
grading_started = "grading_started"
graded = "graded"
retrieved = "retrieved"
unavailable = "unavailable"
extension = "extension"
report_sent = "report_sent"
do_over = "do_over"
exempt = "exempt"
GRADE_STATE_CHANGE_CHOICES = (
(grade_state_change_types.grading_started, 'Grading started'),
(grade_state_change_types.graded, 'Graded'),
(grade_state_change_types.retrieved, 'Retrieved'),
(grade_state_change_types.unavailable, 'Unavailable'),
(grade_state_change_types.extension, 'Extension'),
(grade_state_change_types.report_sent, 'Report sent'),
(grade_state_change_types.do_over, 'Do-over'),
(grade_state_change_types.exempt, 'Exempt'),
)
class GradeChange(models.Model):
opportunity = models.ForeignKey(GradingOpportunity)
participation = models.ForeignKey(Participation)
state = models.CharField(max_length=50,
choices=GRADE_STATE_CHANGE_CHOICES)
points = models.DecimalField(max_digits=10, decimal_places=2,
blank=True, null=True)
comment = models.TextField(blank=True, null=True)
due_time = models.DateTimeField(default=None, blank=True, null=True)
creator = models.ForeignKey(User, null=True)
grade_time = models.DateTimeField(default=now, db_index=True)
class Meta:
ordering = ("opportunity", "participation", "grade_time")
def __unicode__(self):
return "%s %s on %s" % (self.participation, self.state,
self.opportunity.name)
def clean(self):
if self.opportunity.course != self.participation.course:
raise ValidationError("Participation and opportunity must live "
"in the same course")
# }}}
# vim: foldmethod=marker