4e7a38c67e35039021cdda163896f91af5131a4d
[edumed.git] / catalogue / management / commands / importlessons.py
1 # -*- coding: utf-8 -*-
2 # This file is part of EduMed, licensed under GNU Affero GPLv3 or later.
3 # Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
4 #
5 import os
6 import sys
7 import time
8 from optparse import make_option
9 from django.conf import settings
10 from django.core.management.base import BaseCommand
11 from django.core.management.color import color_style
12 from django.core.files import File
13
14 from librarian import IOFile
15 from catalogue.models import Lesson, Section
16
17 #from search import Index
18
19
20 class Command(BaseCommand):
21     option_list = BaseCommand.option_list + (
22         make_option('-q', '--quiet', action='store_false', dest='verbose', default=True,
23             help='Verbosity level; 0=minimal output, 1=normal output, 2=all output'),
24         make_option('-a', '--attachments', dest='attachments', metavar="PATH", default='materialy',
25             help='Attachments dir path.'),
26     )
27     help = 'Imports lessons from the specified directories.'
28     args = 'directory [directory ...]'
29
30     def import_book(self, file_path, options, attachments):
31         verbose = options.get('verbose')
32         iofile = IOFile.from_filename(os.path.join(self.curdir, file_path))
33         iofile.attachments = attachments
34         lesson = Lesson.publish(iofile)
35
36     @staticmethod
37     def all_attachments(path):
38         files = {}
39
40         def read_dir(path):
41             for name in os.listdir(path):
42                 fullname = os.path.join(path, name)
43                 if os.path.isdir(fullname):
44                     read_dir(fullname)
45                 else:
46                     f = IOFile.from_filename(fullname)
47                     files[name] = f
48                     files.setdefault(name.replace(" ", ""), f)
49
50         read_dir(path)
51         return files
52
53
54     def handle(self, *directories, **options):
55         from django.db import transaction
56
57         self.style = color_style()
58         
59         verbose = options.get('verbose')
60         self.curdir = os.path.abspath(os.curdir)
61
62
63         # Start transaction management.
64         transaction.commit_unless_managed()
65         transaction.enter_transaction_management()
66         transaction.managed(True)
67
68         files_imported = 0
69         files_skipped = 0
70
71         for dir_name in directories:
72             abs_dir = os.path.join(self.curdir, dir_name)
73             if not os.path.isdir(abs_dir):
74                 print self.style.ERROR("%s: Not a directory. Skipping." % abs_dir)
75             else:
76                 att_dir = os.path.join(abs_dir, options['attachments'])
77                 attachments = self.all_attachments(att_dir)
78
79                 # files queue
80                 files = sorted(os.listdir(abs_dir))
81                 postponed = {}
82                 while files:
83                     file_name = files.pop(0)
84                     file_path = os.path.join(abs_dir, file_name)
85                     file_base, ext = os.path.splitext(file_path)
86
87                     # Skip files that are not XML files
88                     if not ext == '.xml':
89                         continue
90
91                     if verbose > 0:
92                         print "Parsing '%s'" % file_path
93                     else:
94                         sys.stdout.write('.')
95                         sys.stdout.flush()
96
97                     # Import book files
98                     try:
99                         self.import_book(file_path, options, attachments)
100                         files_imported += 1
101                         transaction.commit()
102                     except Section.IncompleteError, e:
103                         if file_name not in postponed or postponed[file_name] < files_imported:
104                             # Push it back into the queue, maybe the missing lessons will show up.
105                             if verbose > 0:
106                                 print self.style.NOTICE('Waiting for missing lessons.')
107                             files.append(file_name)
108                             postponed[file_name] = files_imported
109                         else:
110                             # We're in a loop, nothing's being imported - some lesson is really missing.
111                             raise e
112                     except BaseException, e:
113                         import traceback
114                         traceback.print_exc()
115                         files_skipped += 1
116
117         # Print results
118         print
119         print "Results: %d files imported, %d skipped, %d total." % (
120             files_imported, files_skipped, files_imported + files_skipped)
121         print
122
123         transaction.commit()
124         transaction.leave_transaction_management()