-
Notifications
You must be signed in to change notification settings - Fork 24
/
models.py
142 lines (116 loc) · 5.99 KB
/
models.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
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
from django.conf import settings
from django.db.models.signals import post_save
from django.core.exceptions import ValidationError
from django.db import models
from devilry.apps.core.models import Delivery, Assignment, StaticFeedback
from registry import gradeeditor_registry
class Config(models.Model):
"""
Stored by admins.
.. attribute:: gradeeditorid
A ``gradeeditorid`` that is used to get the
:class:`devilry.apps.gradeeditors.registry.RegistryItem` for this
config.
.. attribute:: assignment
The primary key. This means we have one config for each assignment.
.. attribute:: config
A text field where the config editor can store its data in any format
it chooses. JSON is usually a good choice because of easy interraction
with JavaScript.
"""
gradeeditorid = models.SlugField()
assignment = models.OneToOneField(Assignment, related_name='gradeeditor_config',
primary_key=True)
config = models.TextField(null=True, blank=True)
def _get_gradeeditor(self):
return gradeeditor_registry[self.gradeeditorid]
def clean(self):
"""
Gets a :class:`devilry.apps.gradeeditors.registry.RegistryItem` from
the ``gradeeditor_registry`` in
:mod:`devilry.apps.gradeeditor.registry`.
Uses
:meth:`devilry.apps.gradeeditors.registry.RegistryItem.validate_config`
to validate the config before saving it.
"""
try:
config = self._get_gradeeditor()
except KeyError, e:
raise ValidationError('Invalid grade editor: {0}'.format(self.gradeeditorid))
if self.config:
config.validate_config(self.config)
def create_gradeconfig_for_assignment(sender, **kwargs):
"""
Signal handler which is invoked when an Assignment is created.
Create default grade Config for Assignment with ``config=''`` if the assignment
has no grade Config.
:param kwargs: Must have an *instance* key with an assignment object as value.
"""
assignment = kwargs['instance']
try:
config = assignment.gradeeditor_config
except Config.DoesNotExist:
config = Config(assignment=assignment,
gradeeditorid=gradeeditor_registry.getdefaultkey(),
config='')
config.save()
post_save.connect(create_gradeconfig_for_assignment,
sender=Assignment)
class FeedbackDraft(models.Model):
"""
Stored by examiners.
"""
delivery = models.ForeignKey(Delivery)
draft = models.TextField()
save_timestamp = models.DateTimeField(auto_now=True, blank=False, null=False,
help_text='Time when this feedback was saved. Since FeedbackDraft '
'is immutable, this never changes.')
saved_by = models.ForeignKey(settings.AUTH_USER_MODEL)
published = models.BooleanField(default=False,
help_text='Has this draft been published as a StaticFeedback? Setting this to true on create automatically creates a StaticFeedback.')
staticfeedback = models.OneToOneField(StaticFeedback, blank=True, null=True,
related_name='gradeeditor_feedbackdraft',
help_text='The StaticFeedback where this was published if this draft has been published.')
def _get_config(self):
return self.delivery.deadline.assignment_group.parentnode.gradeeditor_config
def clean(self):
if self.id == None: # If creating a new FeedbackDraft
try:
config = self._get_config()
except Config.DoesNotExist:
raise ValidationError(('Can not create feedback on delivery:{0} '
'because its assignment does not have a '
'gradeeditor_config.').format(self.delivery))
else:
gradeeditor = config._get_gradeeditor()
gradeeditor.validate_draft(self.draft, config.config)
if not self.published:
self.staticfeedback = None # We should NEVER set staticfeedback if published is not True
else:
raise ValidationError('FeedbackDraft is immutable (it can not be changed).')
def save(self, *args, **kwargs):
"""
Save the draft and optionally a :class:`devilry.core.models.StaticFeedback`
in the database. The ``StaticFeedback`` is only saved if
``self.publish`` is ``True``.
Uses :meth:`to_staticfeedback` to create the staticfeedback.
"""
if self.published:
_tmp_staticfeedback = self.to_staticfeedback()
_tmp_staticfeedback.full_clean()
_tmp_staticfeedback.save()
self.staticfeedback = _tmp_staticfeedback # Note: We use _tmp_staticfeedback because if we need a variable in which to store the staticfeedback while we save it. We can not just save self.staticfeedback() because that would just create create a copy without actually setting self.staticfeedback to the newly saved value.
super(FeedbackDraft, self).save(*args, **kwargs)
def to_staticfeedback(self):
""" Return a staticfeedback generated from self. """
config = self._get_config()
gradeeditor = config._get_gradeeditor()
kwargs = gradeeditor.draft_to_staticfeedback_kwargs(self.draft, config.config)
# Create StaticFeedback from kwargs. We copy by key instead of **kwargs to make sure we dont get anything extra.
return StaticFeedback(is_passing_grade=kwargs['is_passing_grade'],
grade=kwargs['grade'],
points=kwargs['points'],
rendered_view=kwargs['rendered_view'],
delivery=self.delivery,
save_timestamp=None,
saved_by=self.saved_by)