Add related lessons.
[edumed.git] / catalogue / models.py
1 from django.core.files import File
2 from django.core.urlresolvers import reverse
3 from django.db import models
4 from jsonfield import JSONField
5 from curriculum.models import Level
6
7
8 class Section(models.Model):
9     title = models.CharField(max_length=255, unique=True)
10     slug = models.SlugField(unique=True)
11     order = models.IntegerField()
12     xml_file = models.FileField(upload_to="catalogue/section/xml",
13         null=True, blank=True)
14
15     class Meta:
16         ordering = ['order']
17
18     class IncompleteError(BaseException):
19         pass
20
21     def __unicode__(self):
22         return self.title
23
24     def get_absolute_url(self):
25         return "%s#%s" % (reverse("catalogue_lessons"), self.slug)
26
27     @classmethod
28     def publish(cls, infile):
29         from librarian.parser import WLDocument
30         from django.core.files.base import ContentFile
31         xml = infile.get_string()
32         wldoc = WLDocument.from_string(xml)
33
34         try:
35             lessons = [Lesson.objects.get(slug=part.slug)
36                         for part in wldoc.book_info.parts]
37         except Lesson.DoesNotExist, e:
38             raise cls.IncompleteError(part.slug)
39
40         slug = wldoc.book_info.url.slug
41         try:
42             section = cls.objects.get(slug=slug)
43         except cls.DoesNotExist:
44             section = cls(slug=slug, order=0)
45
46         # Save XML file
47         section.xml_file.save('%s.xml' % slug, ContentFile(xml), save=False)
48         section.title = wldoc.book_info.title
49         section.save()
50
51         section.lesson_set.all().update(section=None)
52         for i, lesson in enumerate(lessons):
53             lesson.section = section
54             lesson.order = i
55             lesson.save()
56
57         return section
58
59     def syntetic_lesson(self, level):
60         try:
61             return self.lesson_set.filter(type='synthetic', level=level)[0]
62         except IndexError:
63             return None
64
65
66 class Lesson(models.Model):
67     section = models.ForeignKey(Section, null=True, blank=True)
68     level = models.ForeignKey(Level)
69     title = models.CharField(max_length=255)
70     slug = models.SlugField(unique=True)
71     type = models.CharField(max_length=15, db_index=True)
72     order = models.IntegerField(db_index=True)
73     dc = JSONField(default='{}')
74
75     xml_file = models.FileField(upload_to="catalogue/lesson/xml",
76         null=True, blank=True) # FIXME: slug in paths
77     html_file = models.FileField(upload_to="catalogue/lesson/html",
78         null=True, blank=True)
79     package = models.FileField(upload_to="catalogue/lesson/pack",
80         null=True, blank=True)
81     student_package = models.FileField(upload_to="catalogue/lesson/student_pack",
82         null=True, blank=True)
83     pdf = models.FileField(upload_to="catalogue/lesson/pdf",
84         null=True, blank=True)
85     student_pdf = models.FileField(upload_to="catalogue/lesson/student_pdf",
86         null=True, blank=True)
87
88     class Meta:
89         ordering = ['section', 'level', 'order']
90
91     def __unicode__(self):
92         return self.title
93
94     @models.permalink
95     def get_absolute_url(self):
96         return ('catalogue_lesson', [self.slug])
97
98     @classmethod
99     def publish(cls, infile):
100         from librarian.parser import WLDocument
101         from django.core.files.base import ContentFile
102         xml = infile.get_string()
103         wldoc = WLDocument.from_string(xml)
104
105         # Check if not section metadata block.
106         if wldoc.book_info.parts:
107             return Section.publish(infile)
108         
109         slug = wldoc.book_info.url.slug
110         try:
111             lesson = cls.objects.get(slug=slug)
112         except cls.DoesNotExist:
113             lesson = cls(slug=slug)
114
115         lesson.attachment_set.all().delete()
116         for att_name, att_file in infile.attachments.items():
117             try:
118                 slug, ext = att_name.rsplit('.', 1)
119             except ValueError:
120                 slug, ext = att_name, ''
121             attachment = lesson.attachment_set.create(slug=slug, ext=ext)
122             attachment.file.save(att_name, ContentFile(att_file.get_string()))
123
124         # Save XML file
125         lesson.xml_file.save('%s.xml' % slug, ContentFile(xml), save=False)
126         lesson.title = wldoc.book_info.title
127
128         lesson.level = Level.objects.get(slug=wldoc.book_info.audience)
129         lesson.order = 0
130         lesson.populate_dc()
131         lesson.type = lesson.dc["type"]
132         lesson.save()
133         lesson.build_html()
134         lesson.build_package()
135         lesson.build_package(student=True)
136         return lesson
137
138     def populate_dc(self):
139         from librarian.parser import WLDocument
140         wldoc = WLDocument.from_file(self.xml_file.path)
141         self.dc = wldoc.book_info.to_dict()
142         self.save()
143
144     def build_html(self):
145         from librarian.parser import WLDocument
146         wldoc = WLDocument.from_file(self.xml_file.path)
147         html = wldoc.as_html()
148         self.html_file.save("%s.html" % self.slug,
149             File(open(html.get_filename())))
150
151     def add_to_zip(self, zipf, student=False, prefix=''):
152         zipf.write(self.xml_file.path,
153             "%spliki-zrodlowe/%s.xml" % (prefix, self.slug))
154         pdf = self.student_pdf if student else self.pdf
155         if pdf:
156             zipf.write(self.xml_file.path, 
157                 "%s%s%s.pdf" % (prefix, self.slug, "_student" if student else ""))
158         
159
160     def build_package(self, student=False):
161         from StringIO import StringIO
162         import zipfile
163         from django.core.files.base import ContentFile
164         buff = StringIO()
165         zipf = zipfile.ZipFile(buff, 'w', zipfile.ZIP_STORED)
166         self.add_to_zip(zipf, student)
167         zipf.close()
168         fieldname = "student_package" if student else "package"
169         getattr(self, fieldname).save(
170             "%s%s.zip" % (self.slug, "_student" if student else ""),
171             ContentFile(buff.getvalue()))
172
173     def get_syntetic(self):
174         return self.section.syntetic_lesson(self.level)
175
176
177 class Attachment(models.Model):
178     slug = models.CharField(max_length=255)
179     ext = models.CharField(max_length=15)
180     lesson = models.ForeignKey(Lesson)
181     file = models.FileField(upload_to="catalogue/attachment")
182
183     class Meta:
184         ordering = ['slug', 'ext']
185         unique_together = ['lesson', 'slug', 'ext']
186
187     def __unicode__(self):
188         return "%s.%s" % (self.slug, self.ext)
189
190
191 class Part(models.Model):
192     lesson = models.ForeignKey(Lesson)
193     pdf = models.FileField(upload_to="catalogue/part/pdf",
194         null=True, blank=True)
195     student_pdf = models.FileField(upload_to="catalogue/part/student_pdf",
196         null=True, blank=True)