From: Radek Czajka Date: Fri, 31 Jan 2014 11:57:43 +0000 (+0100) Subject: Prepared for SP 4-6. X-Git-Url: https://git.mdrn.pl/edumed.git/commitdiff_plain/ea300f6c03d47f6c17dd7721b8d6690489af79da?hp=4d0e6b0b3f32591d2c9c3c3af85b1ffc289cfa4d Prepared for SP 4-6. - Main and lesson list pages overhaul. - Lessons now inform about internet requirements and publisher. - PDF support for (by sorl.thumnail with ImageMagick) - Add summary and picture for Sections, description for Lesson. - Level slug and meta dc:audience value can be different. - Per-level lesson packages instead of global ones. - Lesson packages are now rebuilt after import. - Add option for allowing incomplete sections on import. - Django 1.6, `django-piwik` replaces `piwik`. --- diff --git a/catalogue/management/commands/importlessons.py b/catalogue/management/commands/importlessons.py index 4e7a38c..83bf68b 100755 --- a/catalogue/management/commands/importlessons.py +++ b/catalogue/management/commands/importlessons.py @@ -23,15 +23,17 @@ class Command(BaseCommand): help='Verbosity level; 0=minimal output, 1=normal output, 2=all output'), make_option('-a', '--attachments', dest='attachments', metavar="PATH", default='materialy', help='Attachments dir path.'), + make_option('--ignore-incomplete', action='store_true', dest='ignore_incomplete', default=False, + help='Attachments dir path.'), ) help = 'Imports lessons from the specified directories.' args = 'directory [directory ...]' - def import_book(self, file_path, options, attachments): + def import_book(self, file_path, options, attachments, ignore_incomplete=False): verbose = options.get('verbose') iofile = IOFile.from_filename(os.path.join(self.curdir, file_path)) iofile.attachments = attachments - lesson = Lesson.publish(iofile) + return Lesson.publish(iofile, ignore_incomplete) @staticmethod def all_attachments(path): @@ -52,8 +54,9 @@ class Command(BaseCommand): def handle(self, *directories, **options): - from django.db import transaction + from django.db import connection, transaction + levels = set() self.style = color_style() verbose = options.get('verbose') @@ -61,9 +64,14 @@ class Command(BaseCommand): # Start transaction management. - transaction.commit_unless_managed() - transaction.enter_transaction_management() - transaction.managed(True) + # SQLite will choke on generating thumbnails + use_transaction = not connection.features.autocommits_when_autocommit_is_off + if use_transaction: + transaction.commit_unless_managed() + transaction.enter_transaction_management() + transaction.managed(True) + else: + print 'WARNING: Not using transaction management.' files_imported = 0 files_skipped = 0 @@ -79,6 +87,7 @@ class Command(BaseCommand): # files queue files = sorted(os.listdir(abs_dir)) postponed = {} + ignore_incomplete = set() while files: file_name = files.pop(0) file_path = os.path.join(abs_dir, file_name) @@ -96,9 +105,8 @@ class Command(BaseCommand): # Import book files try: - self.import_book(file_path, options, attachments) - files_imported += 1 - transaction.commit() + lesson = self.import_book(file_path, options, attachments, + ignore_incomplete=file_name in ignore_incomplete) except Section.IncompleteError, e: if file_name not in postponed or postponed[file_name] < files_imported: # Push it back into the queue, maybe the missing lessons will show up. @@ -106,6 +114,10 @@ class Command(BaseCommand): print self.style.NOTICE('Waiting for missing lessons.') files.append(file_name) postponed[file_name] = files_imported + elif options['ignore_incomplete'] and file_name not in ignore_incomplete: + files.append(file_name) + ignore_incomplete.add(file_name) + postponed[file_name] = files_imported else: # We're in a loop, nothing's being imported - some lesson is really missing. raise e @@ -113,6 +125,22 @@ class Command(BaseCommand): import traceback traceback.print_exc() files_skipped += 1 + else: + files_imported += 1 + if use_transaction: + transaction.commit() + if hasattr(lesson, 'level'): + levels.add(lesson.level) + finally: + if verbose > 0: + print + + + if levels: + print "Rebuilding level packages:" + for level in levels: + print level.name + level.build_packages() # Print results print @@ -120,5 +148,6 @@ class Command(BaseCommand): files_imported, files_skipped, files_imported + files_skipped) print - transaction.commit() - transaction.leave_transaction_management() + if use_transaction: + transaction.commit() + transaction.leave_transaction_management() diff --git a/catalogue/management/commands/repackage.py b/catalogue/management/commands/repackage.py index 3946e82..f3ae5e8 100755 --- a/catalogue/management/commands/repackage.py +++ b/catalogue/management/commands/repackage.py @@ -2,61 +2,15 @@ # This file is part of EduMed, licensed under GNU Affero GPLv3 or later. # Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information. # -import os from optparse import make_option -from django.conf import settings from django.core.management.base import BaseCommand -from catalogue.models import Section -import zipfile class Command(BaseCommand): - option_list = BaseCommand.option_list + ( - make_option('-q', '--quiet', action='store_false', dest='verbose', default=True, - help='Verbosity level; 0=minimal output, 1=normal output, 2=all output'), - ) help = 'Rebuilds downloadable packages.' - def build_package(self, zippath, student, verbose): - with open(zippath, 'w') as outf: - zipf = zipfile.ZipFile(outf, 'w', zipfile.ZIP_STORED) - - for si, section in enumerate(Section.objects.all()): - li = 1 - li_adv = 1 - for lesson in section.lesson_set.all(): - advanced = lesson.level.slug == "liceum" - section_dir = "%d_%s%s" % ( - si + 1, section.slug, - " (zaawansowane)" if advanced else "") - if lesson.type == 'course': - if advanced: - ind = li_adv - li_adv += 1 - else: - ind = li - li += 1 - prefix = "%s/%02d_%s/" % ( - section_dir, ind, lesson.slug, - ) - elif lesson.type == 'synthetic': - prefix = "%s/%s (synteza)/" % ( - section_dir, lesson.slug) - elif lesson.type == 'project': - prefix = "%s/%s (projekt)/" % ( - section_dir, lesson.slug) - else: - prefix = "%s/%s/" % ( - section_dir, lesson.slug) - lesson.add_to_zip(zipf, student, prefix) - zipf.close() - def handle(self, **options): - verbose = options.get('verbose') + from curriculum.models import Level - self.build_package( - os.path.join(settings.MEDIA_ROOT, settings.CATALOGUE_PACKAGE), - False, verbose) - self.build_package( - os.path.join(settings.MEDIA_ROOT, settings.CATALOGUE_PACKAGE_STUDENT), - True, verbose) + for level in Level.objects.all(): + level.build_packages() diff --git a/catalogue/migrations/0014_auto__add_field_section_summary.py b/catalogue/migrations/0014_auto__add_field_section_summary.py new file mode 100644 index 0000000..7805ec7 --- /dev/null +++ b/catalogue/migrations/0014_auto__add_field_section_summary.py @@ -0,0 +1,94 @@ +# -*- coding: utf-8 -*- +import datetime +from south.db import db +from south.v2 import SchemaMigration +from django.db import models + + +class Migration(SchemaMigration): + + def forwards(self, orm): + # Adding field 'Section.summary' + db.add_column(u'catalogue_section', 'summary', + self.gf('django.db.models.fields.TextField')(null=True, blank=True), + keep_default=False) + + + def backwards(self, orm): + # Deleting field 'Section.summary' + db.delete_column(u'catalogue_section', 'summary') + + + models = { + u'catalogue.attachment': { + 'Meta': {'ordering': "['slug', 'ext']", 'unique_together': "(['lesson', 'slug', 'ext'],)", 'object_name': 'Attachment'}, + 'ext': ('django.db.models.fields.CharField', [], {'max_length': '15'}), + 'file': ('django.db.models.fields.files.FileField', [], {'max_length': '100'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'lesson': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['catalogue.Lesson']"}), + 'slug': ('django.db.models.fields.CharField', [], {'max_length': '255'}) + }, + u'catalogue.lesson': { + 'Meta': {'ordering': "['section', 'level', 'order']", 'object_name': 'Lesson'}, + 'curriculum_courses': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['curriculum.CurriculumCourse']", 'symmetrical': 'False', 'blank': 'True'}), + 'dc': ('jsonfield.fields.JSONField', [], {'default': "'{}'"}), + 'html_file': ('django.db.models.fields.files.FileField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'level': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['curriculum.Level']"}), + 'order': ('django.db.models.fields.IntegerField', [], {'db_index': 'True'}), + 'package': ('django.db.models.fields.files.FileField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), + 'pdf': ('django.db.models.fields.files.FileField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), + 'section': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['catalogue.Section']", 'null': 'True', 'blank': 'True'}), + 'slug': ('django.db.models.fields.SlugField', [], {'unique': 'True', 'max_length': '255'}), + 'student_package': ('django.db.models.fields.files.FileField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), + 'student_pdf': ('django.db.models.fields.files.FileField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), + 'title': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'type': ('django.db.models.fields.CharField', [], {'max_length': '15', 'db_index': 'True'}), + 'xml_file': ('django.db.models.fields.files.FileField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}) + }, + u'catalogue.lessonstub': { + 'Meta': {'ordering': "['section', 'level', 'order']", 'object_name': 'LessonStub'}, + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'level': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['curriculum.Level']"}), + 'order': ('django.db.models.fields.IntegerField', [], {'db_index': 'True'}), + 'section': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['catalogue.Section']", 'null': 'True', 'blank': 'True'}), + 'title': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'type': ('django.db.models.fields.CharField', [], {'max_length': '15', 'db_index': 'True'}) + }, + u'catalogue.part': { + 'Meta': {'object_name': 'Part'}, + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'lesson': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['catalogue.Lesson']"}), + 'pdf': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}), + 'student_pdf': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}) + }, + u'catalogue.section': { + 'Meta': {'ordering': "['order']", 'object_name': 'Section'}, + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'image': ('django.db.models.fields.files.ImageField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}), + 'order': ('django.db.models.fields.IntegerField', [], {}), + 'slug': ('django.db.models.fields.SlugField', [], {'unique': 'True', 'max_length': '255'}), + 'summary': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'title': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}), + 'xml_file': ('django.db.models.fields.files.FileField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}) + }, + u'curriculum.curriculumcourse': { + 'Meta': {'ordering': "['slug']", 'object_name': 'CurriculumCourse'}, + 'accusative': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'slug': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}), + 'title': ('django.db.models.fields.CharField', [], {'max_length': '255'}) + }, + u'curriculum.level': { + 'Meta': {'ordering': "['order']", 'object_name': 'Level'}, + 'group_en': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '255'}), + 'group_pl': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '255'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name_en': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '255'}), + 'name_pl': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '255'}), + 'order': ('django.db.models.fields.IntegerField', [], {}), + 'slug': ('django.db.models.fields.CharField', [], {'max_length': '255'}) + } + } + + complete_apps = ['catalogue'] \ No newline at end of file diff --git a/catalogue/migrations/0015_auto__add_field_lesson_description.py b/catalogue/migrations/0015_auto__add_field_lesson_description.py new file mode 100644 index 0000000..6d7dd5d --- /dev/null +++ b/catalogue/migrations/0015_auto__add_field_lesson_description.py @@ -0,0 +1,95 @@ +# -*- coding: utf-8 -*- +import datetime +from south.db import db +from south.v2 import SchemaMigration +from django.db import models + + +class Migration(SchemaMigration): + + def forwards(self, orm): + # Adding field 'Lesson.description' + db.add_column(u'catalogue_lesson', 'description', + self.gf('django.db.models.fields.TextField')(null=True, blank=True), + keep_default=False) + + + def backwards(self, orm): + # Deleting field 'Lesson.description' + db.delete_column(u'catalogue_lesson', 'description') + + + models = { + u'catalogue.attachment': { + 'Meta': {'ordering': "['slug', 'ext']", 'unique_together': "(['lesson', 'slug', 'ext'],)", 'object_name': 'Attachment'}, + 'ext': ('django.db.models.fields.CharField', [], {'max_length': '15'}), + 'file': ('django.db.models.fields.files.FileField', [], {'max_length': '100'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'lesson': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['catalogue.Lesson']"}), + 'slug': ('django.db.models.fields.CharField', [], {'max_length': '255'}) + }, + u'catalogue.lesson': { + 'Meta': {'ordering': "['section', 'level', 'order']", 'object_name': 'Lesson'}, + 'curriculum_courses': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['curriculum.CurriculumCourse']", 'symmetrical': 'False', 'blank': 'True'}), + 'dc': ('jsonfield.fields.JSONField', [], {'default': "'{}'"}), + 'description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'html_file': ('django.db.models.fields.files.FileField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'level': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['curriculum.Level']"}), + 'order': ('django.db.models.fields.IntegerField', [], {'db_index': 'True'}), + 'package': ('django.db.models.fields.files.FileField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), + 'pdf': ('django.db.models.fields.files.FileField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), + 'section': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['catalogue.Section']", 'null': 'True', 'blank': 'True'}), + 'slug': ('django.db.models.fields.SlugField', [], {'unique': 'True', 'max_length': '255'}), + 'student_package': ('django.db.models.fields.files.FileField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), + 'student_pdf': ('django.db.models.fields.files.FileField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), + 'title': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'type': ('django.db.models.fields.CharField', [], {'max_length': '15', 'db_index': 'True'}), + 'xml_file': ('django.db.models.fields.files.FileField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}) + }, + u'catalogue.lessonstub': { + 'Meta': {'ordering': "['section', 'level', 'order']", 'object_name': 'LessonStub'}, + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'level': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['curriculum.Level']"}), + 'order': ('django.db.models.fields.IntegerField', [], {'db_index': 'True'}), + 'section': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['catalogue.Section']", 'null': 'True', 'blank': 'True'}), + 'title': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'type': ('django.db.models.fields.CharField', [], {'max_length': '15', 'db_index': 'True'}) + }, + u'catalogue.part': { + 'Meta': {'object_name': 'Part'}, + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'lesson': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['catalogue.Lesson']"}), + 'pdf': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}), + 'student_pdf': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}) + }, + u'catalogue.section': { + 'Meta': {'ordering': "['order']", 'object_name': 'Section'}, + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'image': ('django.db.models.fields.files.ImageField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}), + 'order': ('django.db.models.fields.IntegerField', [], {}), + 'slug': ('django.db.models.fields.SlugField', [], {'unique': 'True', 'max_length': '255'}), + 'summary': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'title': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}), + 'xml_file': ('django.db.models.fields.files.FileField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}) + }, + u'curriculum.curriculumcourse': { + 'Meta': {'ordering': "['slug']", 'object_name': 'CurriculumCourse'}, + 'accusative': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'slug': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}), + 'title': ('django.db.models.fields.CharField', [], {'max_length': '255'}) + }, + u'curriculum.level': { + 'Meta': {'ordering': "['order']", 'object_name': 'Level'}, + 'group_en': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '255'}), + 'group_pl': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '255'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name_en': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '255'}), + 'name_pl': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '255'}), + 'order': ('django.db.models.fields.IntegerField', [], {}), + 'slug': ('django.db.models.fields.CharField', [], {'max_length': '255'}) + } + } + + complete_apps = ['catalogue'] \ No newline at end of file diff --git a/catalogue/migrations/0016_auto__add_field_section_pic__add_field_section_pic_attribution__add_fi.py b/catalogue/migrations/0016_auto__add_field_section_pic__add_field_section_pic_attribution__add_fi.py new file mode 100644 index 0000000..6be3fcf --- /dev/null +++ b/catalogue/migrations/0016_auto__add_field_section_pic__add_field_section_pic_attribution__add_fi.py @@ -0,0 +1,114 @@ +# -*- coding: utf-8 -*- +import datetime +from south.db import db +from south.v2 import SchemaMigration +from django.db import models + + +class Migration(SchemaMigration): + + def forwards(self, orm): + # Adding field 'Section.pic' + db.add_column(u'catalogue_section', 'pic', + self.gf('django.db.models.fields.files.ImageField')(max_length=100, null=True, blank=True), + keep_default=False) + + # Adding field 'Section.pic_attribution' + db.add_column(u'catalogue_section', 'pic_attribution', + self.gf('django.db.models.fields.CharField')(max_length=255, null=True, blank=True), + keep_default=False) + + # Adding field 'Section.pic_src' + db.add_column(u'catalogue_section', 'pic_src', + self.gf('django.db.models.fields.URLField')(max_length=200, null=True, blank=True), + keep_default=False) + + + def backwards(self, orm): + # Deleting field 'Section.pic' + db.delete_column(u'catalogue_section', 'pic') + + # Deleting field 'Section.pic_attribution' + db.delete_column(u'catalogue_section', 'pic_attribution') + + # Deleting field 'Section.pic_src' + db.delete_column(u'catalogue_section', 'pic_src') + + + models = { + u'catalogue.attachment': { + 'Meta': {'ordering': "['slug', 'ext']", 'unique_together': "(['lesson', 'slug', 'ext'],)", 'object_name': 'Attachment'}, + 'ext': ('django.db.models.fields.CharField', [], {'max_length': '15'}), + 'file': ('django.db.models.fields.files.FileField', [], {'max_length': '100'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'lesson': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['catalogue.Lesson']"}), + 'slug': ('django.db.models.fields.CharField', [], {'max_length': '255'}) + }, + u'catalogue.lesson': { + 'Meta': {'ordering': "['section', 'level', 'order']", 'object_name': 'Lesson'}, + 'curriculum_courses': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['curriculum.CurriculumCourse']", 'symmetrical': 'False', 'blank': 'True'}), + 'dc': ('jsonfield.fields.JSONField', [], {'default': "'{}'"}), + 'description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'html_file': ('django.db.models.fields.files.FileField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'level': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['curriculum.Level']"}), + 'order': ('django.db.models.fields.IntegerField', [], {'db_index': 'True'}), + 'package': ('django.db.models.fields.files.FileField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), + 'pdf': ('django.db.models.fields.files.FileField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), + 'section': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['catalogue.Section']", 'null': 'True', 'blank': 'True'}), + 'slug': ('django.db.models.fields.SlugField', [], {'unique': 'True', 'max_length': '255'}), + 'student_package': ('django.db.models.fields.files.FileField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), + 'student_pdf': ('django.db.models.fields.files.FileField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), + 'title': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'type': ('django.db.models.fields.CharField', [], {'max_length': '15', 'db_index': 'True'}), + 'xml_file': ('django.db.models.fields.files.FileField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}) + }, + u'catalogue.lessonstub': { + 'Meta': {'ordering': "['section', 'level', 'order']", 'object_name': 'LessonStub'}, + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'level': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['curriculum.Level']"}), + 'order': ('django.db.models.fields.IntegerField', [], {'db_index': 'True'}), + 'section': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['catalogue.Section']", 'null': 'True', 'blank': 'True'}), + 'title': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'type': ('django.db.models.fields.CharField', [], {'max_length': '15', 'db_index': 'True'}) + }, + u'catalogue.part': { + 'Meta': {'object_name': 'Part'}, + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'lesson': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['catalogue.Lesson']"}), + 'pdf': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}), + 'student_pdf': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}) + }, + u'catalogue.section': { + 'Meta': {'ordering': "['order']", 'object_name': 'Section'}, + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'image': ('django.db.models.fields.files.ImageField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}), + 'order': ('django.db.models.fields.IntegerField', [], {}), + 'pic': ('django.db.models.fields.files.ImageField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}), + 'pic_attribution': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), + 'pic_src': ('django.db.models.fields.URLField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}), + 'slug': ('django.db.models.fields.SlugField', [], {'unique': 'True', 'max_length': '255'}), + 'summary': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'title': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}), + 'xml_file': ('django.db.models.fields.files.FileField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}) + }, + u'curriculum.curriculumcourse': { + 'Meta': {'ordering': "['slug']", 'object_name': 'CurriculumCourse'}, + 'accusative': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'slug': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}), + 'title': ('django.db.models.fields.CharField', [], {'max_length': '255'}) + }, + u'curriculum.level': { + 'Meta': {'ordering': "['order']", 'object_name': 'Level'}, + 'group_en': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '255'}), + 'group_pl': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '255'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name_en': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '255'}), + 'name_pl': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '255'}), + 'order': ('django.db.models.fields.IntegerField', [], {}), + 'slug': ('django.db.models.fields.CharField', [], {'max_length': '255'}) + } + } + + complete_apps = ['catalogue'] \ No newline at end of file diff --git a/catalogue/models.py b/catalogue/models.py index 239f60c..4af4810 100644 --- a/catalogue/models.py +++ b/catalogue/models.py @@ -1,8 +1,11 @@ +# -*- 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 curriculum.models import Level, Curriculum, CurriculumCourse +import logging + class Section(models.Model): @@ -14,6 +17,12 @@ class Section(models.Model): 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'] @@ -24,20 +33,22 @@ class Section(models.Model): 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 - 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) - 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: @@ -74,6 +85,7 @@ class Lesson(models.Model): 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", null=True, blank=True, max_length=255) @@ -99,7 +111,7 @@ class Lesson(models.Model): 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() @@ -107,8 +119,8 @@ class Lesson(models.Model): # 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) @@ -120,13 +132,14 @@ class Lesson(models.Model): 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_description(wldoc=wldoc) lesson.build_html(infile=infile) - lesson.build_pdf(infile=infile) + lesson.build_pdf() lesson.build_package() if lesson.type != 'project': - lesson.build_pdf(student=True, infile=infile) + lesson.build_pdf(student=True) lesson.build_package(student=True) return lesson @@ -135,18 +148,34 @@ class Lesson(models.Model): 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'), \ + u"Unknown lesson type: %s" % self.type self.save() courses = set() for identifier in wldoc.book_info.curriculum: + identifier = (identifier or "").replace(' ', '') + if not identifier: continue try: - curr = Curriculum.objects.get(identifier=identifier) + curr = Curriculum.objects.get(identifier__iexact=identifier) 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 + def populate_description(self, wldoc=None, infile=None): + if wldoc is None: + wldoc = self.wldocument(infile) + for nagl in wldoc.edoc.findall('.//naglowek_rozdzial'): + if (nagl.text or '').strip() == u'Pomysł na lekcję': + from lxml import etree + self.description = etree.tostring(nagl.getnext(), + method='text', encoding='unicode').strip() + self.save() + return + def wldocument(self, infile=None): from librarian import IOFile from librarian.parser import WLDocument @@ -166,9 +195,11 @@ class Lesson(models.Model): 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 - 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, @@ -230,6 +261,9 @@ class Lesson(models.Model): 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) @@ -265,3 +299,10 @@ class LessonStub(models.Model): def __unicode__(self): return self.title + + @property + def slug(self): + return '' + + def add_to_zip(self, *args, **kwargs): + pass diff --git a/catalogue/publish.py b/catalogue/publish.py index 9f79dae..cca25de 100755 --- a/catalogue/publish.py +++ b/catalogue/publish.py @@ -1,13 +1,56 @@ # -*- coding: utf-8 from django.core.files.base import ContentFile from django.core.files import File +from django.core.urlresolvers import reverse from librarian import DocProvider, IOFile from librarian.pyhtml import EduModuleFormat from librarian.pypdf import EduModulePDFFormat from .models import Lesson, Attachment +from fnpdjango.utils.text.slughifi import slughifi + + +# TODO: Using sorl.thumbnail for now, +# but this should be done in Librarian, +# directly using convert or PIL as a fallback. +def get_image(src_img_path, width=None, + default_width=1600, formats=('PNG', 'JPEG', 'GIF')): + """ Returns an object with `url` and `storage` attributes, + or None if using the original image is OK. + """ + + from PIL import Image + from sorl.thumbnail import get_thumbnail + + # Does it need converting? + # Yes, if width is given explicitly. + convert = width is not None + if not convert: + # Looks like it doesn't need converting. + # But let's try opening it and checking its type. + try: + simg = Image.open(src_img_path) + except IOError: + # It doesn't look like image, + # but maybe it's convertable to one. + convert = True + else: + if simg.format not in formats: + # It's an image, but it's in some weird format. + convert = True + width = simg.size[0] + + if convert: + if width is None: + width = default_width + return get_thumbnail(src_img_path, '%sx%s' % (width, 10*width)) + else: + return None class HtmlFormat(EduModuleFormat): + IMAGE_FORMATS = ('PNG', 'JPEG', 'GIF') + DEFAULT_IMAGE_WIDTH = 1600 + def find_attachment(self, slug, fmt): lesson_slug = self.wldoc.book_info.url.slug try: @@ -34,35 +77,45 @@ class HtmlFormat(EduModuleFormat): return self.find_attachment(slug, fmt).file.url def url_for_image(self, slug, fmt, width=None): - if width is None: - return self.url_for_material(slug, fmt) - - lesson_slug = self.wldoc.book_info.url.slug - th_slug = "thumb/%s__th%d" % (slug, width) try: - # If already saved, use it. - att = Attachment.objects.get(lesson__slug=lesson_slug, - slug=th_slug, ext=fmt) - except Attachment.DoesNotExist, e: - from PIL import Image - from StringIO import StringIO - # Find full image, create thumbnail, save. - src_att = self.find_attachment(slug, fmt) - simg = Image.open(src_att.file.path) - size = (width, simg.size[1]*width/simg.size[0]) - simg = simg.resize(size, Image.ANTIALIAS) - - tempfile = StringIO() - img_format = "JPEG" if fmt.upper() == "JPG" else fmt - simg.save(tempfile, format=img_format) - att_name = "%s.%s" % (th_slug, fmt) - lesson = Lesson.objects.get(slug=lesson_slug) - att = lesson.attachment_set.create(slug=th_slug, ext=fmt) - att.file.save(att_name, ContentFile(tempfile.getvalue())) - return att.file.url + src_img = self.find_attachment(slug, fmt).file + except self.MaterialNotFound: + return '' + img = get_image(src_img.path, width, + self.DEFAULT_IMAGE_WIDTH, self.IMAGE_FORMATS) + return (img or src_img).url + + def text_to_anchor(self, text): + return slughifi(text) + + def get_forma_url(self, forma): + return '%s#%s' % ( + reverse('catalogue_lesson', args=['metody']), + self.text_to_anchor(forma) + ) + + def get_help_url(self, naglowek): + return '%s%s#%s' % ( + '//edukacjamedialna.edu.pl', + reverse('info', args=['jak-korzystac/']), + self.naglowek_to_anchor(naglowek) + ) + class PdfFormat(EduModulePDFFormat): - pass + IMAGE_FORMATS = ('PNG', 'JPEG', 'GIF') + DEFAULT_IMAGE_WIDTH = 1600 + + def get_image(self, name): + src_img = super(PdfFormat, self).get_image(name) + img = get_image(src_img.get_filename(), + default_width=self.DEFAULT_IMAGE_WIDTH, + formats=self.IMAGE_FORMATS + ) + if img: + return IOFile.from_filename(img.storage.path(img)) + else: + return src_img class OrmDocProvider(DocProvider): diff --git a/catalogue/static/catalogue/css/carousel.css b/catalogue/static/catalogue/css/carousel.css index 968e8d1..a7f365c 100644 --- a/catalogue/static/catalogue/css/carousel.css +++ b/catalogue/static/catalogue/css/carousel.css @@ -2,12 +2,12 @@ float: left; position: relative; width: 43.75em; - height: 14.688em; + height: 14.6875em; overflow: hidden; - border-radius: 0.938em; } + border-radius: 0.9375em; } #catalogue-carousel #catalogue-carousel-links { width: 28.75em; - height: 14.688em; + height: 14.6875em; list-style: none; margin: 0; padding: 0; } @@ -18,21 +18,23 @@ left: 0; height: 100%; background-size: 100% 100%; - border-top-left-radius: 0.938em 6.38%; - border-bottom-left-radius: 0.938em 6.38%; } - #catalogue-carousel #catalogue-carousel-links li a { + border-top-left-radius: 0.9375em 6.38%; + border-bottom-left-radius: 0.9375em 6.38%; + z-index: 100; + background-color: #888; } + #catalogue-carousel #catalogue-carousel-links li a.catalogue-carousel-link { display: block; overflow: hidden; width: 28.75em; height: 100%; background: url(/static/catalogue/img/carousel-left.png) 100% 0 no-repeat; background-size: 4.375em 100%; } - #catalogue-carousel #catalogue-carousel-links li a .catalogue-carousel-note { + #catalogue-carousel #catalogue-carousel-links li a.catalogue-carousel-link .catalogue-carousel-note { position: relative; height: 100%; color: white; - margin-top: 12em; } - #catalogue-carousel #catalogue-carousel-links li a .catalogue-carousel-note p:before { + margin-top: 8.5em; } + #catalogue-carousel #catalogue-carousel-links li a.catalogue-carousel-link .catalogue-carousel-note div:before { content: " "; display: block; position: absolute; @@ -41,40 +43,49 @@ z-index: -1; background-color: black; opacity: 0.6; } - #catalogue-carousel #catalogue-carousel-links li a .catalogue-carousel-note p { - margin: 0; } - #catalogue-carousel #catalogue-carousel-links li a .catalogue-carousel-note p em { - margin: 0 .2em 0 .5em; - font-style: normal; - font-size: 1.5em; } - #catalogue-carousel #catalogue-carousel-links li a .catalogue-carousel-note p strong { - margin-left: .5em; - font-size: 2em; } - #catalogue-carousel #catalogue-carousel-links li a:active { + #catalogue-carousel #catalogue-carousel-links li a.catalogue-carousel-link .catalogue-carousel-note div p { + padding: .4em 3em 0 .5em; } + #catalogue-carousel #catalogue-carousel-links li a.catalogue-carousel-link .catalogue-carousel-note div p strong { + font-size: 1.2em; + display: block; } + #catalogue-carousel #catalogue-carousel-links li a.catalogue-carousel-link .catalogue-carousel-note div p .more { + position: absolute; + right: 4em; + top: 4.5em; } + #catalogue-carousel #catalogue-carousel-links li a.catalogue-carousel-link:active { outline: none; } + #catalogue-carousel #catalogue-carousel-links li .attribution { + text-align: right; + font-size: .75em; + position: absolute; + right: 5em; + top: .1em; + color: white; + font-weight: bold; + text-shadow: 0 0 5px #000; } #catalogue-carousel #catalogue-carousel-switcher { margin: 0; - padding: 3.125em 0 0 3.625em; + padding: 1.25em 0 0 3.625em; width: 11.375em; - height: 11.563em; + height: 13.4375em; position: absolute; right: 0; top: 0; list-style: none; - border-radius: 0 0.938em 0.938em 0; + border-radius: 0 0.9375em 0.9375em 0; background-color: #ed7831; background-image: url(/static/catalogue/img/carousel-right.png); background-position: 0 0; background-repeat: no-repeat; - background-size: auto 14.688em; + background-size: auto 14.6875em; /* right part of mask as background */ } #catalogue-carousel #catalogue-carousel-switcher li { - margin-bottom: .9em; } + margin-bottom: .5em; + font-size: .85em; + line-height: 1em; } #catalogue-carousel #catalogue-carousel-switcher li a { text-transform: uppercase; - color: #363a3e; - font-size: .9em; - font-weight: bold; } + color: #363a3e; } #catalogue-carousel #catalogue-carousel-switcher li a:before { vertical-align: top; margin-right: 1.5em; } diff --git a/catalogue/static/catalogue/css/carousel.scss b/catalogue/static/catalogue/css/carousel.scss index 079ec3a..bc2041d 100755 --- a/catalogue/static/catalogue/css/carousel.scss +++ b/catalogue/static/catalogue/css/carousel.scss @@ -27,8 +27,10 @@ $ciemny: #363a3e; background-size: 100% 100%; border-top-left-radius: 15*$px 6.38%; border-bottom-left-radius: 15*$px 6.38%; + z-index: 100; + background-color: #888; - a { + a.catalogue-carousel-link { display: block; overflow: hidden; width: 460*$px; @@ -40,44 +42,58 @@ $ciemny: #363a3e; position: relative; height: 100%; color: white; - margin-top: 12em; - - p:before { - content: " "; - display: block; - position: absolute; - height: 100%; - width: 100%; - z-index: -1; - background-color: black; - opacity: 0.6; - } + margin-top: 8.5em; - p { - margin: 0; - em { - margin: 0 .2em 0 .5em; - font-style: normal; - font-size: 1.5em; + div { + &:before { + content: " "; + display: block; + position: absolute; + height: 100%; + width: 100%; + z-index: -1; + background-color: black; + opacity: 0.6; } - strong { - margin-left: .5em; - font-size: 2em; + + p { + padding: .4em 3em 0 .5em; + + strong { + font-size: 1.2em; + display: block; + } + + .more { + position: absolute; + right: 4em; + top: 4.5em; + } } - } } } - a:active { + a.catalogue-carousel-link:active { outline: none; } + .attribution { + text-align: right; + font-size: .75em; + position: absolute; + right: 5em; + top: .1em; + color: white; + font-weight: bold; + text-shadow: 0 0 5px #000; + } + } } #catalogue-carousel-switcher { margin: 0; - padding: 50*$px 0 0 58*$px; + padding: 20*$px 0 0 58*$px; width: 240*$px - 58*$px; - height: 235*$px - 50*$px; + height: 235*$px - 20*$px; position: absolute; right: 0; top: 0; @@ -92,13 +108,13 @@ $ciemny: #363a3e; /* right part of mask as background */ li { - margin-bottom: .9em; + margin-bottom: .5em; + font-size: .85em; + line-height: 1em; a { text-transform: uppercase; color: $ciemny; - font-size: .9em; - font-weight: bold; } a:before { vertical-align: top; diff --git a/catalogue/static/catalogue/css/layout.css b/catalogue/static/catalogue/css/layout.css index 09ff5af..acf699d 100644 --- a/catalogue/static/catalogue/css/layout.css +++ b/catalogue/static/catalogue/css/layout.css @@ -1,4 +1,25 @@ @charset "UTF-8"; +.box-button { + background-color: #ed7831; + border-radius: 0.9375em; } + .box-button .dl-button { + color: white; + padding: 1.0625em 0.75em 1.0625em 0.75em; } + +.dl-button { + color: #363a3e; + display: block; + font-weight: bold; + text-align: center; + text-transform: uppercase; + font-size: .9em; } + +.dl-button:after { + content: " ↓"; } + +#main-bar section.button { + margin-bottom: 1.0625em; } + #sidebar { position: absolute; right: 0; @@ -6,39 +27,17 @@ width: 13.75em; color: #363a3e; } #sidebar section { - margin-bottom: 1.063em; } + margin-bottom: 1.0625em; } #sidebar section h1 { margin: 0; } #sidebar section h1.realisation { font-weight: normal; } - #sidebar .box { - background-color: #d4d6d8; - border-radius: 0.938em; - padding: 1.063em 0.75em 1.063em 0.75em; } - #sidebar .box h1 { - font-size: 1em; - text-transform: uppercase; } - #sidebar .box-button { - background-color: #ed7831; - border-radius: 0.938em; } - #sidebar .box-button .dl-button { - color: white; - padding: 1.063em 0.75em 1.063em 0.75em; } - #sidebar .dl-button { - color: #363a3e; - display: block; - font-weight: bold; - text-align: center; - text-transform: uppercase; - font-size: .9em; } - #sidebar .dl-button:after { - content: " ↓"; } #sidebar .section { border-top: 1px solid #c9ccce; - padding-top: 1.063em; } + padding-top: 1.0625em; } #sidebar .section-minor { border-top: 1px solid #c9ccce; - padding-top: 1.063em; } + padding-top: 1.0625em; } #sidebar .section-minor h1 { font-weight: normal; font-size: 1em; } @@ -46,17 +45,33 @@ font-size: .8em; color: #888; border-top: 1px solid #c9ccce; - padding-top: 1.063em; } + padding-top: 1.0625em; } #sidebar .section-micro h1 { font-weight: normal; font-size: 1em; } #sidebar .section-micro .link-list a { color: #888; } + #sidebar section:first-child { + border-top: 0; + padding-top: 0; } #main-bar { width: 40em; } #main-bar .top-link { float: right; } + #main-bar .box { + background-color: #d4d6d8; + border-radius: 0.9375em; + padding: 1.0625em; } + #main-bar .box h1 { + font-size: 1em; + text-transform: uppercase; } + #main-bar .box p { + margin: 0; } + #main-bar .box .box-icon { + margin: -.2em 0 -.2em 1em; + float: right; + text-align: center; } .lesson-footer { clear: both; diff --git a/catalogue/static/catalogue/css/layout.scss b/catalogue/static/catalogue/css/layout.scss index 7bea63a..230e4aa 100755 --- a/catalogue/static/catalogue/css/layout.scss +++ b/catalogue/static/catalogue/css/layout.scss @@ -1,6 +1,30 @@ $px: .0625em; $new_black: #363a3e; +.box-button { + background-color: #ed7831; + border-radius: 15*$px; + .dl-button { + color: white; + padding: 17*$px 12*$px 17*$px 12*$px; + } +} +.dl-button { + color: $new_black; + display: block; + font-weight: bold; + text-align: center; + text-transform: uppercase; + font-size: .9em; +} +.dl-button:after { + content: " ↓"; +} + +#main-bar section.button { + margin-bottom: 17*$px; +} + #sidebar { position: absolute; right: 0; @@ -18,34 +42,6 @@ $new_black: #363a3e; } } - .box { - background-color: #d4d6d8; - border-radius: 15*$px; - padding: 17*$px 12*$px 17*$px 12*$px; - h1 { - font-size: 1em; - text-transform: uppercase; - } - } - .box-button { - background-color: #ed7831; - border-radius: 15*$px; - .dl-button { - color: white; - padding: 17*$px 12*$px 17*$px 12*$px; - } - } - .dl-button { - color: $new_black; - display: block; - font-weight: bold; - text-align: center; - text-transform: uppercase; - font-size: .9em; - } - .dl-button:after { - content: " ↓"; - } .section { border-top: 1px solid #c9ccce; padding-top: 17*$px; @@ -71,6 +67,10 @@ $new_black: #363a3e; color: #888; } } + section:first-child { + border-top: 0; + padding-top: 0; + } } #main-bar { width: 640*$px; @@ -78,6 +78,24 @@ $new_black: #363a3e; .top-link { float:right; } + + .box { + background-color: #d4d6d8; + border-radius: 15*$px; + padding: 17*$px; + h1 { + font-size: 1em; + text-transform: uppercase; + } + p { + margin: 0; + } + .box-icon { + margin: -.2em 0 -.2em 1em; + float: right; + text-align: center; + } + } } .lesson-footer { diff --git a/catalogue/static/catalogue/css/lesson.css b/catalogue/static/catalogue/css/lesson.css index b51e7f3..c8e73c4 100644 --- a/catalogue/static/catalogue/css/lesson.css +++ b/catalogue/static/catalogue/css/lesson.css @@ -207,15 +207,15 @@ em.person { font-size: 2em; } .activity .info { float: right; - width: 8.438em; } + width: 8.4375em; } .activity .info .infobox { padding: 1em 0; border-top: 1px solid #c9ccce; } .activity .info .infobox h1 { text-transform: uppercase; font-weight: bold; - margin: 0 0 0.5em -2.188em; - padding-left: 2.188em; + margin: 0 0 0.5em -2.1875em; + padding-left: 2.1875em; line-height: 24px; font-size: 1em; } .activity .info .infobox p { @@ -246,3 +246,9 @@ em.person { #book-text .top-link { margin-top: 1em; } + +.help { + font-size: .7em; + padding: 0 .5em; + color: #888; + vertical-align: super; } diff --git a/catalogue/static/catalogue/css/lesson.scss b/catalogue/static/catalogue/css/lesson.scss index b200002..d98f1a3 100755 --- a/catalogue/static/catalogue/css/lesson.scss +++ b/catalogue/static/catalogue/css/lesson.scss @@ -318,3 +318,10 @@ em.person { #book-text .top-link { margin-top: 1em; } + +.help { + font-size: .7em; + padding: 0 .5em; + color: #888; + vertical-align: super; +} diff --git a/catalogue/static/catalogue/css/section_list.css b/catalogue/static/catalogue/css/section_list.css index 15c44ca..1a45397 100644 --- a/catalogue/static/catalogue/css/section_list.css +++ b/catalogue/static/catalogue/css/section_list.css @@ -1,84 +1,54 @@ -.section-level { - width: 40em; - border-radius: 0.9375em; - margin: 1em 0; - overflow: hidden; } - .section-level a:hover { - text-decoration: underline; } - -.sections-row { - display: table; } - -.section-type { - display: table-cell; - vertical-align: top; - padding: 1.25em; } - .section-type h1 { +#level-chooser-place { + min-height: 4em; + margin-top: 2em; } + #level-chooser-place ul#level-chooser { + margin: 0; + padding: 1em 0 1em 8.75em; + background-color: white; + width: 31.25em; + z-index: 300; + position: relative; text-transform: uppercase; - margin: 0 0 1em 0; - font-size: 1em; } - .section-type img { - float: left; - margin-right: 1em; - margin-bottom: 1em; - border: 0.375em solid white; } - -.section-type-synthetic { - width: 18.75em; } - -.section-type-course { - width: 16.25em; } - -.section-type-project { - width: 37.5em; } - -.section-level-gimnazjum { - background: #f4ae83; - color: #67584f; } - .section-level-gimnazjum a, .section-level-gimnazjum a:hover { - color: #67584f; } - .section-level-gimnazjum .section-type-course { - background: #ed7831; - color: #fff; } - .section-level-gimnazjum .section-type-course a { - color: #fff; } - .section-level-gimnazjum .section-type-project { - background-color: #f8cdb2; } - -.section-level-liceum { - background: #44b69f; - color: #363a3e; } - .section-level-liceum a, .section-level-liceum a:hover { - color: #363a3e; } - .section-level-liceum .section-type-course { - background: #16a487; - color: #fff; } - .section-level-liceum .section-type-course a { - color: #fff; } - .section-level-liceum .section-type-project { - background-color: #9fdbcf; } - -.course-boxes h1 { - color: #363a3e; } -.course-boxes .section-level { - background: white; - border: 1px solid #777777; } - .course-boxes .section-level a, .course-boxes .section-level a:hover { - color: #363a3e; } - .course-boxes .section-level .section-type { - background: white; } -.course-boxes .section-type-synthetic { - width: 16.25em; } -.course-boxes .section-type-course { - width: 18.75em; } - -.section-links { - float: right; } - -h2.section-header { - margin: 0; } - -.section-list-toc { - display: inline-block; - vertical-align: top; - width: 18.75em; } + text-align: right; } + #level-chooser-place ul#level-chooser .home { + display: none; + position: absolute; + top: .5em; + left: 0; } + #level-chooser-place ul#level-chooser .home a { + background: none; + padding: 0; } + #level-chooser-place ul#level-chooser .home a img { + width: 6.25em; } + #level-chooser-place ul#level-chooser.fixed { + position: fixed; + top: 0; + border-bottom: 1px solid #c9ccce; } + #level-chooser-place ul#level-chooser.fixed .home { + display: block; } + #level-chooser-place ul#level-chooser li { + display: inline-block; + list-style: none; } + #level-chooser-place ul#level-chooser li a { + padding: .5em 1em; + border-radius: 0.3125em; + background: #eee; } + #level-chooser-place ul#level-chooser li a.active { + color: white; + background: #ED7831; } + +.level .link-list { + margin-left: 1em; } +.level .level-toc { + overflow: hidden; + /* Because we're changing bg color lower. */ } + .level .level-toc.fixed { + position: fixed; } + .level .level-toc .link-list { + margin-left: 1em; } + .level .level-toc .link-list li { + margin-bottom: 0; } + .level .level-toc .link-list li.curriculumcourses { + margin: 10px -17px -17px; + padding: 10px 16px 16px; + background-color: #eee; } diff --git a/catalogue/static/catalogue/css/section_list.scss b/catalogue/static/catalogue/css/section_list.scss index a9a1305..192e5b6 100755 --- a/catalogue/static/catalogue/css/section_list.scss +++ b/catalogue/static/catalogue/css/section_list.scss @@ -1,127 +1,86 @@ $px: 0.0625em; -.section-level { - width: 640*$px; - border-radius: 15*$px; - margin: 1em 0; - overflow: hidden; - - a:hover { - text-decoration: underline; - } -} - -.sections-row { - display: table; -} - -.section-type { - display: table-cell; - vertical-align: top; - padding: 20*$px; - - h1 { +#level-chooser-place { + min-height: 4em; + margin-top: 2em; + + ul#level-chooser { + margin: 0; + padding: 1em 0 1em 140*$px; + background-color: white; + width: 500*$px; + z-index: 300; + position: relative; text-transform: uppercase; - margin: 0 0 1em 0; - font-size: 1em; - } - - img { - float: left; - margin-right: 16*$px; - margin-bottom: 16*$px; - border: 6*$px solid white; - } -} -.section-type-synthetic { - width: 340*$px - 2 * 20*$px; -} -.section-type-course { - width: 300*$px - 2 * 20*$px; -} - -.section-type-project { - width: 640*$px - 2 * 20*$px; -} + text-align: right; + + .home { + display: none; + position: absolute; + top: .5em; + left: 0; + + a { + background: none; + padding: 0; + img { + width: 100*$px; + } + } + } -.section-level-gimnazjum { - background: #f4ae83; - color: #67584f; - a, a:hover { - color: #67584f; - } + &.fixed { + position: fixed; + top: 0; + border-bottom: 1px solid #c9ccce; - .section-type-synthetic { - } - .section-type-course { - background: #ed7831; - color: #fff; - a { - color: #fff; + .home { + display: block; + } } - } - .section-type-project { - background-color: lighten(#f4ae83, 10); - } -} + li { + display: inline-block; + list-style: none; -.section-level-liceum { - background: #44b69f; - color: #363a3e; - a, a:hover { - color: #363a3e; - } + a { + padding: .5em 1em; + border-radius: 5*$px; + background: #eee; - .section-type-synthetic { - } - .section-type-course { - background: #16a487; - color: #fff; - a { - color: #fff; + &.active { + color: white; + background: #ED7831; + } + } } } - .section-type-project { - background-color: lighten(#44b69f, 25); - } } - -.course-boxes { - h1 { - color: #363a3e; - } - .section-level { - background: white; - border: 1px solid #777; - a, a:hover { - color: #363a3e; - } - .section-type { - background: white; - } - } - .section-type-synthetic { - width: 300*$px - 2 * 20*$px; - } - .section-type-course { - width: 340*$px - 2 * 20*$px; +.level { + .link-list { + margin-left: 1em; } -} + .level-toc { + overflow: hidden; /* Because we're changing bg color lower. */ -.section-links { - float: right; -} + &.fixed { + position: fixed; + } -h2.section-header { - margin: 0; -} + .link-list { + margin-left: 1em; + li { + margin-bottom: 0; -.section-list-toc { - display: inline-block; - vertical-align: top; - width: 300*$px; + &.curriculumcourses { + margin: 10px -17px -17px; + padding: 10px 16px 16px; + background-color: #eee; + } + } + } + } } diff --git a/catalogue/static/catalogue/js/carousel.js b/catalogue/static/catalogue/js/carousel.js index b7e5021..b2484be 100755 --- a/catalogue/static/catalogue/js/carousel.js +++ b/catalogue/static/catalogue/js/carousel.js @@ -2,31 +2,26 @@ $(function() { -$.fn.cycle.transitions.rgrowY = function($cont, $slides, opts) { - opts.before.push(function(curr, next, opts) { - $.fn.cycle.commonReset(curr,next,opts,true,false,true); - opts.cssBefore.top = this.cycleH/2; - opts.animIn.top = 0; - opts.animIn.height = this.cycleH; - opts.animOut.top = this.cycleH/2; - opts.animOut.height = 0; - }); - opts.cssBefore.height = 0; - opts.cssBefore.left = 0; -}; - $("#catalogue-carousel-links").each(function() { - $(this).cycle({ - fx: 'rgrowY', - sync:false, - easeIn: 'easeInQuad', - easeOut: 'easeOutQuad', + $slides = $(this); + + $slides.cycle({ + fx: 'fade', speed: 1000, + timeout: 5000, pager: '#catalogue-carousel-switcher', - pagerAnchorBuilder: function(){}, + pagerAnchorBuilder: function() {}, }); + + $("#catalogue-carousel-switcher li").each(function(i, e) { + $("a", e).click(function(ev) { + ev.preventDefault(); + $slides.cycle(i); + }); + }); + }); }); -})($); +})(jQuery); diff --git a/catalogue/static/catalogue/js/lesson-list.js b/catalogue/static/catalogue/js/lesson-list.js new file mode 100644 index 0000000..62bbb65 --- /dev/null +++ b/catalogue/static/catalogue/js/lesson-list.js @@ -0,0 +1,60 @@ +(function($){ +$(function() { + + +function scrollTo(thing) { + $('html, body').scrollTop($(thing).offset().top - $('#level-chooser').outerHeight()); +} + +function updateView() { + var scrolltop = $(window).scrollTop(); + + $('#level-chooser-place').each(function(i, el){ + if (scrolltop > $(el).offset().top) { + $("#level-chooser").addClass("fixed"); + } + else { + $("#level-chooser").removeClass("fixed"); + } + }); + + $('.level-toc').each(function(i, el) { + var $sect = $($(el).parent()); + var menu_top = $('#level-chooser').outerHeight(); + var menu_scrolltop = scrolltop + menu_top; + + if (menu_scrolltop + 2 >= $sect.offset().top && + menu_scrolltop < $sect.offset().top + $sect.outerHeight()) { + $(el).addClass("fixed").css("top", Math.min( + menu_top, + - scrolltop + $sect.offset().top + $sect.outerHeight() - $(el).outerHeight() + )); + $("#level-chooser a[href='#" + $sect.attr('id') + "']").addClass('active'); + } + else { + $(el).removeClass("fixed"); + $("#level-chooser a[href='#" + $sect.attr('id') + "']").removeClass('active'); + } + }); +} + + + +$("#level-chooser a, .level-toc a").click(function(ev) { + ev.preventDefault(); + scrollTo($(this).attr('href')); +}); + + + + + +updateView(); +$(document).scroll(updateView); +if (window.location.hash) { + scrollTo(window.location.hash); +} + + +}); +})(jQuery); diff --git a/catalogue/static/catalogue/js/lesson.js b/catalogue/static/catalogue/js/lesson.js index 6b22a83..080eb45 100755 --- a/catalogue/static/catalogue/js/lesson.js +++ b/catalogue/static/catalogue/js/lesson.js @@ -2,7 +2,10 @@ $(function() { -$('a.image').colorbox(); +$('a.image').colorbox({ + maxWidth: '100%', + maxHeight: '100%', +}); }); diff --git a/catalogue/templates/catalogue/lesson/appendix/lesson_detail.html b/catalogue/templates/catalogue/lesson/appendix/lesson_detail.html index 7dce3c9..98b6e3b 100755 --- a/catalogue/templates/catalogue/lesson/appendix/lesson_detail.html +++ b/catalogue/templates/catalogue/lesson/appendix/lesson_detail.html @@ -1,22 +1,9 @@ {% extends "catalogue/lesson/lesson_detail.html" %} -{% block sidebar-top %} - -
-

Zebrane dla wszystkich tematów

- -

To jest materiał wspólny dla wszystkich lekcji - edukacji medialnej{% if object.level.slug = "liceum" %} - (na poziomie zaawansowanym) - {% endif %}. - Zobacz też - pełny kurs - z podziałem na poszczególne tematy. -

-
- +{% block lesson-info %} {% endblock %} + {% block suggest-link %} Zgłoś swoją uwagę na temat tej strony. diff --git a/catalogue/templates/catalogue/lesson/box-icons.html b/catalogue/templates/catalogue/lesson/box-icons.html new file mode 100644 index 0000000..2963698 --- /dev/null +++ b/catalogue/templates/catalogue/lesson/box-icons.html @@ -0,0 +1,18 @@ +{% load static from staticfiles %} +{% if object.requires_internet %} +
Wymaga dostępu do Internetu
Internet
+{% else %} +
Nie wymaga dostępu do Internetu
Bez Internetu
+{% endif %} +{% if publisher %} +
{{ publisher.name }}
+{% endif %} diff --git a/catalogue/templates/catalogue/lesson/course/lesson_detail.html b/catalogue/templates/catalogue/lesson/course/lesson_detail.html index cadc580..28f6504 100755 --- a/catalogue/templates/catalogue/lesson/course/lesson_detail.html +++ b/catalogue/templates/catalogue/lesson/course/lesson_detail.html @@ -1,24 +1,25 @@ {% extends "catalogue/lesson/lesson_detail.html" %} +{% load static from staticfiles %} -{% block sidebar-top %} - +{% block lesson-info %}
-

Realizacja i czas lekcji

+

45m
+ + {% include "catalogue/lesson/box-icons.html" %} +

Ta lekcja jest częścią tematu - {{ object.section }}{% if object.level.slug = "liceum" %} - (na poziomie zaawansowanym) - {% endif %}. - {% with object.get_syntetic as synth %} - {% if synth %} - Dostępna jest również - lekcja syntetyczna - dla tego tematu. - {% endif %} - {% endwith %} + {{ object.section }} + na poziomie {{ object.level|lower }}.

-

Czas trwania: 45 minut.

+
+{% endblock %} + + +{% block sidebar-top %} +
+ {% if object.package %}
Pobierz całą lekcję
{% endif %} @@ -26,5 +27,5 @@
Pobierz lekcję w wersji dla ucznia
{% endif %} - +
{% endblock %} diff --git a/catalogue/templates/catalogue/lesson/lesson_detail.html b/catalogue/templates/catalogue/lesson/lesson_detail.html index f08b5b8..362df10 100755 --- a/catalogue/templates/catalogue/lesson/lesson_detail.html +++ b/catalogue/templates/catalogue/lesson/lesson_detail.html @@ -74,6 +74,10 @@
+ +{% block lesson-info %} +{% endblock %} + {{ object.html_file.read|safe }} diff --git a/catalogue/templates/catalogue/lesson/project/lesson_detail.html b/catalogue/templates/catalogue/lesson/project/lesson_detail.html index 88e4a34..0c6d217 100755 --- a/catalogue/templates/catalogue/lesson/project/lesson_detail.html +++ b/catalogue/templates/catalogue/lesson/project/lesson_detail.html @@ -1,18 +1,25 @@ {% extends "catalogue/lesson/lesson_detail.html" %} -{% block sidebar-top %} - +{% block lesson-info %}
-

Projekt

-

To jest projekt w ramach tematu - {{ object.section }}{% if object.level.slug = "liceum" %} - (na poziomie zaawansowanym) - {% endif %}. - Dostępny jest również - pełny kurs - tego tematu. + {% if publisher %} +

{{ publisher.name }}
+ {% endif %} + +

To jest projekt + na poziomie + {{ object.level|lower }}.

+{% endblock %} + + + +{% block sidebar-top %} + {% if object.package %}
Pobierz cały projekt
diff --git a/catalogue/templates/catalogue/lesson/synthetic/lesson_detail.html b/catalogue/templates/catalogue/lesson/synthetic/lesson_detail.html index c7d04c8..df60c9f 100755 --- a/catalogue/templates/catalogue/lesson/synthetic/lesson_detail.html +++ b/catalogue/templates/catalogue/lesson/synthetic/lesson_detail.html @@ -1,19 +1,19 @@ {% extends "catalogue/lesson/lesson_detail.html" %} -{% block sidebar-top %} - +{% block lesson-info %}
-

Realizacja i czas lekcji

-

Ta lekcja jest syntezą tematu - {{ object.section }}{% if object.level.slug = "liceum" %} - (na poziomie zaawansowanym) - {% endif %}. - Dostępny jest również - pełny kurs - tego tematu. +


45m
+ + {% include "catalogue/lesson/box-icons.html" %} + +

Ta lekcja jest częścią skróconego kursu na poziomie {{ object.level|lower }}. + Zobacz też pełny kurs.

-

Czas trwania: 45 minut.

+
+{% endblock %} + +{% block sidebar-top %} {% if object.package %}
Pobierz całą lekcję
diff --git a/catalogue/templates/catalogue/lesson_list.html b/catalogue/templates/catalogue/lesson_list.html new file mode 100755 index 0000000..1578aa2 --- /dev/null +++ b/catalogue/templates/catalogue/lesson_list.html @@ -0,0 +1,46 @@ +{% extends "base.html" %} +{% load catalogue_tags %} +{% load static from staticfiles %} +{% load course_boxes course_boxes_toc from curriculum_tags %} +{% load chunk from chunks %} + +{% block title %}Lekcje{% endblock %} + +{% block body %} +

Lekcje

+ + + +
+
+ {% chunk 'levels_disclaimer' %} +
+ +
+
    +
  • + {% for object in object_list %} +
  • {{ object }}
  • + {% endfor %} +
+
+ + + + {% for level in object_list %} + {% level_box level %} + {% endfor %} +
+ + +{% endblock %} diff --git a/catalogue/templates/catalogue/section_list.html b/catalogue/templates/catalogue/section_list.html deleted file mode 100755 index 9f48c4f..0000000 --- a/catalogue/templates/catalogue/section_list.html +++ /dev/null @@ -1,64 +0,0 @@ -{% extends "base.html" %} -{% load catalogue_tags %} -{% load course_boxes course_boxes_toc from curriculum_tags %} - -{% block title %}Lekcje{% endblock %} - -{% block body %} -

Lekcje

- - - -
-
-

Tematy

- -
-
-

Przedmioty

- -
- - {% for object in object_list %} - -

{{ object }}

- - {% section_box object %} - {% endfor %} - -
-

Lekcje wybrane na poszczególne przedmioty:

- {% course_boxes %} -
- -
- - -{% endblock %} diff --git a/catalogue/templates/catalogue/snippets/carousel.html b/catalogue/templates/catalogue/snippets/carousel.html index c482556..bb31eae 100755 --- a/catalogue/templates/catalogue/snippets/carousel.html +++ b/catalogue/templates/catalogue/snippets/carousel.html @@ -1,21 +1,27 @@ -{% load static %} - -{% url "info" "jak-korzystac/" as jak %} +{% load thumbnail %} +{% url 'catalogue_lessons' as lessons %} diff --git a/catalogue/templates/catalogue/snippets/lesson_nav.html b/catalogue/templates/catalogue/snippets/lesson_nav.html index 4e36e22..d2bcf48 100755 --- a/catalogue/templates/catalogue/snippets/lesson_nav.html +++ b/catalogue/templates/catalogue/snippets/lesson_nav.html @@ -1,10 +1,10 @@

{% if root %} - {{ root }} + {{ root }},
{{ lesson.level }}
{% elif lesson.type == 'synthetic' %} - Lekcje syntetyczne ze wszystkich tematów + Kurs skrócony,
{{ lesson.level }}
{% elif lesson.type == 'project' %} - Projekty ze wszystkich tematów + Projekty,
{{ lesson.level }}
{% else %} Inne {% endif %} @@ -15,22 +15,9 @@
  • {% if item == lesson %} {{ item }} - {% if mark_level and item.level.slug == 'liceum' %} (poziom zaawansowany){% endif %} {% else %} - {{ item }} - {% if mark_level and item.level.slug == 'liceum' %} (poziom zaawansowany){% endif %} - + {{ item }} {% endif %}
  • {% endfor %} - -{% if link_other_level %} -{% with other=lesson.get_other_level %} - {% if other %} -

    Ten temat jest dostępny również na - poziomie - {% if other.slug == 'liceum' %}zaawansowanym{% else %}podstawowym{% endif %}.

    - {% endif %} -{% endwith %} -{% endif %} diff --git a/catalogue/templates/catalogue/snippets/lesson_or_stub.html b/catalogue/templates/catalogue/snippets/lesson_or_stub.html new file mode 100644 index 0000000..5bb2614 --- /dev/null +++ b/catalogue/templates/catalogue/snippets/lesson_or_stub.html @@ -0,0 +1,9 @@ +{% if lesson.slug %} + +{% endif %} +{{ lesson }} +{% if lesson.slug %} + +{% else %} +(w przygotowaniu) +{% endif %} diff --git a/catalogue/templates/catalogue/snippets/level_box.html b/catalogue/templates/catalogue/snippets/level_box.html new file mode 100755 index 0000000..bb2fa12 --- /dev/null +++ b/catalogue/templates/catalogue/snippets/level_box.html @@ -0,0 +1,142 @@ +
    + +
    + {{ level }} + +
    + + +

    {{ level }}

    + +
    Pobierz wszystkie lekcje
    +
    Pobierz wszystkie lekcje w wersji dla ucznia
    + + {% if lessons.synthetic %} +
    +

    Skrócony kurs

    + +

    Masz kilka godzin? Przeprowadź po jednej lekcji przeglądowej z każdego tematu.

    + + +
    + {% endif %} + + + {% if lessons.course %} +
    +

    Pełny kurs

    + +

    Masz więcej czasu? Zrealizuj kompletny program edukacji medialnej.

    + + {% for section, s_lessons in lessons.course.items %} +
    +

    {{ section }}

    + + +
    + {% endfor %} + +
    + {% endif %} + + + {% if lessons.project %} +
    +

    Projekt

    + +

    Masz 4-6 tygodni? Zrealizuj jeden z projektów ze swoimi uczniami.

    + + +
    + {% endif %} + + + {% if courses %} +
    +

    Wg podstawy programowej

    + + {% for course, lessons in courses %} +
    +

    {{ course }}

    + + {% if lessons.synthetic %} +
    +

    Z kursu skróconego

    + +
    + {% endif %} + + {% if lessons.course %} +
    +

    Z kursu pełnego

    + +
    + {% endif %} + + {% if lessons.project %} +
    +

    Projekt

    + +
    + {% endif %} + +
    + {% endfor %} + +
    + {% endif %} + +
    diff --git a/catalogue/templates/catalogue/snippets/levels_main.html b/catalogue/templates/catalogue/snippets/levels_main.html new file mode 100644 index 0000000..497a5c8 --- /dev/null +++ b/catalogue/templates/catalogue/snippets/levels_main.html @@ -0,0 +1,19 @@ +{% load i18n %} + +{% url 'catalogue_lessons' as les %} + diff --git a/catalogue/templates/catalogue/snippets/section_box.html b/catalogue/templates/catalogue/snippets/section_box.html deleted file mode 100755 index c505c04..0000000 --- a/catalogue/templates/catalogue/snippets/section_box.html +++ /dev/null @@ -1,52 +0,0 @@ -{% load thumbnail %} -{% for level, types in lessons.items %} -{% if level.slug == "liceum" %} -

    {{section.title}}: poziom zaawansowany - wróć do spisu treści -

    -{% endif %} -
    - {% spaceless %} -
    - {% for lesson_type, lesson_list in types.items %} - {% if lesson_type == 'project' %} -
    - {% endif %} -
    - {% if lesson_type == 'synthetic' %} - {% if section.image %} - {% thumbnail section.image "120x160" as im %} - - - - {% endthumbnail %} - {% endif %} -

    Lekcja syntetyczna

    - {% elif lesson_type == 'project' %} -

    Projekt

    - {% else %} -

    Pełny kurs

    - {% endif %} - {% if lesson_list %} - - {% else %} -

    (W przygotowaniu)

    - {% endif %} -
    - {% endfor %} -
    - {% endspaceless %} -
    -{% endfor %} diff --git a/catalogue/templates/catalogue/snippets/section_buttons.html b/catalogue/templates/catalogue/snippets/section_buttons.html deleted file mode 100755 index c7bb162..0000000 --- a/catalogue/templates/catalogue/snippets/section_buttons.html +++ /dev/null @@ -1,6 +0,0 @@ -
      -{% for object in object_list %} - {% url "catalogue_lessons" as lessons_url %} -
    • {{ object }}
    • -{% endfor %} -
    diff --git a/catalogue/templatetags/catalogue_tags.py b/catalogue/templatetags/catalogue_tags.py index a8d69e6..5166298 100755 --- a/catalogue/templatetags/catalogue_tags.py +++ b/catalogue/templatetags/catalogue_tags.py @@ -1,6 +1,8 @@ +from collections import defaultdict from django import template from django.utils.datastructures import SortedDict from ..models import Lesson, Section +from curriculum.models import Level, CurriculumCourse from librarian.dcparser import WLURI, Person register = template.Library() @@ -8,43 +10,58 @@ register = template.Library() @register.inclusion_tag("catalogue/snippets/carousel.html") def catalogue_carousel(): - lessons_count = Lesson.objects.filter(type__in=('course', 'synthetic')).count() - if 1 < lessons_count % 10 < 5 and lessons_count / 10 % 10 != 1: - lessons_desc = u'kompletne lekcje' - else: - lessons_desc = u'kompletnych lekcji' - return locals() - -@register.inclusion_tag("catalogue/snippets/section_buttons.html") -def catalogue_section_buttons(): return { "object_list": Section.objects.all() } -@register.inclusion_tag("catalogue/snippets/section_box.html") -def section_box(section): - lessons = SortedDict() +@register.inclusion_tag("catalogue/snippets/levels_main.html") +def catalogue_levels_main(): + object_list = Level.objects.exclude(lesson=None) + c = object_list.count() + return { + 'object_list': object_list, + 'section_width': (700 - 20 * (c - 1)) / c, + } + + +@register.inclusion_tag("catalogue/snippets/level_box.html") +def level_box(level): + lessons = dict( + synthetic = [], + course = SortedDict(), + project = [], + ) + by_course = defaultdict(lambda: defaultdict(list)) + lesson_lists = [alist for alist in [ - list(section.lesson_set.all()), - list(section.lessonstub_set.all()) + list(level.lesson_set.exclude(type='appendix').order_by('section__order')), + list(level.lessonstub_set.all()) ] if alist] + while lesson_lists: min_index, min_list = min(enumerate(lesson_lists), key=lambda x: x[1][0].order) lesson = min_list.pop(0) if not min_list: lesson_lists.pop(min_index) - if lesson.level not in lessons: - newdict = SortedDict() - newdict['synthetic'] = [] - newdict['course'] = [] - lessons[lesson.level] = newdict - if lesson.type not in lessons[lesson.level]: - lessons[lesson.level][lesson.type] = [] - lessons[lesson.level][lesson.type].append(lesson) + if lesson.type == 'course': + if lesson.section not in lessons['course']: + lessons['course'][lesson.section] = [] + lessons['course'][lesson.section].append(lesson) + else: + lessons[lesson.type].append(lesson) + + if hasattr(lesson, 'curriculum_courses'): + for course in lesson.curriculum_courses.all(): + by_course[course][lesson.type].append(lesson) + + courses = [(course, by_course[course]) for course in + CurriculumCourse.objects.filter(lesson__level=level).distinct()] + return { - "section": section, + "level": level, "lessons": lessons, + "courses": courses, } @register.inclusion_tag("catalogue/snippets/lesson_nav.html") @@ -52,17 +69,16 @@ def lesson_nav(lesson): if lesson.type == 'course': root = lesson.section siblings = Lesson.objects.filter(type='course', level=lesson.level, section=root) - mark_level = False - link_other_level = True - else: + elif lesson.type == 'appendix': root = None siblings = Lesson.objects.filter(type=lesson.type) - mark_level = link_other_level = lesson.type == 'course' + else: + root = None + siblings = Lesson.objects.filter(type=lesson.type, level=lesson.level) return { "lesson": lesson, "root": root, "siblings": siblings, - "mark_level": mark_level } @register.inclusion_tag("catalogue/snippets/lesson_link.html") diff --git a/catalogue/urls.py b/catalogue/urls.py index 61e9e9a..3923f61 100755 --- a/catalogue/urls.py +++ b/catalogue/urls.py @@ -1,9 +1,9 @@ from django.conf.urls import patterns, include, url -from .views import SectionView, LessonView +from .views import LessonListView, LessonView urlpatterns = patterns('', url(r'^$', - SectionView.as_view(), + LessonListView.as_view(), name="catalogue_lessons"), url(r'^(?P[^/]+)/$', LessonView.as_view(), diff --git a/catalogue/views.py b/catalogue/views.py index 273bfa3..0ce7454 100644 --- a/catalogue/views.py +++ b/catalogue/views.py @@ -2,16 +2,17 @@ import os.path from django.conf import settings from django.views.generic import DetailView, ListView from .models import Lesson, Section +from curriculum.models import Level +from publishers.models import Publisher -class SectionView(ListView): - model = Section +class LessonListView(ListView): + queryset = Level.objects.exclude(lesson=None) + template_name = "catalogue/lesson_list.html" def get_context_data(self, **kwargs): - context = super(SectionView, self).get_context_data(**kwargs) + context = super(LessonListView, self).get_context_data(**kwargs) context['appendix'] = Lesson.objects.filter(type='appendix') - context['package_url'] = os.path.join(settings.MEDIA_URL, settings.CATALOGUE_PACKAGE) - context['package_student_url'] = os.path.join(settings.MEDIA_URL, settings.CATALOGUE_PACKAGE_STUDENT) return context @@ -23,4 +24,12 @@ class LessonView(DetailView): 'catalogue/lesson/%s/lesson_detail.html' % self.object.type, 'catalogue/lesson/lesson_detail.html', ] - + + def get_context_data(self, **kwargs): + context = super(LessonView, self).get_context_data(**kwargs) + try: + context['publisher'] = Publisher.objects.get( + name=context['object'].dc.get('publisher', '').strip()) + except: + pass + return context diff --git a/contact/forms.py b/contact/forms.py index 8fa0149..b975da3 100644 --- a/contact/forms.py +++ b/contact/forms.py @@ -1,7 +1,7 @@ from django.contrib.sites.models import Site from django.core.files.uploadedfile import UploadedFile from django.core.mail import send_mail, mail_managers -from django.core.validators import email_re +from django.core.validators import validate_email from django import forms from django.template.loader import render_to_string from django.template import RequestContext @@ -78,7 +78,7 @@ class ContactForm(forms.Form): mail_managers(mail_managers_subject, mail_managers_body, fail_silently=True) - if email_re.match(contact.contact): + if validate_email(contact.contact): mail_subject = render_to_string([ 'contact/%s/mail_subject.txt' % self.form_tag, 'contact/mail_subject.txt', diff --git a/curriculum/migrations/0010_auto__add_field_level_meta_name.py b/curriculum/migrations/0010_auto__add_field_level_meta_name.py new file mode 100644 index 0000000..24fc996 --- /dev/null +++ b/curriculum/migrations/0010_auto__add_field_level_meta_name.py @@ -0,0 +1,82 @@ +# -*- coding: utf-8 -*- +import datetime +from south.db import db +from south.v2 import SchemaMigration +from django.db import models + + +class Migration(SchemaMigration): + + def forwards(self, orm): + # Adding field 'Level.meta_name' + db.add_column(u'curriculum_level', 'meta_name', + self.gf('django.db.models.fields.CharField')(default=' ', max_length=255), + keep_default=False) + + + def backwards(self, orm): + # Deleting field 'Level.meta_name' + db.delete_column(u'curriculum_level', 'meta_name') + + + models = { + u'curriculum.competence': { + 'Meta': {'ordering': "['section', 'order']", 'object_name': 'Competence'}, + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name_en': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '255'}), + 'name_pl': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '255'}), + 'order': ('django.db.models.fields.IntegerField', [], {}), + 'section': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['curriculum.Section']"}), + 'slug': ('django.db.models.fields.SlugField', [], {'max_length': '50'}) + }, + u'curriculum.competencelevel': { + 'Meta': {'ordering': "['competence', 'level']", 'object_name': 'CompetenceLevel'}, + 'competence': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['curriculum.Competence']"}), + 'description_en': ('django.db.models.fields.TextField', [], {'default': "''"}), + 'description_pl': ('django.db.models.fields.TextField', [], {'default': "''"}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'level': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['curriculum.Level']"}) + }, + u'curriculum.curriculum': { + 'Meta': {'object_name': 'Curriculum'}, + 'course': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['curriculum.CurriculumCourse']"}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'identifier': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}), + 'level': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['curriculum.CurriculumLevel']"}), + 'title': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'type': ('django.db.models.fields.CharField', [], {'max_length': '16'}) + }, + u'curriculum.curriculumcourse': { + 'Meta': {'ordering': "['slug']", 'object_name': 'CurriculumCourse'}, + 'accusative': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'slug': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}), + 'title': ('django.db.models.fields.CharField', [], {'max_length': '255'}) + }, + u'curriculum.curriculumlevel': { + 'Meta': {'object_name': 'CurriculumLevel'}, + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'title': ('django.db.models.fields.CharField', [], {'max_length': '16', 'db_index': 'True'}) + }, + u'curriculum.level': { + 'Meta': {'ordering': "['order']", 'object_name': 'Level'}, + 'group_en': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '255'}), + 'group_pl': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '255'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'meta_name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'name_en': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '255'}), + 'name_pl': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '255'}), + 'order': ('django.db.models.fields.IntegerField', [], {}), + 'slug': ('django.db.models.fields.CharField', [], {'max_length': '255'}) + }, + u'curriculum.section': { + 'Meta': {'ordering': "['order']", 'object_name': 'Section'}, + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name_en': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '255'}), + 'name_pl': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '255'}), + 'order': ('django.db.models.fields.IntegerField', [], {}), + 'slug': ('django.db.models.fields.SlugField', [], {'max_length': '50'}) + } + } + + complete_apps = ['curriculum'] \ No newline at end of file diff --git a/curriculum/migrations/0011_meta_name.py b/curriculum/migrations/0011_meta_name.py new file mode 100644 index 0000000..0539ae7 --- /dev/null +++ b/curriculum/migrations/0011_meta_name.py @@ -0,0 +1,77 @@ +# -*- coding: utf-8 -*- +import datetime +from south.db import db +from south.v2 import DataMigration +from django.db import models + +class Migration(DataMigration): + + def forwards(self, orm): + "Write your forwards methods here." + orm.Level.objects.all().update(meta_name=models.F('slug')) + + def backwards(self, orm): + "Write your backwards methods here." + + models = { + u'curriculum.competence': { + 'Meta': {'ordering': "['section', 'order']", 'object_name': 'Competence'}, + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name_en': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '255'}), + 'name_pl': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '255'}), + 'order': ('django.db.models.fields.IntegerField', [], {}), + 'section': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['curriculum.Section']"}), + 'slug': ('django.db.models.fields.SlugField', [], {'max_length': '50'}) + }, + u'curriculum.competencelevel': { + 'Meta': {'ordering': "['competence', 'level']", 'object_name': 'CompetenceLevel'}, + 'competence': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['curriculum.Competence']"}), + 'description_en': ('django.db.models.fields.TextField', [], {'default': "''"}), + 'description_pl': ('django.db.models.fields.TextField', [], {'default': "''"}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'level': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['curriculum.Level']"}) + }, + u'curriculum.curriculum': { + 'Meta': {'object_name': 'Curriculum'}, + 'course': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['curriculum.CurriculumCourse']"}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'identifier': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}), + 'level': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['curriculum.CurriculumLevel']"}), + 'title': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'type': ('django.db.models.fields.CharField', [], {'max_length': '16'}) + }, + u'curriculum.curriculumcourse': { + 'Meta': {'ordering': "['slug']", 'object_name': 'CurriculumCourse'}, + 'accusative': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'slug': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}), + 'title': ('django.db.models.fields.CharField', [], {'max_length': '255'}) + }, + u'curriculum.curriculumlevel': { + 'Meta': {'object_name': 'CurriculumLevel'}, + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'title': ('django.db.models.fields.CharField', [], {'max_length': '16', 'db_index': 'True'}) + }, + u'curriculum.level': { + 'Meta': {'ordering': "['order']", 'object_name': 'Level'}, + 'group_en': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '255'}), + 'group_pl': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '255'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'meta_name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'name_en': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '255'}), + 'name_pl': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '255'}), + 'order': ('django.db.models.fields.IntegerField', [], {}), + 'slug': ('django.db.models.fields.CharField', [], {'max_length': '255'}) + }, + u'curriculum.section': { + 'Meta': {'ordering': "['order']", 'object_name': 'Section'}, + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name_en': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '255'}), + 'name_pl': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '255'}), + 'order': ('django.db.models.fields.IntegerField', [], {}), + 'slug': ('django.db.models.fields.SlugField', [], {'max_length': '50'}) + } + } + + complete_apps = ['curriculum'] + symmetrical = True diff --git a/curriculum/migrations/0012_auto__add_unique_level_meta_name__add_unique_level_slug.py b/curriculum/migrations/0012_auto__add_unique_level_meta_name__add_unique_level_slug.py new file mode 100644 index 0000000..f9fa032 --- /dev/null +++ b/curriculum/migrations/0012_auto__add_unique_level_meta_name__add_unique_level_slug.py @@ -0,0 +1,86 @@ +# -*- coding: utf-8 -*- +import datetime +from south.db import db +from south.v2 import SchemaMigration +from django.db import models + + +class Migration(SchemaMigration): + + def forwards(self, orm): + # Adding unique constraint on 'Level', fields ['meta_name'] + db.create_unique(u'curriculum_level', ['meta_name']) + + # Adding unique constraint on 'Level', fields ['slug'] + db.create_unique(u'curriculum_level', ['slug']) + + + def backwards(self, orm): + # Removing unique constraint on 'Level', fields ['slug'] + db.delete_unique(u'curriculum_level', ['slug']) + + # Removing unique constraint on 'Level', fields ['meta_name'] + db.delete_unique(u'curriculum_level', ['meta_name']) + + + models = { + u'curriculum.competence': { + 'Meta': {'ordering': "['section', 'order']", 'object_name': 'Competence'}, + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name_en': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '255'}), + 'name_pl': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '255'}), + 'order': ('django.db.models.fields.IntegerField', [], {}), + 'section': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['curriculum.Section']"}), + 'slug': ('django.db.models.fields.SlugField', [], {'max_length': '50'}) + }, + u'curriculum.competencelevel': { + 'Meta': {'ordering': "['competence', 'level']", 'object_name': 'CompetenceLevel'}, + 'competence': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['curriculum.Competence']"}), + 'description_en': ('django.db.models.fields.TextField', [], {'default': "''"}), + 'description_pl': ('django.db.models.fields.TextField', [], {'default': "''"}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'level': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['curriculum.Level']"}) + }, + u'curriculum.curriculum': { + 'Meta': {'object_name': 'Curriculum'}, + 'course': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['curriculum.CurriculumCourse']"}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'identifier': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}), + 'level': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['curriculum.CurriculumLevel']"}), + 'title': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'type': ('django.db.models.fields.CharField', [], {'max_length': '16'}) + }, + u'curriculum.curriculumcourse': { + 'Meta': {'ordering': "['slug']", 'object_name': 'CurriculumCourse'}, + 'accusative': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'slug': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}), + 'title': ('django.db.models.fields.CharField', [], {'max_length': '255'}) + }, + u'curriculum.curriculumlevel': { + 'Meta': {'object_name': 'CurriculumLevel'}, + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'title': ('django.db.models.fields.CharField', [], {'max_length': '16', 'db_index': 'True'}) + }, + u'curriculum.level': { + 'Meta': {'ordering': "['order']", 'object_name': 'Level'}, + 'group_en': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '255'}), + 'group_pl': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '255'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'meta_name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}), + 'name_en': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '255'}), + 'name_pl': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '255'}), + 'order': ('django.db.models.fields.IntegerField', [], {}), + 'slug': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}) + }, + u'curriculum.section': { + 'Meta': {'ordering': "['order']", 'object_name': 'Section'}, + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name_en': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '255'}), + 'name_pl': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '255'}), + 'order': ('django.db.models.fields.IntegerField', [], {}), + 'slug': ('django.db.models.fields.SlugField', [], {'max_length': '50'}) + } + } + + complete_apps = ['curriculum'] \ No newline at end of file diff --git a/curriculum/migrations/0013_auto__add_field_level_package__add_field_level_student_package.py b/curriculum/migrations/0013_auto__add_field_level_package__add_field_level_student_package.py new file mode 100644 index 0000000..4e0ee70 --- /dev/null +++ b/curriculum/migrations/0013_auto__add_field_level_package__add_field_level_student_package.py @@ -0,0 +1,92 @@ +# -*- coding: utf-8 -*- +import datetime +from south.db import db +from south.v2 import SchemaMigration +from django.db import models + + +class Migration(SchemaMigration): + + def forwards(self, orm): + # Adding field 'Level.package' + db.add_column(u'curriculum_level', 'package', + self.gf('django.db.models.fields.files.FileField')(max_length=255, null=True, blank=True), + keep_default=False) + + # Adding field 'Level.student_package' + db.add_column(u'curriculum_level', 'student_package', + self.gf('django.db.models.fields.files.FileField')(max_length=255, null=True, blank=True), + keep_default=False) + + + def backwards(self, orm): + # Deleting field 'Level.package' + db.delete_column(u'curriculum_level', 'package') + + # Deleting field 'Level.student_package' + db.delete_column(u'curriculum_level', 'student_package') + + + models = { + u'curriculum.competence': { + 'Meta': {'ordering': "['section', 'order']", 'object_name': 'Competence'}, + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name_en': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '255'}), + 'name_pl': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '255'}), + 'order': ('django.db.models.fields.IntegerField', [], {}), + 'section': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['curriculum.Section']"}), + 'slug': ('django.db.models.fields.SlugField', [], {'max_length': '50'}) + }, + u'curriculum.competencelevel': { + 'Meta': {'ordering': "['competence', 'level']", 'object_name': 'CompetenceLevel'}, + 'competence': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['curriculum.Competence']"}), + 'description_en': ('django.db.models.fields.TextField', [], {'default': "''"}), + 'description_pl': ('django.db.models.fields.TextField', [], {'default': "''"}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'level': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['curriculum.Level']"}) + }, + u'curriculum.curriculum': { + 'Meta': {'object_name': 'Curriculum'}, + 'course': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['curriculum.CurriculumCourse']"}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'identifier': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}), + 'level': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['curriculum.CurriculumLevel']"}), + 'title': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'type': ('django.db.models.fields.CharField', [], {'max_length': '16'}) + }, + u'curriculum.curriculumcourse': { + 'Meta': {'ordering': "['slug']", 'object_name': 'CurriculumCourse'}, + 'accusative': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'slug': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}), + 'title': ('django.db.models.fields.CharField', [], {'max_length': '255'}) + }, + u'curriculum.curriculumlevel': { + 'Meta': {'object_name': 'CurriculumLevel'}, + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'title': ('django.db.models.fields.CharField', [], {'max_length': '16', 'db_index': 'True'}) + }, + u'curriculum.level': { + 'Meta': {'ordering': "['order']", 'object_name': 'Level'}, + 'group_en': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '255'}), + 'group_pl': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '255'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'meta_name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}), + 'name_en': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '255'}), + 'name_pl': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '255'}), + 'order': ('django.db.models.fields.IntegerField', [], {}), + 'package': ('django.db.models.fields.files.FileField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), + 'slug': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}), + 'student_package': ('django.db.models.fields.files.FileField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}) + }, + u'curriculum.section': { + 'Meta': {'ordering': "['order']", 'object_name': 'Section'}, + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name_en': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '255'}), + 'name_pl': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '255'}), + 'order': ('django.db.models.fields.IntegerField', [], {}), + 'slug': ('django.db.models.fields.SlugField', [], {'max_length': '50'}) + } + } + + complete_apps = ['curriculum'] \ No newline at end of file diff --git a/curriculum/models.py b/curriculum/models.py index b53d2ca..b4d8ac4 100644 --- a/curriculum/models.py +++ b/curriculum/models.py @@ -22,7 +22,7 @@ class Section(models.Model): def url_for_level(self, level): return "%s?s=%d&level=%s&d=1" % (reverse("curriculum"), self.pk, level.slug) - + add_translatable(Section, { 'name': models.CharField(_('name'), max_length=255, default = '') }) @@ -66,8 +66,13 @@ add_translatable(Competence, { class Level(models.Model): - slug = models.CharField(_('slug'), max_length=255) + slug = models.CharField(_('slug'), max_length=255, unique=True) + meta_name = models.CharField(_('meta name'), max_length=255, unique=True) order = models.IntegerField(_('order')) + package = models.FileField(upload_to=lambda i, f: "curriculum/pack/edukacjamedialna_%s.zip" % i.slug, + null=True, blank=True, max_length=255) + student_package = models.FileField(upload_to=lambda i, f: "curriculum/pack/edukacjamedialna_%s_uczen.zip" % i.slug, + null=True, blank=True, max_length=255) class Meta: ordering = ['order'] @@ -77,6 +82,48 @@ class Level(models.Model): def __unicode__(self): return self.name + def length_course(self): + return self.lesson_set.filter(type='course').count() + + def length_synthetic(self): + return self.lesson_set.filter(type='synthetic').count() + + def build_package(self, student): + from StringIO import StringIO + import zipfile + from django.core.files.base import ContentFile + from catalogue.templatetags.catalogue_tags import section_box + from catalogue.models import Lesson + + buff = StringIO() + zipf = zipfile.ZipFile(buff, 'w', zipfile.ZIP_STORED) + + lessons = section_box(self)['lessons'] + for i, lesson in enumerate(lessons['synthetic']): + prefix = 'Skrocony kurs/%d %s/' % (i, lesson.slug) + lesson.add_to_zip(zipf, student, prefix) + for c, (section, clessons) in enumerate(lessons['course'].items()): + for i, lesson in enumerate(clessons): + prefix = 'Pelny kurs/%d %s/%d %s/' % (c, section.slug, i, lesson.slug) + lesson.add_to_zip(zipf, student, prefix) + for i, lesson in enumerate(lessons['project']): + prefix = 'Kurs skrocony/%d %s/' % (i, lesson.slug) + lesson.add_to_zip(zipf, student, prefix) + # Add all appendix lessons, from all levels. + for lesson in Lesson.objects.exclude(type__in=('synthetic', 'course', 'project')): + prefix = '%s/' % lesson.slug + lesson.add_to_zip(zipf, student, prefix) + zipf.close() + + fieldname = "student_package" if student else "package" + getattr(self, fieldname).save(None, ContentFile(buff.getvalue())) + + def build_packages(self): + self.build_package(False) + self.build_package(True) + + + add_translatable(Level, { 'name': models.CharField(_('name'), max_length=255, default = ''), 'group': models.CharField(_('group'), max_length=255, default = '') diff --git a/curriculum/templates/curriculum/snippets/course_boxes_toc.html b/curriculum/templates/curriculum/snippets/course_boxes_toc.html index db6d484..a2000b7 100755 --- a/curriculum/templates/curriculum/snippets/course_boxes_toc.html +++ b/curriculum/templates/curriculum/snippets/course_boxes_toc.html @@ -1,10 +1,14 @@ {% url "catalogue_lessons" as lessons_url %} -{% for course in object_list %} -
  • - {% if accusative %} - {{ course.accusative }} - {% else %} - {{ course }} - {% endif %} -
  • +{% for level, course_list in object_list %} +
    {{ level }}: + +
    {% endfor %} diff --git a/curriculum/templatetags/curriculum_tags.py b/curriculum/templatetags/curriculum_tags.py index 986271c..4e02e04 100755 --- a/curriculum/templatetags/curriculum_tags.py +++ b/curriculum/templatetags/curriculum_tags.py @@ -1,6 +1,7 @@ from django import template from django.utils.datastructures import SortedDict from ..models import Competence, Curriculum, CurriculumCourse +from catalogue.models import Lesson register = template.Library() @@ -19,7 +20,7 @@ def competence(texts, level): @register.inclusion_tag("curriculum/snippets/curriculum.html") def curriculum(identifiers): try: - currs = [Curriculum.objects.get(identifier=identifier) + currs = [Curriculum.objects.get(identifier__iexact=identifier.replace(' ', '')) for identifier in identifiers] except Curriculum.DoesNotExist: return {'identifiers': identifiers} @@ -70,7 +71,18 @@ def course_boxes(): @register.inclusion_tag("curriculum/snippets/course_boxes_toc.html") def course_boxes_toc(accusative=False): + last = None, None + object_list = [] + for l in Lesson.curriculum_courses.through.objects.all().order_by( + 'lesson__level', 'curriculumcourse'): + level, course = l.lesson.level, l.curriculumcourse + if (level, course) == last: + continue + if level != last[0]: + object_list.append((level, [])) + object_list[-1][1].append(course) + last = (level, course) return { - 'object_list': CurriculumCourse.objects.all(), + 'object_list': object_list, 'accusative': accusative, } diff --git a/edumed/settings.d/30-apps.py b/edumed/settings.d/30-apps.py index 7091ff1..ee80ab7 100644 --- a/edumed/settings.d/30-apps.py +++ b/edumed/settings.d/30-apps.py @@ -3,12 +3,13 @@ INSTALLED_APPS = ( 'curriculum', 'catalogue', 'comment', + 'publishers', 'fnpdjango', 'south', 'pipeline', # Disable, if not using Piwik. - 'piwik.django', + 'piwik', # Disable, if not using CAS. 'honeypot', 'django_cas', diff --git a/edumed/settings.d/40-middleware.py b/edumed/settings.d/40-middleware.py index 998b707..bb7401f 100644 --- a/edumed/settings.d/40-middleware.py +++ b/edumed/settings.d/40-middleware.py @@ -15,8 +15,6 @@ MIDDLEWARE_CLASSES = tuple(x for x in ( if "django_cas" in INSTALLED_APPS else None, 'django.contrib.messages.middleware.MessageMiddleware' if "django.contrib.messages" in INSTALLED_APPS else None, - 'piwik.django.middleware.PiwikMiddleware' - if "piwik.django" in INSTALLED_APPS else None, # Uncomment the next line for simple clickjacking protection: # 'django.middleware.clickjacking.XFrameOptionsMiddleware', 'pagination.middleware.PaginationMiddleware' diff --git a/edumed/settings.d/50-contrib.py b/edumed/settings.d/50-contrib.py index 64770e8..e5b3dee 100644 --- a/edumed/settings.d/50-contrib.py +++ b/edumed/settings.d/50-contrib.py @@ -11,3 +11,6 @@ PYBB_ENABLE_ANONYMOUS_POST = False PYBB_DEFAULT_TITLE = u'Forum' PYBB_DEFAULT_TIME_ZONE = 1 PYBB_PERMISSION_HANDLER = 'edumed.forum.ForumPermissionHandler' + +THUMBNAIL_ENGINE = 'sorl.thumbnail.engines.convert_engine.Engine' +THUMBNAIL_CONVERT = 'convert -density 300 -background white -flatten -alpha off' diff --git a/edumed/settings.d/50-static.py b/edumed/settings.d/50-static.py index 43dbb7c..7cdd26c 100644 --- a/edumed/settings.d/50-static.py +++ b/edumed/settings.d/50-static.py @@ -39,8 +39,10 @@ PIPELINE_JS = { 'catalogue/js/jquery.cycle.all.js', 'jquery/colorbox/jquery.colorbox-min.js', 'jquery/colorbox/jquery.colorbox-pl.js', + 'catalogue/js/carousel.js', 'catalogue/js/edumed.js', 'catalogue/js/lesson.js', + 'catalogue/js/lesson-list.js', 'sponsors/js/sponsors.js', 'curriculum/curriculum.js', 'js/formset.js', diff --git a/edumed/settings.d/60-custom.py b/edumed/settings.d/60-custom.py index 758819b..869e6f4 100644 --- a/edumed/settings.d/60-custom.py +++ b/edumed/settings.d/60-custom.py @@ -1,3 +1 @@ -CATALOGUE_PACKAGE = "catalogue/edukacjamedialna.zip" -CATALOGUE_PACKAGE_STUDENT = "catalogue/edukacjamedialna_uczen.zip" CONTACT_FORMS_MODULE = 'edumed.contact_forms' diff --git a/edumed/static/css/main.css b/edumed/static/css/main.css index 4fecbb1..ffb78d9 100644 --- a/edumed/static/css/main.css +++ b/edumed/static/css/main.css @@ -1,10 +1,10 @@ #main-promobox { float: right; - border-radius: 0.938em; + border-radius: 0.9375em; background: #16a487; padding: 1.5em 1.25em; width: 11.25em; - height: 11.688em; } + height: 11.6875em; } #main-promobox a { display: block; } #main-promobox h1 { @@ -35,28 +35,26 @@ width: 43.75em; } #main-sections h1 { font-size: .9em; - margin: 0 0 0 1.6em; + margin: 0 0 0 1.25em; text-transform: uppercase; } #main-sections ul { - margin: -0.188em 0 0 -1.25em; + margin: -0.1875em 0 0 -1.25em; padding: 0; list-style: none; } #main-sections ul li { margin-top: 1.25em; margin-left: 1.25em; float: left; - width: 10em; height: 5.625em; - border-radius: 0.938em; } + border-radius: 0.9375em; } #main-sections ul li a { color: white; text-transform: uppercase; display: block; height: 5em; - width: 9.375em; display: table; - padding: 0.313em; } - #main-sections ul li a span { + padding: 5px; } + #main-sections ul li a .in-box { font-size: .9em; height: 100%; width: 100%; @@ -65,7 +63,12 @@ border: 1px solid transparent; border-radius: 0.625em; padding-left: 1em; } - #main-sections ul li a:hover span { + #main-sections ul li a .in-box .name { + display: block; + font-size: 1.5em; + line-height: 1em; + margin-bottom: .2em; } + #main-sections ul li a:hover .in-box { border: 1px solid white; } #main-sections ul .box1 { background-color: #adaeaf; } @@ -76,7 +79,7 @@ #main-sections ul .box4 { background-color: #5e6165; } #main-sections ul .box5 { - background-color: #16a487; } + background-color: #f8b323; } #main-sections ul .box6 { background-color: #363a3e; } #main-sections ul .box7 { @@ -84,20 +87,51 @@ #main-sections ul .box8 { background-color: #ed7831; } -#main-chosen { +#main-howto { float: right; margin-top: 1.2em; width: 13.75em; } - #main-chosen h1 { + #main-howto h1 { font-size: .9em; margin: 0 0 0 1.4em; text-transform: uppercase; } - #main-chosen ul { - margin: 1.063em 0 0 1.4em; } - #main-chosen ul li { + #main-howto ul { + margin: 1.0625em 0 1.0625em 1.4em; } + #main-howto ul li { font-size: .9em; text-transform: uppercase; line-height: 1.25em; } + #main-howto ul a:before { + height: 1.25em; } + #main-howto ul .knowledge:before { + content: url(/static/img/icons/knowledge_dark.png); } + #main-howto ul .activity:before { + content: url(/static/img/icons/activity_dark.png); } + #main-howto ul .lesson-plan:before { + content: url(/static/img/icons/lesson-plan_dark.png); } + #main-howto ul .reference:before { + content: url(/static/img/icons/reference_dark.png); } + #main-howto ul .knowledge:hover:before { + content: url(/static/img/icons/knowledge_orange.png); } + #main-howto ul .activity:hover:before { + content: url(/static/img/icons/activity_orange.png); } + #main-howto ul .lesson-plan:hover:before { + content: url(/static/img/icons/lesson-plan_orange.png); } + #main-howto ul .reference:hover:before { + content: url(/static/img/icons/reference_orange.png); } + #main-howto p { + margin: 0 0 1.875em 1.4em; } + +#main-chosen { + clear: left; + float: left; + margin-top: 2em; } + #main-chosen h1 { + font-size: .9em; + margin: 0 0 1em 1.25em; + text-transform: uppercase; } + #main-chosen .levelth { + margin-left: 1.25em; } #main-tools { clear: both; } diff --git a/edumed/static/css/main.scss b/edumed/static/css/main.scss index e956c81..54b2d35 100755 --- a/edumed/static/css/main.scss +++ b/edumed/static/css/main.scss @@ -48,7 +48,7 @@ $px: .0625em; h1 { font-size: .9em; - margin: 0 0 0 1.6em; + margin: 0 0 0 20*$px; text-transform: uppercase; } @@ -61,7 +61,6 @@ $px: .0625em; margin-top: 20*$px; margin-left: 20*$px; float: left; - width: 160*$px; height: 90*$px; border-radius: 15*$px; @@ -70,11 +69,10 @@ $px: .0625em; text-transform: uppercase; display: block; height: 80*$px; - width: 150*$px; display: table; - padding: 5*$px; + padding: 5px; - span { + .in-box { font-size: .9em; height: 100%; width: 100%; @@ -83,9 +81,16 @@ $px: .0625em; border: 1px solid transparent; border-radius: 10*$px; padding-left: 16*$px; + + .name { + display: block; + font-size: 1.5em; + line-height: 1em; + margin-bottom: .2em; + } } } - a:hover span { + a:hover .in-box { border: 1px solid white; } } @@ -93,14 +98,15 @@ $px: .0625em; .box2 {background-color: #f8b323;} .box3 {background-color: #16a487;} .box4 {background-color: #5e6165;} - .box5 {background-color: #16a487;} + // .box5 {background-color: #16a487;} + .box5 {background-color: #f8b323;} .box6 {background-color: #363a3e;} .box7 {background-color: #adaeaf;} .box8 {background-color: #ed7831;} } } -#main-chosen { +#main-howto { float: right; margin-top: 1.2em; width: 220*$px; @@ -112,13 +118,45 @@ $px: .0625em; } ul { - margin: 17*$px 0 0 1.4em;; + margin: 17*$px 0 17*$px 1.4em; li { font-size: .9em; text-transform: uppercase; line-height: 1.25em; } + a:before { + height: 20*$px; + } + + .knowledge:before {content: url(/static/img/icons/knowledge_dark.png);} + .activity:before {content: url(/static/img/icons/activity_dark.png);} + .lesson-plan:before {content: url(/static/img/icons/lesson-plan_dark.png);} + .reference:before {content: url(/static/img/icons/reference_dark.png);} + .knowledge:hover:before {content: url(/static/img/icons/knowledge_orange.png);} + .activity:hover:before {content: url(/static/img/icons/activity_orange.png);} + .lesson-plan:hover:before {content: url(/static/img/icons/lesson-plan_orange.png);} + .reference:hover:before {content: url(/static/img/icons/reference_orange.png);} + + } + p { + margin: 0 0 30*$px 1.4em; + } +} + +#main-chosen { + clear: left; + float: left; + margin-top: 2em; + + h1 { + font-size: .9em; + margin: 0 0 1em 20*$px; + text-transform: uppercase; + } + + .levelth { + margin-left: 20*$px; } } diff --git a/edumed/static/img/icons/internet_black.png b/edumed/static/img/icons/internet_black.png new file mode 100644 index 0000000..538e60b Binary files /dev/null and b/edumed/static/img/icons/internet_black.png differ diff --git a/edumed/static/img/icons/nointernet_black.png b/edumed/static/img/icons/nointernet_black.png new file mode 100644 index 0000000..9977783 Binary files /dev/null and b/edumed/static/img/icons/nointernet_black.png differ diff --git a/edumed/templates/base_super.html b/edumed/templates/base_super.html index f4a3c27..9607254 100644 --- a/edumed/templates/base_super.html +++ b/edumed/templates/base_super.html @@ -3,6 +3,7 @@ {% load fnp_common fnp_share fnp_lang macros %} {% load compressed static %} {% load subdomainurls %} +{% load piwik_tags %} {% macro title %}{% block title %}{% endblock %}{% endmacro %} {% macro site_name %}Edukacja medialna{% endmacro %} @@ -98,6 +99,6 @@ {% compressed_js 'base' %} {% block extra_script %}{% endblock %} - {{ piwik_tag|safe }} + {% tracking_code %} diff --git a/edumed/templates/home.html b/edumed/templates/home.html index 3a82a7b..ce81ed9 100755 --- a/edumed/templates/home.html +++ b/edumed/templates/home.html @@ -17,16 +17,28 @@

    Lekcje:

    -{% catalogue_section_buttons %} +{% catalogue_levels_main %}
    -
    -

    Wybrane tematy na:

    +
    +

    Nasze lekcje to:

    +

    Zobacz, jak przeprowadzili je inni.

    + +{# #} +
    + +
    +

    Według podstawy programowej:

    +{% course_boxes_toc %}
    +
    @@ -39,8 +51,6 @@