new exercises
[edumed.git] / catalogue / models.py
index ae87ca8..85f0af0 100644 (file)
@@ -1,8 +1,13 @@
+# -*- coding: utf-8
 from django.core.files import File
 from django.core.urlresolvers import reverse
 from django.db import models
 from jsonfield import JSONField
 from django.core.files import File
 from django.core.urlresolvers import reverse
 from django.db import models
 from jsonfield import JSONField
+from fnpdjango.storage import BofhFileSystemStorage
 from curriculum.models import Level, Curriculum, CurriculumCourse
 from curriculum.models import Level, Curriculum, CurriculumCourse
+import logging
+
+bofh_storage = BofhFileSystemStorage()
 
 
 class Section(models.Model):
 
 
 class Section(models.Model):
@@ -10,10 +15,17 @@ class Section(models.Model):
     slug = models.SlugField(max_length=255, unique=True)
     order = models.IntegerField()
     xml_file = models.FileField(upload_to="catalogue/section/xml",
     slug = models.SlugField(max_length=255, unique=True)
     order = models.IntegerField()
     xml_file = models.FileField(upload_to="catalogue/section/xml",
-        null=True, blank=True, max_length=255)
+        null=True, blank=True, max_length=255,
+        storage=bofh_storage)
     image = models.ImageField(upload_to="catalogue/section/image",
         null=True, blank=True)
 
     image = models.ImageField(upload_to="catalogue/section/image",
         null=True, blank=True)
 
+    pic = models.ImageField(upload_to="catalogue/section/pic", null=True, blank=True)
+    pic_attribution = models.CharField(max_length=255, null=True, blank=True)
+    pic_src = models.URLField(null=True, blank=True)
+    
+    summary = models.TextField(blank=True, null=True)
+
     class Meta:
         ordering = ['order']
 
     class Meta:
         ordering = ['order']
 
@@ -24,20 +36,22 @@ class Section(models.Model):
         return self.title
 
     def get_absolute_url(self):
         return self.title
 
     def get_absolute_url(self):
-        return "%s#%s" % (reverse("catalogue_lessons"), self.slug)
+        return "%s#gimnazjum_%s" % (reverse("catalogue_lessons"), self.slug)
 
     @classmethod
 
     @classmethod
-    def publish(cls, infile):
+    def publish(cls, infile, ignore_incomplete=False):
         from librarian.parser import WLDocument
         from django.core.files.base import ContentFile
         xml = infile.get_string()
         wldoc = WLDocument.from_string(xml)
 
         from librarian.parser import WLDocument
         from django.core.files.base import ContentFile
         xml = infile.get_string()
         wldoc = WLDocument.from_string(xml)
 
-        try:
-            lessons = [Lesson.objects.get(slug=part.slug)
-                        for part in wldoc.book_info.parts]
-        except Lesson.DoesNotExist, e:
-            raise cls.IncompleteError(part.slug)
+        lessons = []
+        for part in wldoc.book_info.parts:
+            try:
+                lessons.append(Lesson.objects.get(slug=part.slug))
+            except Lesson.DoesNotExist, e:
+                if not ignore_incomplete:
+                    raise cls.IncompleteError(part.slug)
 
         slug = wldoc.book_info.url.slug
         try:
 
         slug = wldoc.book_info.url.slug
         try:
@@ -74,19 +88,20 @@ class Lesson(models.Model):
     order = models.IntegerField(db_index=True)
     dc = JSONField(default='{}')
     curriculum_courses = models.ManyToManyField(CurriculumCourse, blank=True)
     order = models.IntegerField(db_index=True)
     dc = JSONField(default='{}')
     curriculum_courses = models.ManyToManyField(CurriculumCourse, blank=True)
+    description = models.TextField(null=True, blank=True)
 
     xml_file = models.FileField(upload_to="catalogue/lesson/xml",
 
     xml_file = models.FileField(upload_to="catalogue/lesson/xml",
-        null=True, blank=True, max_length=255)
+        null=True, blank=True, max_length=255, storage=bofh_storage)
     html_file = models.FileField(upload_to="catalogue/lesson/html",
     html_file = models.FileField(upload_to="catalogue/lesson/html",
-        null=True, blank=True, max_length=255)
+        null=True, blank=True, max_length=255, storage=bofh_storage)
     package = models.FileField(upload_to="catalogue/lesson/pack",
     package = models.FileField(upload_to="catalogue/lesson/pack",
-        null=True, blank=True, max_length=255)
+        null=True, blank=True, max_length=255, storage=bofh_storage)
     student_package = models.FileField(upload_to="catalogue/lesson/student_pack",
     student_package = models.FileField(upload_to="catalogue/lesson/student_pack",
-        null=True, blank=True, max_length=255)
+        null=True, blank=True, max_length=255, storage=bofh_storage)
     pdf = models.FileField(upload_to="catalogue/lesson/pdf",
     pdf = models.FileField(upload_to="catalogue/lesson/pdf",
-        null=True, blank=True, max_length=255)
+        null=True, blank=True, max_length=255, storage=bofh_storage)
     student_pdf = models.FileField(upload_to="catalogue/lesson/student_pdf",
     student_pdf = models.FileField(upload_to="catalogue/lesson/student_pdf",
-        null=True, blank=True, max_length=255)
+        null=True, blank=True, max_length=255, storage=bofh_storage)
 
     class Meta:
         ordering = ['section', 'level', 'order']
 
     class Meta:
         ordering = ['section', 'level', 'order']
@@ -99,7 +114,7 @@ class Lesson(models.Model):
         return ('catalogue_lesson', [self.slug])
 
     @classmethod
         return ('catalogue_lesson', [self.slug])
 
     @classmethod
-    def publish(cls, infile):
+    def publish(cls, infile, ignore_incomplete=False):
         from librarian.parser import WLDocument
         from django.core.files.base import ContentFile
         xml = infile.get_string()
         from librarian.parser import WLDocument
         from django.core.files.base import ContentFile
         xml = infile.get_string()
@@ -107,8 +122,8 @@ class Lesson(models.Model):
 
         # Check if not section metadata block.
         if wldoc.book_info.parts:
 
         # Check if not section metadata block.
         if wldoc.book_info.parts:
-            return Section.publish(infile)
-        
+            return Section.publish(infile, ignore_incomplete=ignore_incomplete)
+
         slug = wldoc.book_info.url.slug
         try:
             lesson = cls.objects.get(slug=slug)
         slug = wldoc.book_info.url.slug
         try:
             lesson = cls.objects.get(slug=slug)
@@ -120,13 +135,15 @@ class Lesson(models.Model):
         lesson.xml_file.save('%s.xml' % slug, ContentFile(xml), save=False)
         lesson.title = wldoc.book_info.title
 
         lesson.xml_file.save('%s.xml' % slug, ContentFile(xml), save=False)
         lesson.title = wldoc.book_info.title
 
-        lesson.level = Level.objects.get(slug=wldoc.book_info.audience)
+        lesson.level = Level.objects.get(meta_name=wldoc.book_info.audience)
         lesson.populate_dc()
         lesson.populate_dc()
+        lesson.populate_description(wldoc=wldoc)
         lesson.build_html(infile=infile)
         lesson.build_html(infile=infile)
-        lesson.build_pdf(infile=infile)
-        lesson.build_pdf(student=True, infile=infile)
+        lesson.build_pdf()
         lesson.build_package()
         lesson.build_package()
-        lesson.build_package(student=True)
+        if lesson.type != 'project':
+            lesson.build_pdf(student=True)
+            lesson.build_package(student=True)
         return lesson
 
     def populate_dc(self):
         return lesson
 
     def populate_dc(self):
@@ -134,18 +151,38 @@ class Lesson(models.Model):
         wldoc = WLDocument.from_file(self.xml_file.path)
         self.dc = wldoc.book_info.to_dict()
         self.type = self.dc["type"]
         wldoc = WLDocument.from_file(self.xml_file.path)
         self.dc = wldoc.book_info.to_dict()
         self.type = self.dc["type"]
+        assert self.type in ('appendix', 'course', 'synthetic', 'project', 'added', 'added-var'), \
+            u"Unknown lesson type: %s" % self.type
         self.save()
 
         courses = set()
         for identifier in wldoc.book_info.curriculum:
         self.save()
 
         courses = set()
         for identifier in wldoc.book_info.curriculum:
+            identifier = (identifier or "").replace(' ', '')
+            if not identifier: continue
             try:
             try:
-                curr = Curriculum.objects.get(identifier=identifier)
+                curr = Curriculum.objects.get(identifier__iexact=identifier)
             except Curriculum.DoesNotExist:
             except Curriculum.DoesNotExist:
+                logging.warn('Unknown curriculum course %s in lesson %s' % (identifier, self.slug))
                 pass
             else:
                 courses.add(curr.course)
         self.curriculum_courses = courses
 
                 pass
             else:
                 courses.add(curr.course)
         self.curriculum_courses = courses
 
+    def populate_description(self, wldoc=None, infile=None):
+        if wldoc is None:
+            wldoc = self.wldocument(infile)
+        if self.type == 'project':
+            lookup = u'Zadanie'
+        else:
+            lookup = u'Pomysł na lekcję'
+        for header in wldoc.edoc.findall('.//naglowek_rozdzial'):
+            if (header.text or '').strip() == lookup:
+                from lxml import etree
+                self.description = etree.tostring(header.getnext(),
+                        method='text', encoding='unicode').strip()
+                self.save()
+                return
+
     def wldocument(self, infile=None):
         from librarian import IOFile
         from librarian.parser import WLDocument
     def wldocument(self, infile=None):
         from librarian import IOFile
         from librarian.parser import WLDocument
@@ -165,9 +202,11 @@ class Lesson(models.Model):
         self.html_file.save("%s.html" % self.slug,
             File(open(html.get_filename())))
 
         self.html_file.save("%s.html" % self.slug,
             File(open(html.get_filename())))
 
-    def build_pdf(self, student=False, infile=None):
+    def build_pdf(self, student=False):
         from .publish import PdfFormat
         from .publish import PdfFormat
-        wldoc = self.wldocument(infile)
+        # PDF uses document with attachments already saved as media,
+        # otherwise sorl.thumbnail complains about SuspiciousOperations.
+        wldoc = self.wldocument()
         if student:
             pdf = PdfFormat(wldoc).build()
             self.student_pdf.save("%s.pdf" % self.slug,
         if student:
             pdf = PdfFormat(wldoc).build()
             self.student_pdf.save("%s.pdf" % self.slug,
@@ -178,17 +217,15 @@ class Lesson(models.Model):
                 File(open(pdf.get_filename())))
 
     def add_to_zip(self, zipf, student=False, prefix=''):
                 File(open(pdf.get_filename())))
 
     def add_to_zip(self, zipf, student=False, prefix=''):
-        zipf.write(self.xml_file.path,
-            "%spliki-zrodlowe/%s.xml" % (prefix, self.slug))
         pdf = self.student_pdf if student else self.pdf
         if pdf:
             zipf.write(pdf.path, 
                 "%s%s%s.pdf" % (prefix, self.slug, "_student" if student else ""))
         pdf = self.student_pdf if student else self.pdf
         if pdf:
             zipf.write(pdf.path, 
                 "%s%s%s.pdf" % (prefix, self.slug, "_student" if student else ""))
-        for attachment in self.attachment_set.all():
-            zipf.write(attachment.file.path,
-                u"%smaterialy/%s.%s" % (prefix, attachment.slug, attachment.ext))
-            
-        
+            for attachment in self.attachment_set.all():
+                zipf.write(attachment.file.path,
+                    u"%smaterialy/%s.%s" % (prefix, attachment.slug, attachment.ext))
+            zipf.write(self.xml_file.path,
+                "%spliki-zrodlowe/%s.xml" % (prefix, self.slug))
 
     def build_package(self, student=False):
         from StringIO import StringIO
 
     def build_package(self, student=False):
         from StringIO import StringIO
@@ -231,12 +268,15 @@ class Lesson(models.Model):
         except IndexError:
             return None
 
         except IndexError:
             return None
 
+    def requires_internet(self):
+        return 'internet' in self.dc.get('requires', [])
+
 
 class Attachment(models.Model):
     slug = models.CharField(max_length=255)
     ext = models.CharField(max_length=15)
     lesson = models.ForeignKey(Lesson)
 
 class Attachment(models.Model):
     slug = models.CharField(max_length=255)
     ext = models.CharField(max_length=15)
     lesson = models.ForeignKey(Lesson)
-    file = models.FileField(upload_to="catalogue/attachment")
+    file = models.FileField(upload_to="catalogue/attachment", storage=bofh_storage)
 
     class Meta:
         ordering = ['slug', 'ext']
 
     class Meta:
         ordering = ['slug', 'ext']
@@ -266,3 +306,10 @@ class LessonStub(models.Model):
 
     def __unicode__(self):
         return self.title
 
     def __unicode__(self):
         return self.title
+
+    @property
+    def slug(self):
+        return ''
+
+    def add_to_zip(self, *args, **kwargs):
+        pass