src/cm/views/create.py
changeset 460 2fdb7d095d5c
parent 216 6f635c8e98c3
child 463 9c7de6dd1723
equal deleted inserted replaced
459:a69421197502 460:2fdb7d095d5c
     1 from cm.cm_settings import VALID_EMAIL_FOR_PUBLISH, SITE_NAME
     1 from cm.cm_settings import VALID_EMAIL_FOR_PUBLISH, SITE_NAME
     2 from cm.converters import convert_from_mimetype
     2 from cm.converters import convert_from_mimetype
     3 from cm.converters.pandoc_converters import pandoc_convert
     3 from cm.converters.pandoc_converters import pandoc_convert
     4 from cm.models import Text, TextVersion, Attachment
     4 from cm.models import Text, TextVersion, Comment, Attachment
     5 from cm.utils.files import remove_extension
     5 from cm.utils.files import remove_extension
     6 from cm.utils.mail import EmailMessage
     6 from cm.utils.mail import EmailMessage
     7 from cm.views import get_text_by_keys_or_404
     7 from cm.views import get_text_by_keys_or_404
     8 from django import forms
     8 from django import forms
     9 from cm.message import display_message
     9 from cm.message import display_message
    14 from django.http import HttpResponse, HttpResponseRedirect
    14 from django.http import HttpResponse, HttpResponseRedirect
    15 from django.shortcuts import render_to_response
    15 from django.shortcuts import render_to_response
    16 from django.template import RequestContext
    16 from django.template import RequestContext
    17 from django.template.loader import render_to_string
    17 from django.template.loader import render_to_string
    18 from django.utils.translation import ugettext as _, ugettext_lazy
    18 from django.utils.translation import ugettext as _, ugettext_lazy
       
    19 from django.db import connection, transaction
    19 from mimetypes import guess_type
    20 from mimetypes import guess_type
    20 from cm.activity import register_activity
    21 from cm.activity import register_activity
    21 from cm.security import has_global_perm
    22 from cm.security import has_global_perm
    22 import os
    23 import os
       
    24 from BeautifulSoup import BeautifulStoneSoup
       
    25 import re
       
    26 from base64 import b64decode
    23 
    27 
    24 class CreateTextUploadForm(ModelForm):
    28 class CreateTextUploadForm(ModelForm):
    25     file = forms.FileField(required=False,
    29     file = forms.FileField(required=False,
    26                            label=ugettext_lazy("Upload file (optional)"),
    30                            label=ugettext_lazy("Upload file (optional)"),
    27                            help_text=ugettext_lazy("Upload a file from your computer instead of using the direct input above"),)
    31                            help_text=ugettext_lazy("Upload a file from your computer instead of using the direct input above"),)
    36         cleaned_data = self.cleaned_data
    40         cleaned_data = self.cleaned_data
    37         if not cleaned_data.get('file', None) :
    41         if not cleaned_data.get('file', None) :
    38             msg = _("You should specify a file to upload.")
    42             msg = _("You should specify a file to upload.")
    39             self._errors["file"] = ErrorList([msg])
    43             self._errors["file"] = ErrorList([msg])
    40               
    44               
       
    45         return cleaned_data
       
    46 
       
    47 class CreateTextImportForm(ModelForm):
       
    48     file = forms.FileField(required=True,
       
    49                            label=ugettext_lazy("Upload XML file"),
       
    50                            help_text=ugettext_lazy("Upload a previously exported XML file from your computer"),)
       
    51 
       
    52     class Meta:
       
    53         model = TextVersion
       
    54         fields = ()
       
    55 
       
    56     def clean(self):
       
    57         cleaned_data = self.cleaned_data
       
    58         if not cleaned_data.get('file', None) :
       
    59           msg = _("You should specify a file to upload.")
       
    60           self._errors["file"] = ErrorList([msg])
       
    61           return cleaned_data
       
    62 
       
    63         uploaded_file = self.cleaned_data['file']
       
    64         if (uploaded_file.content_type != 'text/xml'):
       
    65           msg = _("The imported file should be an XML file generated by co-ment when exporting a text and comments.")
       
    66           self._errors["file"] = ErrorList([msg])
       
    67           return cleaned_data
       
    68 
       
    69         soup = BeautifulStoneSoup(uploaded_file)
       
    70         if not soup.co_ment_text:
       
    71           msg = _("No co_ment_text node found in XML.")
       
    72           self._errors["file"] = ErrorList([msg])
       
    73           return cleaned_data
       
    74         for mandatory_child in ['title', 'created', 'modified', 'name', 'email', 'format', 'content']:
       
    75           if not getattr(soup.co_ment_text, mandatory_child):
       
    76             msg = _('No %(tag)s node found in XML.' %{"tag":mandatory_child})
       
    77             self._errors["file"] = ErrorList([msg])
       
    78             return cleaned_data
       
    79         cleaned_data['soup'] = soup
    41         return cleaned_data
    80         return cleaned_data
    42 
    81 
    43 class CreateTextContentForm(ModelForm):
    82 class CreateTextContentForm(ModelForm):
    44     title = forms.CharField(required=True,
    83     title = forms.CharField(required=True,
    45                             label=ugettext_lazy("Title"),
    84                             label=ugettext_lazy("Title"),
    57     
    96     
    58 def redirect_post_create(text) :
    97 def redirect_post_create(text) :
    59     return HttpResponseRedirect(reverse('text-view', args=[text.key]))
    98     return HttpResponseRedirect(reverse('text-view', args=[text.key]))
    60 
    99 
    61 def _text_create_content(request, createForm):
   100 def _text_create_content(request, createForm):
    62 #    CreateForm = CreateTextContentForm
       
    63     document = ""
   101     document = ""
    64         
   102         
    65     if request.method == 'POST':
   103     if request.method == 'POST':
    66         form = createForm(request.POST)
   104         form = createForm(request.POST)
    67         if form.is_valid():
   105         if form.is_valid():
    75         
   113         
    76     return None, render_to_response('site/text_create_content.html', {'document':document, 'form' : form}, context_instance=RequestContext(request))
   114     return None, render_to_response('site/text_create_content.html', {'document':document, 'form' : form}, context_instance=RequestContext(request))
    77 
   115 
    78 def _text_create_upload(request, createForm):
   116 def _text_create_upload(request, createForm):
    79     
   117     
    80 #    CreateForm = CreateTextUploadForm if request.user.is_authenticated() else CreateTextUploadFormAnon
       
    81 
       
    82     if request.method == 'POST':
   118     if request.method == 'POST':
    83         form = createForm(request.POST, request.FILES)
   119         form = createForm(request.POST, request.FILES)
    84         if form.is_valid():
   120         if form.is_valid():
    85             # should convert?
   121             # should convert?
    86             if form.cleaned_data['file']:
   122             if form.cleaned_data['file']:
   111     else:
   147     else:
   112         form = createForm()
   148         form = createForm()
   113         
   149         
   114     return None, render_to_response('site/text_create_upload.html', {'form' : form}, context_instance=RequestContext(request))
   150     return None, render_to_response('site/text_create_upload.html', {'form' : form}, context_instance=RequestContext(request))
   115 
   151 
       
   152 def _text_create_import(request, createForm):
       
   153   if request.method == 'POST':
       
   154     form = createForm(request.POST, request.FILES)
       
   155     if form.is_valid():
       
   156       soup = form.cleaned_data['soup']
       
   157       if not soup.co_ment_text:
       
   158         raise Exception('Bad Soup')
       
   159 
       
   160       # Process attachments first to create new keys.
       
   161       attachments_keys_map = {}
       
   162       if soup.co_ment_text.attachments:
       
   163         for imported_attachement in soup.co_ment_text.attachments.findAll('attachment'):
       
   164           # Creates attachment object.
       
   165           filename = 'imported_attachment'
       
   166           attachment = Attachment.objects.create_attachment(filename=filename, data=b64decode(imported_attachement.data.renderContents()), text_version=None)
       
   167           # Stores key mapping.
       
   168           attachments_keys_map[imported_attachement.key.renderContents()] = attachment.key
       
   169 
       
   170       # Process text.
       
   171       form.cleaned_data['title'] = soup.co_ment_text.title.renderContents()
       
   172       form.cleaned_data['format'] = soup.co_ment_text.format.renderContents()
       
   173       form.cleaned_data['content'] = re.sub(r'^<!\[CDATA\[|\]\]>$', '', soup.co_ment_text.content.renderContents())
       
   174       form.cleaned_data['name'] = soup.co_ment_text.find('name').renderContents()
       
   175       form.cleaned_data['email'] = soup.co_ment_text.email.renderContents()
       
   176       if soup.co_ment_text.tags:
       
   177         form.cleaned_data['tags'] = soup.co_ment_text.tags.renderContents()
       
   178 
       
   179       # Replaces attachements keys in content.
       
   180       for old_key in attachments_keys_map.keys():
       
   181         form.cleaned_data['content'] = re.sub(old_key, attachments_keys_map[old_key], form.cleaned_data['content'])
       
   182 
       
   183       # Creates text.
       
   184       text = create_text(request.user, form.cleaned_data)
       
   185 
       
   186       # Brute updates of dates (cannot do it through django models since fields are set with auto_now or auto_now_add).
       
   187       created = soup.co_ment_text.created.renderContents()
       
   188       modified = soup.co_ment_text.modified.renderContents()
       
   189       cursor = connection.cursor()
       
   190       cursor.execute("UPDATE cm_textversion SET created = %s, modified = %s WHERE id = %s", [created, modified, text.last_text_version_id])
       
   191       cursor.execute("UPDATE cm_text SET created = %s, modified = %s WHERE id = %s", [created, modified, text.id])
       
   192       transaction.commit_unless_managed()
       
   193 
       
   194       # Process comments.
       
   195       if soup.co_ment_text.comments:
       
   196         comments_ids_map = {}
       
   197         for imported_comment in soup.co_ment_text.comments.findAll('comment'):
       
   198           # Creates each comment.
       
   199           comment = Comment.objects.create(
       
   200               text_version=text.get_latest_version(),
       
   201               title=imported_comment.title.renderContents(),
       
   202               state=imported_comment.state.renderContents(),
       
   203               name=imported_comment.find('name').renderContents(),
       
   204               email=imported_comment.email.renderContents(),
       
   205               format=imported_comment.format.renderContents(),
       
   206               content=re.sub(r'^<!\[CDATA\[|\]\]>$', '', imported_comment.content.renderContents()),
       
   207               content_html=re.sub(r'^<!\[CDATA\[|\]\]>$', '', imported_comment.content_html.renderContents()),
       
   208               )
       
   209 
       
   210           # Stores id for reply_to mapping.
       
   211           comments_ids_map[imported_comment.id.renderContents()] = comment
       
   212 
       
   213           # Process boolean and potentially null integer/foreign key attributes.
       
   214           save = False
       
   215           if imported_comment.deleted.renderContents() == 'True':
       
   216             comment.deleted = True
       
   217             save = True
       
   218           if imported_comment.start_wrapper.renderContents() != 'None':
       
   219             comment.start_wrapper = imported_comment.start_wrapper.renderContents()
       
   220             save = True
       
   221           if imported_comment.end_wrapper.renderContents() != 'None':
       
   222             comment.end_wrapper = imported_comment.end_wrapper.renderContents()
       
   223             save = True
       
   224           if imported_comment.start_offset.renderContents() != 'None':
       
   225             comment.start_offset = imported_comment.start_offset.renderContents()
       
   226             save = True
       
   227           if imported_comment.end_offset.renderContents() != 'None':
       
   228             comment.end_offset = imported_comment.end_offset.renderContents()
       
   229             save = True
       
   230           if imported_comment.find('parent'):
       
   231             comment.reply_to = comments_ids_map.get(imported_comment.find('parent').renderContents())
       
   232             save = True
       
   233           if save:
       
   234             comment.save()
       
   235 
       
   236           # Brute updates of dates (cannot do it through django models since fields are set with auto_now or auto_now_add).
       
   237           created=imported_comment.created.renderContents(),
       
   238           modified=imported_comment.modified.renderContents(),
       
   239           cursor.execute("UPDATE cm_comment SET created = %s, modified = %s WHERE id = %s", [created, modified, comment.id])
       
   240           transaction.commit_unless_managed()
       
   241 
       
   242       # Logs on activity.
       
   243       register_activity(request, "text_imported", text)
       
   244       display_message(request, _(u'Text "%(text_title)s" has been imported')%{"text_title":text.get_latest_version().title})
       
   245       return None, HttpResponseRedirect(reverse('text-view', args=[text.key]))
       
   246   else:
       
   247     form = createForm()
       
   248 
       
   249   return None, render_to_response('site/text_create_import.html', {'form' : form}, context_instance=RequestContext(request))
       
   250 
       
   251 
   116 @has_global_perm('can_create_text')
   252 @has_global_perm('can_create_text')
   117 def text_create_upload(request):
   253 def text_create_upload(request):
   118     text, rep = _text_create_upload(request, CreateTextUploadForm)
   254     text, rep = _text_create_upload(request, CreateTextUploadForm)
       
   255     return rep
       
   256 
       
   257 def text_create_import(request):
       
   258     text, rep = _text_create_import(request, CreateTextImportForm)
   119     return rep
   259     return rep
   120 
   260 
   121 def create_text(user, data):
   261 def create_text(user, data):
   122     text = Text.objects.create_text(title=data['title'],
   262     text = Text.objects.create_text(title=data['title'],
   123                                     format=data['format'],
   263                                     format=data['format'],