Statistics
| Branch: | Tag: | Revision:

root / cloudcms / forms.py @ deb708bf

History | View | Annotate | Download (8 kB)

1
# -*- coding: utf-8 -*-
2

    
3
import zipfile
4
import tempfile
5
import os
6
import glob
7
import logging
8

    
9
from django import forms
10
from django.conf import settings
11
from django.db import transaction
12
from django.core.files import File
13

    
14
from feincms.module.medialibrary.models import Category as MediaCategory, \
15
        MediaFile
16

    
17
from cloudcmsguide.models import UserGuideEntry
18
from cloudcmsfaq.models import Category as FaqCategory, Question
19
from cloudcms.rstutils import generate_rst_contents_from_dir
20
from cloudcms.models import Service, ServiceTranslation, Application
21
from feincms.content.raw.models import RawContent
22

    
23
logger = logging.getLogger('cloudcms.rstimport')
24

    
25
# base filename to service slug map
26
DEFAULT_SERVICE_MAP = {
27
        'cyclades':'cyclades',
28
        'okeanos':'okeanos',
29
        'pithos':'pithos'
30
}
31

    
32
DEFAULT_REGION_MAP = {
33
        'faq':'main',
34
        'userguide':'main',
35
}
36

    
37
DEFAULT_RESIZE_GEOMETRY = (400, 400)
38

    
39
SERVICE_MAP = getattr(settings, 'CMS_RST_IMPORT_SERVICE_FILE_MAP',
40
        DEFAULT_SERVICE_MAP)
41
REGIONS_MAP = getattr(settings, 'CMS_RST_IMPORT_REGIONS_MAP',
42
        DEFAULT_REGION_MAP)
43
RESIZE_GEOMETRY = getattr(settings, 'CMS_RST_IMPORT_RESIZE_GEOMETRY',
44
    DEFAULT_RESIZE_GEOMETRY)
45

    
46
def service_from_filename(rst):
47
    fname = os.path.basename(rst).replace(".rst","")
48
    service_slug = DEFAULT_SERVICE_MAP.get(fname, None)
49
    if not service_slug:
50
        return None
51

    
52
    try:
53
        return Service.objects.filter(translations__slug=service_slug)[0]
54
    except IndexError:
55
        return None
56
    except Service.DoesNotExist:
57
        return None
58

    
59
    return None
60

    
61

    
62
def get_media_category(slug):
63
    return MediaCategory.objects.get(slug=slug)
64

    
65

    
66
CATEGORIES_CHOICES = (('faqs', 'FAQs'), ('guide', 'User guide'))
67

    
68
class RstZipImportForm(forms.Form):
69

    
70
    FAQ_MEDIA_CATEGORY = 'faq-images'
71
    GUIDE_MEDIA_CATEGORY = 'user-guide-images'
72

    
73
    clean_data = forms.BooleanField(initial=False, required=False)
74
    dry_run = forms.BooleanField(initial=True, required=False,
75
            widget=forms.HiddenInput)
76
    import_file = forms.FileField(required=True)
77

    
78
    def __init__(self, *args, **kwargs):
79
        super(RstZipImportForm, self).__init__(*args, **kwargs)
80
        self.log_data = ""
81

    
82
    def log(self, msg):
83
        self.log_data += "\n" + msg
84

    
85
    def get_tmp_file(self, f):
86
        tmp = tempfile.mktemp('cloudcms-sphinx-import')
87
        f.file.reset()
88
        fd = file(tmp, 'w')
89
        fd.write(f.read())
90
        fd.close()
91
        return tmp
92

    
93
    def clean_import_file(self):
94
        f = self.cleaned_data['import_file']
95
        tmpfile = self.get_tmp_file(f)
96
        if not zipfile.is_zipfile(tmpfile):
97
            raise forms.ValidationError("Invalid zip file")
98
        return f
99

    
100
    def clean(self, *args, **kwargs):
101
        data = super(RstZipImportForm, self).clean(*args, **kwargs)
102
        return data
103

    
104
    def clean_existing_data(self):
105
        Question.objects.all().delete()
106
        UserGuideEntry.objects.all().delete()
107
        MediaFile.objects.filter(categories__slug__in=[self.FAQ_MEDIA_CATEGORY, \
108
            self.GUIDE_MEDIA_CATEGORY]).delete()
109

    
110
    def save(self, user, use_dir=None):
111
        dry_run = self.cleaned_data.get('dry_run')
112
        clean_data = self.cleaned_data.get('clean_data')
113
        import_file = self.cleaned_data.get('import_file')
114

    
115
        if not use_dir:
116
            zipdir = tempfile.mkdtemp('cloudcms-sphinx-exports')
117
            zipdatafile = self.get_tmp_file(import_file)
118
            zipf = zipfile.ZipFile(file(zipdatafile))
119
            zipf.extractall(zipdir)
120
        else:
121
            zipdir = use_dir
122

    
123
        subdirs = os.listdir(zipdir)
124
        if len(subdirs) == 1 and os.path.isdir(os.path.join(zipdir, \
125
                subdirs[0])) and subdirs[0] != 'source':
126
            zipdir = os.path.join(zipdir, subdirs[0])
127

    
128
        #sid = transaction.savepoint()
129

    
130
        if clean_data:
131
            try:
132
                self.clean_existing_data()
133
            except Exception, e:
134
                return False
135

    
136
        ret = ""
137
        try:
138
            for data_type, rst, category, slug, title, html_content, \
139
                    images, stderr in generate_rst_contents_from_dir(zipdir):
140

    
141
                ret += stderr
142
                #logger.info("Parsed %s" % (rst, ))
143
                if stderr:
144
                    pass
145
                    #logger.info("Error output: %s" % (stderr, ))
146

    
147
                service = service_from_filename(rst)
148
                if not service:
149
                    logger.info("Skipping entry for file '%s'. No category found" % rst)
150
                    continue
151

    
152

    
153
                # first save media files
154
                newimages = []
155
                if data_type == 'userguide':
156
                    cat = get_media_category(self.GUIDE_MEDIA_CATEGORY)
157
                if data_type == 'faq':
158
                    cat = get_media_category(self.FAQ_MEDIA_CATEGORY)
159

    
160
                if not cat:
161
                    continue
162

    
163
                for imgname, imgpath, imgabspath in images:
164
                    newalt, newpath = create_or_update_media_file(cat, \
165
                            imgname, imgabspath)
166

    
167
                    html_content = html_content.replace(imgpath, newpath)
168

    
169
                # now html contains correct image links, we are ready to save
170
                # the faq/guide content
171
                if data_type == 'faq':
172
                    cat = add_or_update_faq_category(category[0], category[1])
173
                    question = add_or_update_faq_question(user, service, cat, slug, \
174
                            title, html_content)
175

    
176
                if data_type == 'userguide':
177
                    guide_entry = add_or_update_guide_entry(user, service, slug, \
178
                            title, html_content)
179

    
180

    
181
        except Exception, e:
182
            logger.exception("RST import failed")
183
            #transaction.savepoint_rollback(sid)
184
            return False
185

    
186
        if dry_run:
187
            pass
188
            #transaction.savepoint_rollback(sid)
189
        else:
190
            pass
191
            #transaction.savepoint_commit(sid)
192

    
193

    
194
def create_or_update_media_file(category, name, path):
195
    name = category.title + " " + name
196

    
197
    try:
198
        # TODO: Check language ?????
199
        mf = MediaFile.objects.get(categories=category, translations__caption=name)
200
    except MediaFile.DoesNotExist:
201
        mf = MediaFile()
202
        mf.category = category
203
        mf.file = File(open(path))
204
        mf.save()
205
        mf.translations.create(caption=name)
206

    
207
    # TODO: Check language ?????
208
    return mf.translations.all()[0].caption, mf.get_absolute_url()
209

    
210

    
211
def add_or_update_faq_category(slug, name):
212
    try:
213
        category = FaqCategory.objects.get(translations__slug=slug)
214
    except FaqCategory.DoesNotExist:
215
        category = FaqCategory()
216
        category.save()
217
        category.translations.create(slug=slug, title=name)
218

    
219
    return category
220

    
221
def add_or_update_faq_question(author, service, category, slug,\
222
        title, html_content):
223

    
224
    try:
225
        q = Question.objects.get(slug=slug)
226
    except:
227
        q = Question()
228

    
229
    q.author = author
230
    q.is_active = True
231
    q.category = category
232
    q.service = service
233
    q.slug = slug
234
    q.title = title
235
    q.save()
236
    q.application = [Application.current()]
237
    q.save()
238

    
239
    RawContentModel = Question.content_type_for(RawContent)
240
    try:
241
        content = q.rawcontent_set.filter()[0]
242
    except:
243
        content = q.rawcontent_set.create(region=REGIONS_MAP['faq'])
244

    
245
    content.text = html_content
246
    content.save()
247

    
248
    return q
249

    
250
def add_or_update_guide_entry(author, service, slug, title, html_content):
251
    try:
252
        guide = UserGuideEntry.objects.get(slug=slug)
253
    except:
254
        guide = UserGuideEntry()
255

    
256
    guide.author = author
257
    guide.is_active = True
258
    guide.service = service
259
    guide.slug = slug
260
    guide.title = title
261
    guide.save()
262

    
263
    RawContentModel = UserGuideEntry.content_type_for(RawContent)
264
    try:
265
        content = guide.rawcontent_set.filter()[0]
266
    except:
267
        content = guide.rawcontent_set.create(region=REGIONS_MAP['userguide'])
268

    
269
    content.text = html_content
270
    content.save()
271

    
272
    return guide
273