Prepared for SP 4-6.
[edumed.git] / curriculum / models.py
1 # -*- coding: utf-8
2 import re
3 from django.core.urlresolvers import reverse
4 from django.db import models
5 from django.utils.translation import ugettext_lazy as _, get_language
6 from fnpdjango.utils.models.translation import add_translatable
7
8 class Section(models.Model):
9     slug = models.SlugField(_('slug'))
10     order = models.IntegerField(_('order'))
11
12     class Meta:
13         ordering = ['order']
14         verbose_name = _('section')
15         verbose_name_plural = _('sections')
16
17     def __unicode__(self):
18         return self.name
19
20     def get_absolute_url(self):
21         return "%s?s=%d" % (reverse("curriculum"), self.pk)
22
23     def url_for_level(self, level):
24         return "%s?s=%d&level=%s&d=1" % (reverse("curriculum"), self.pk, level.slug)
25
26 add_translatable(Section, {
27     'name': models.CharField(_('name'), max_length=255, default = '')
28 })
29
30
31 class Competence(models.Model):
32     section = models.ForeignKey(Section)
33     slug = models.SlugField(_('slug'))
34     order = models.IntegerField(_('order'))
35
36     class Meta:
37         ordering = ['section', 'order']
38         verbose_name = _('competence')
39         verbose_name_plural = _('competences')
40
41     def __unicode__(self):
42         return self.name
43
44     def get_absolute_url(self):
45         return "%s?c=%d" % (reverse("curriculum"), self.pk)
46
47     def for_level(self, level):
48         return self.competencelevel_set.get(level=level)
49
50     def url_for_level(self, level):
51         return self.for_level(level).get_absolute_url()
52
53     @classmethod
54     def from_text(cls, text):
55         """Tries to return a Competence or a Section."""
56         parts = re.split(ur'[-\u2013]', text, 1)
57         lookup_field_name = 'name_%s__iexact' % get_language()
58         if len(parts) == 1:
59             return Section.objects.get(**{lookup_field_name: text.strip()})
60         else:
61             return cls.objects.get(**{lookup_field_name: parts[1].strip()})
62
63 add_translatable(Competence, {
64     'name': models.CharField(_('name'), max_length=255, default = '')
65 })
66
67
68 class Level(models.Model):
69     slug = models.CharField(_('slug'), max_length=255, unique=True)
70     meta_name = models.CharField(_('meta name'), max_length=255, unique=True)
71     order = models.IntegerField(_('order'))
72     package = models.FileField(upload_to=lambda i, f: "curriculum/pack/edukacjamedialna_%s.zip" % i.slug,
73         null=True, blank=True, max_length=255)
74     student_package = models.FileField(upload_to=lambda i, f: "curriculum/pack/edukacjamedialna_%s_uczen.zip" % i.slug,
75         null=True, blank=True, max_length=255)
76
77     class Meta:
78         ordering = ['order']
79         verbose_name = _('educational level')
80         verbose_name_plural = _('educational levels')
81
82     def __unicode__(self):
83         return self.name
84
85     def length_course(self):
86         return self.lesson_set.filter(type='course').count()
87
88     def length_synthetic(self):
89         return self.lesson_set.filter(type='synthetic').count()
90
91     def build_package(self, student):
92         from StringIO import StringIO
93         import zipfile
94         from django.core.files.base import ContentFile
95         from catalogue.templatetags.catalogue_tags import section_box
96         from catalogue.models import Lesson
97
98         buff = StringIO()
99         zipf = zipfile.ZipFile(buff, 'w', zipfile.ZIP_STORED)
100
101         lessons = section_box(self)['lessons']
102         for i, lesson in enumerate(lessons['synthetic']):
103             prefix = 'Skrocony kurs/%d %s/' % (i, lesson.slug)
104             lesson.add_to_zip(zipf, student, prefix)
105         for c, (section, clessons) in enumerate(lessons['course'].items()):
106             for i, lesson in enumerate(clessons):
107                 prefix = 'Pelny kurs/%d %s/%d %s/' % (c, section.slug, i, lesson.slug)
108                 lesson.add_to_zip(zipf, student, prefix)
109         for i, lesson in enumerate(lessons['project']):
110             prefix = 'Kurs skrocony/%d %s/' % (i, lesson.slug)
111             lesson.add_to_zip(zipf, student, prefix)
112         # Add all appendix lessons, from all levels.
113         for lesson in Lesson.objects.exclude(type__in=('synthetic', 'course', 'project')):
114             prefix = '%s/' % lesson.slug
115             lesson.add_to_zip(zipf, student, prefix)
116         zipf.close()
117
118         fieldname = "student_package" if student else "package"
119         getattr(self, fieldname).save(None, ContentFile(buff.getvalue()))
120
121     def build_packages(self):
122         self.build_package(False)
123         self.build_package(True)
124
125
126
127 add_translatable(Level, {
128     'name': models.CharField(_('name'), max_length=255, default = ''),
129     'group': models.CharField(_('group'), max_length=255, default = '')
130 })
131
132
133 class CompetenceLevel(models.Model):
134     competence = models.ForeignKey(Competence)
135     level = models.ForeignKey(Level)
136
137     class Meta:
138         ordering = ['competence', 'level']
139         verbose_name = _('competence on level')
140         verbose_name_plural = _('competences on levels')
141
142     def __unicode__(self):
143         return u"%s/%s" % (self.competence, self.level)
144
145     def get_absolute_url(self):
146         return "%s?c=%d&level=%s&d=1" % (reverse("curriculum"), self.competence.pk, self.level.slug)
147
148 add_translatable(CompetenceLevel, {
149     'description': models.TextField(_('description'), default = '')
150 })
151
152
153 class CurriculumLevel(models.Model):
154     title = models.CharField(max_length=16, db_index=True)
155
156     class Meta:
157         verbose_name = _("curriculum level")
158         verbose_name_plural = _("curriculum levels")
159
160     def __unicode__(self):
161         return self.title
162
163
164 class CurriculumCourse(models.Model):
165     title = models.CharField(max_length=255)
166     accusative = models.CharField(max_length=255)
167     slug = models.CharField(max_length=255, db_index=True)
168
169     class Meta:
170         verbose_name = _("curriculum course")
171         verbose_name_plural = _("curriculum courses")
172         ordering = ['slug']
173
174     def __unicode__(self):
175         return self.title
176
177
178 class Curriculum(models.Model):
179     """Official curriculum."""
180     TYPES = {'c': u'Cele kształcenia', 't': u'Treści nauczania'}
181
182     identifier = models.CharField(max_length=255, db_index=True)
183     title = models.CharField(max_length=255)
184     course = models.ForeignKey(CurriculumCourse)
185     level = models.ForeignKey(CurriculumLevel)
186     type = models.CharField(max_length=16, choices=TYPES.items())
187
188     class Meta:
189         verbose_name = _("curriculum item")
190         verbose_name_plural = _("curriculum items")
191
192     def __unicode__(self):
193         return self.identifier
194
195     @classmethod
196     def from_text(cls, identifier, title):
197         m = re.match(r"^\d+/(?P<level>[^/]+)/(?P<course>[^/]+)/"
198                      "(?P<type>(?:%s))[^/]+(?P<roz>/roz)?" %
199                         "|".join(cls.TYPES), identifier)
200         assert m is not None, "Curriculum identifier doesn't match template."
201         level, created = CurriculumLevel.objects.get_or_create(
202                                        title=m.group('level'))
203         def_title = m.group('course').title()
204         course, created = CurriculumCourse.objects.get_or_create(
205                                         slug=m.group('course').lower(),
206                                         defaults={
207                                             'title': def_title,
208                                             'accusative': def_title,
209                                         })
210         type_ = m.group('type')
211         if m.group('roz'):
212             title += " (zakres rozszerzony)"
213
214         try:
215             curr = cls.objects.get(identifier=identifier)
216         except cls.DoesNotExist:
217             curr = cls(identifier=identifier)
218         curr.title = title
219         curr.course = course
220         curr.level = level
221         curr.type = type_
222         curr.save()
223         return curr
224