2 from django.core.files import File
3 from django.core.urlresolvers import reverse
4 from django.db import models
5 from jsonfield import JSONField
6 from curriculum.models import Level, Curriculum, CurriculumCourse
11 class Section(models.Model):
12 title = models.CharField(max_length=255, unique=True)
13 slug = models.SlugField(max_length=255, unique=True)
14 order = models.IntegerField()
15 xml_file = models.FileField(upload_to="catalogue/section/xml",
16 null=True, blank=True, max_length=255)
17 image = models.ImageField(upload_to="catalogue/section/image",
18 null=True, blank=True)
20 pic = models.ImageField(upload_to="catalogue/section/pic", null=True, blank=True)
21 pic_attribution = models.CharField(max_length=255, null=True, blank=True)
22 pic_src = models.URLField(null=True, blank=True)
24 summary = models.TextField(blank=True, null=True)
29 class IncompleteError(BaseException):
32 def __unicode__(self):
35 def get_absolute_url(self):
36 return "%s#gimnazjum_%s" % (reverse("catalogue_lessons"), self.slug)
39 def publish(cls, infile, ignore_incomplete=False):
40 from librarian.parser import WLDocument
41 from django.core.files.base import ContentFile
42 xml = infile.get_string()
43 wldoc = WLDocument.from_string(xml)
46 for part in wldoc.book_info.parts:
48 lessons.append(Lesson.objects.get(slug=part.slug))
49 except Lesson.DoesNotExist, e:
50 if not ignore_incomplete:
51 raise cls.IncompleteError(part.slug)
53 slug = wldoc.book_info.url.slug
55 section = cls.objects.get(slug=slug)
56 except cls.DoesNotExist:
57 section = cls(slug=slug, order=0)
60 section.xml_file.save('%s.xml' % slug, ContentFile(xml), save=False)
61 section.title = wldoc.book_info.title
64 section.lesson_set.all().update(section=None)
65 for i, lesson in enumerate(lessons):
66 lesson.section = section
72 def syntetic_lesson(self, level):
74 return self.lesson_set.filter(type='synthetic', level=level)[0]
79 class Lesson(models.Model):
80 section = models.ForeignKey(Section, null=True, blank=True)
81 level = models.ForeignKey(Level)
82 title = models.CharField(max_length=255)
83 slug = models.SlugField(max_length=255, unique=True)
84 type = models.CharField(max_length=15, db_index=True)
85 order = models.IntegerField(db_index=True)
86 dc = JSONField(default='{}')
87 curriculum_courses = models.ManyToManyField(CurriculumCourse, blank=True)
88 description = models.TextField(null=True, blank=True)
90 xml_file = models.FileField(upload_to="catalogue/lesson/xml",
91 null=True, blank=True, max_length=255)
92 html_file = models.FileField(upload_to="catalogue/lesson/html",
93 null=True, blank=True, max_length=255)
94 package = models.FileField(upload_to="catalogue/lesson/pack",
95 null=True, blank=True, max_length=255)
96 student_package = models.FileField(upload_to="catalogue/lesson/student_pack",
97 null=True, blank=True, max_length=255)
98 pdf = models.FileField(upload_to="catalogue/lesson/pdf",
99 null=True, blank=True, max_length=255)
100 student_pdf = models.FileField(upload_to="catalogue/lesson/student_pdf",
101 null=True, blank=True, max_length=255)
104 ordering = ['section', 'level', 'order']
106 def __unicode__(self):
110 def get_absolute_url(self):
111 return ('catalogue_lesson', [self.slug])
114 def publish(cls, infile, ignore_incomplete=False):
115 from librarian.parser import WLDocument
116 from django.core.files.base import ContentFile
117 xml = infile.get_string()
118 wldoc = WLDocument.from_string(xml)
120 # Check if not section metadata block.
121 if wldoc.book_info.parts:
122 return Section.publish(infile, ignore_incomplete=ignore_incomplete)
124 slug = wldoc.book_info.url.slug
126 lesson = cls.objects.get(slug=slug)
127 lesson.attachment_set.all().delete()
128 except cls.DoesNotExist:
129 lesson = cls(slug=slug, order=0)
132 lesson.xml_file.save('%s.xml' % slug, ContentFile(xml), save=False)
133 lesson.title = wldoc.book_info.title
135 lesson.level = Level.objects.get(meta_name=wldoc.book_info.audience)
137 lesson.populate_description(wldoc=wldoc)
138 lesson.build_html(infile=infile)
140 lesson.build_package()
141 if lesson.type != 'project':
142 lesson.build_pdf(student=True)
143 lesson.build_package(student=True)
146 def populate_dc(self):
147 from librarian.parser import WLDocument
148 wldoc = WLDocument.from_file(self.xml_file.path)
149 self.dc = wldoc.book_info.to_dict()
150 self.type = self.dc["type"]
151 assert self.type in ('appendix', 'course', 'synthetic', 'project'), \
152 u"Unknown lesson type: %s" % self.type
156 for identifier in wldoc.book_info.curriculum:
157 identifier = (identifier or "").replace(' ', '')
158 if not identifier: continue
160 curr = Curriculum.objects.get(identifier__iexact=identifier)
161 except Curriculum.DoesNotExist:
162 logging.warn('Unknown curriculum course %s in lesson %s' % (identifier, self.slug))
165 courses.add(curr.course)
166 self.curriculum_courses = courses
168 def populate_description(self, wldoc=None, infile=None):
170 wldoc = self.wldocument(infile)
171 for nagl in wldoc.edoc.findall('.//naglowek_rozdzial'):
172 if (nagl.text or '').strip() == u'Pomysł na lekcję':
173 from lxml import etree
174 self.description = etree.tostring(nagl.getnext(),
175 method='text', encoding='unicode').strip()
179 def wldocument(self, infile=None):
180 from librarian import IOFile
181 from librarian.parser import WLDocument
182 from .publish import OrmDocProvider
185 infile = IOFile.from_filename(self.xml_file.path)
186 for att in self.attachment_set.all():
187 infile.attachments["%s.%s" % (att.slug, att.ext)] = \
188 IOFile.from_filename(att.file.path)
189 return WLDocument(infile, provider=OrmDocProvider())
191 def build_html(self, infile=None):
192 from .publish import HtmlFormat
193 wldoc = self.wldocument(infile)
194 html = HtmlFormat(wldoc).build()
195 self.html_file.save("%s.html" % self.slug,
196 File(open(html.get_filename())))
198 def build_pdf(self, student=False):
199 from .publish import PdfFormat
200 # PDF uses document with attachments already saved as media,
201 # otherwise sorl.thumbnail complains about SuspiciousOperations.
202 wldoc = self.wldocument()
204 pdf = PdfFormat(wldoc).build()
205 self.student_pdf.save("%s.pdf" % self.slug,
206 File(open(pdf.get_filename())))
208 pdf = PdfFormat(wldoc, teacher=True).build()
209 self.pdf.save("%s.pdf" % self.slug,
210 File(open(pdf.get_filename())))
212 def add_to_zip(self, zipf, student=False, prefix=''):
213 pdf = self.student_pdf if student else self.pdf
216 "%s%s%s.pdf" % (prefix, self.slug, "_student" if student else ""))
217 for attachment in self.attachment_set.all():
218 zipf.write(attachment.file.path,
219 u"%smaterialy/%s.%s" % (prefix, attachment.slug, attachment.ext))
220 zipf.write(self.xml_file.path,
221 "%spliki-zrodlowe/%s.xml" % (prefix, self.slug))
223 def build_package(self, student=False):
224 from StringIO import StringIO
226 from django.core.files.base import ContentFile
228 zipf = zipfile.ZipFile(buff, 'w', zipfile.ZIP_STORED)
229 self.add_to_zip(zipf, student)
231 fieldname = "student_package" if student else "package"
232 getattr(self, fieldname).save(
233 "%s%s.zip" % (self.slug, "_student" if student else ""),
234 ContentFile(buff.getvalue()))
236 def get_syntetic(self):
237 if self.section is None: return None
238 return self.section.syntetic_lesson(self.level)
240 def get_other_level(self):
241 if self.section is None: return None
242 other_levels = self.section.lesson_set.exclude(level=self.level)
243 if other_levels.exists():
244 return other_levels[0].level
246 def get_previous(self):
247 if self.section is None: return None
249 return self.section.lesson_set.filter(
250 type=self.type, level=self.level,
251 order__lt=self.order).order_by('-order')[0]
256 if self.section is None: return None
258 return self.section.lesson_set.filter(
259 type=self.type, level=self.level,
260 order__gt=self.order).order_by('order')[0]
264 def requires_internet(self):
265 return 'internet' in self.dc.get('requires', [])
268 class Attachment(models.Model):
269 slug = models.CharField(max_length=255)
270 ext = models.CharField(max_length=15)
271 lesson = models.ForeignKey(Lesson)
272 file = models.FileField(upload_to="catalogue/attachment")
275 ordering = ['slug', 'ext']
276 unique_together = ['lesson', 'slug', 'ext']
278 def __unicode__(self):
279 return "%s.%s" % (self.slug, self.ext)
282 class Part(models.Model):
283 lesson = models.ForeignKey(Lesson)
284 pdf = models.FileField(upload_to="catalogue/part/pdf",
285 null=True, blank=True)
286 student_pdf = models.FileField(upload_to="catalogue/part/student_pdf",
287 null=True, blank=True)
290 class LessonStub(models.Model):
291 section = models.ForeignKey(Section, null=True, blank=True)
292 level = models.ForeignKey(Level)
293 title = models.CharField(max_length=255)
294 type = models.CharField(max_length=15, db_index=True)
295 order = models.IntegerField(db_index=True)
298 ordering = ['section', 'level', 'order']
300 def __unicode__(self):
307 def add_to_zip(self, *args, **kwargs):