--- a/src/cm/views/create.py Thu Aug 09 16:55:25 2012 +0200
+++ b/src/cm/views/create.py Fri Aug 10 16:12:29 2012 +0200
@@ -1,7 +1,7 @@
from cm.cm_settings import VALID_EMAIL_FOR_PUBLISH, SITE_NAME
from cm.converters import convert_from_mimetype
from cm.converters.pandoc_converters import pandoc_convert
-from cm.models import Text, TextVersion, Attachment
+from cm.models import Text, TextVersion, Comment, Attachment
from cm.utils.files import remove_extension
from cm.utils.mail import EmailMessage
from cm.views import get_text_by_keys_or_404
@@ -16,10 +16,14 @@
from django.template import RequestContext
from django.template.loader import render_to_string
from django.utils.translation import ugettext as _, ugettext_lazy
+from django.db import connection, transaction
from mimetypes import guess_type
from cm.activity import register_activity
from cm.security import has_global_perm
import os
+from BeautifulSoup import BeautifulStoneSoup
+import re
+from base64 import b64decode
class CreateTextUploadForm(ModelForm):
file = forms.FileField(required=False,
@@ -40,6 +44,41 @@
return cleaned_data
+class CreateTextImportForm(ModelForm):
+ file = forms.FileField(required=True,
+ label=ugettext_lazy("Upload XML file"),
+ help_text=ugettext_lazy("Upload a previously exported XML file from your computer"),)
+
+ class Meta:
+ model = TextVersion
+ fields = ()
+
+ def clean(self):
+ cleaned_data = self.cleaned_data
+ if not cleaned_data.get('file', None) :
+ msg = _("You should specify a file to upload.")
+ self._errors["file"] = ErrorList([msg])
+ return cleaned_data
+
+ uploaded_file = self.cleaned_data['file']
+ if (uploaded_file.content_type != 'text/xml'):
+ msg = _("The imported file should be an XML file generated by co-ment when exporting a text and comments.")
+ self._errors["file"] = ErrorList([msg])
+ return cleaned_data
+
+ soup = BeautifulStoneSoup(uploaded_file)
+ if not soup.co_ment_text:
+ msg = _("No co_ment_text node found in XML.")
+ self._errors["file"] = ErrorList([msg])
+ return cleaned_data
+ for mandatory_child in ['title', 'created', 'modified', 'name', 'email', 'format', 'content']:
+ if not getattr(soup.co_ment_text, mandatory_child):
+ msg = _('No %(tag)s node found in XML.' %{"tag":mandatory_child})
+ self._errors["file"] = ErrorList([msg])
+ return cleaned_data
+ cleaned_data['soup'] = soup
+ return cleaned_data
+
class CreateTextContentForm(ModelForm):
title = forms.CharField(required=True,
label=ugettext_lazy("Title"),
@@ -59,7 +98,6 @@
return HttpResponseRedirect(reverse('text-view', args=[text.key]))
def _text_create_content(request, createForm):
-# CreateForm = CreateTextContentForm
document = ""
if request.method == 'POST':
@@ -77,8 +115,6 @@
def _text_create_upload(request, createForm):
-# CreateForm = CreateTextUploadForm if request.user.is_authenticated() else CreateTextUploadFormAnon
-
if request.method == 'POST':
form = createForm(request.POST, request.FILES)
if form.is_valid():
@@ -113,11 +149,115 @@
return None, render_to_response('site/text_create_upload.html', {'form' : form}, context_instance=RequestContext(request))
+def _text_create_import(request, createForm):
+ if request.method == 'POST':
+ form = createForm(request.POST, request.FILES)
+ if form.is_valid():
+ soup = form.cleaned_data['soup']
+ if not soup.co_ment_text:
+ raise Exception('Bad Soup')
+
+ # Process attachments first to create new keys.
+ attachments_keys_map = {}
+ if soup.co_ment_text.attachments:
+ for imported_attachement in soup.co_ment_text.attachments.findAll('attachment'):
+ # Creates attachment object.
+ filename = 'imported_attachment'
+ attachment = Attachment.objects.create_attachment(filename=filename, data=b64decode(imported_attachement.data.renderContents()), text_version=None)
+ # Stores key mapping.
+ attachments_keys_map[imported_attachement.key.renderContents()] = attachment.key
+
+ # Process text.
+ form.cleaned_data['title'] = soup.co_ment_text.title.renderContents()
+ form.cleaned_data['format'] = soup.co_ment_text.format.renderContents()
+ form.cleaned_data['content'] = re.sub(r'^<!\[CDATA\[|\]\]>$', '', soup.co_ment_text.content.renderContents())
+ form.cleaned_data['name'] = soup.co_ment_text.find('name').renderContents()
+ form.cleaned_data['email'] = soup.co_ment_text.email.renderContents()
+ if soup.co_ment_text.tags:
+ form.cleaned_data['tags'] = soup.co_ment_text.tags.renderContents()
+
+ # Replaces attachements keys in content.
+ for old_key in attachments_keys_map.keys():
+ form.cleaned_data['content'] = re.sub(old_key, attachments_keys_map[old_key], form.cleaned_data['content'])
+
+ # Creates text.
+ text = create_text(request.user, form.cleaned_data)
+
+ # Brute updates of dates (cannot do it through django models since fields are set with auto_now or auto_now_add).
+ created = soup.co_ment_text.created.renderContents()
+ modified = soup.co_ment_text.modified.renderContents()
+ cursor = connection.cursor()
+ cursor.execute("UPDATE cm_textversion SET created = %s, modified = %s WHERE id = %s", [created, modified, text.last_text_version_id])
+ cursor.execute("UPDATE cm_text SET created = %s, modified = %s WHERE id = %s", [created, modified, text.id])
+ transaction.commit_unless_managed()
+
+ # Process comments.
+ if soup.co_ment_text.comments:
+ comments_ids_map = {}
+ for imported_comment in soup.co_ment_text.comments.findAll('comment'):
+ # Creates each comment.
+ comment = Comment.objects.create(
+ text_version=text.get_latest_version(),
+ title=imported_comment.title.renderContents(),
+ state=imported_comment.state.renderContents(),
+ name=imported_comment.find('name').renderContents(),
+ email=imported_comment.email.renderContents(),
+ format=imported_comment.format.renderContents(),
+ content=re.sub(r'^<!\[CDATA\[|\]\]>$', '', imported_comment.content.renderContents()),
+ content_html=re.sub(r'^<!\[CDATA\[|\]\]>$', '', imported_comment.content_html.renderContents()),
+ )
+
+ # Stores id for reply_to mapping.
+ comments_ids_map[imported_comment.id.renderContents()] = comment
+
+ # Process boolean and potentially null integer/foreign key attributes.
+ save = False
+ if imported_comment.deleted.renderContents() == 'True':
+ comment.deleted = True
+ save = True
+ if imported_comment.start_wrapper.renderContents() != 'None':
+ comment.start_wrapper = imported_comment.start_wrapper.renderContents()
+ save = True
+ if imported_comment.end_wrapper.renderContents() != 'None':
+ comment.end_wrapper = imported_comment.end_wrapper.renderContents()
+ save = True
+ if imported_comment.start_offset.renderContents() != 'None':
+ comment.start_offset = imported_comment.start_offset.renderContents()
+ save = True
+ if imported_comment.end_offset.renderContents() != 'None':
+ comment.end_offset = imported_comment.end_offset.renderContents()
+ save = True
+ if imported_comment.find('parent'):
+ comment.reply_to = comments_ids_map.get(imported_comment.find('parent').renderContents())
+ save = True
+ if save:
+ comment.save()
+
+ # Brute updates of dates (cannot do it through django models since fields are set with auto_now or auto_now_add).
+ created=imported_comment.created.renderContents(),
+ modified=imported_comment.modified.renderContents(),
+ cursor.execute("UPDATE cm_comment SET created = %s, modified = %s WHERE id = %s", [created, modified, comment.id])
+ transaction.commit_unless_managed()
+
+ # Logs on activity.
+ register_activity(request, "text_imported", text)
+ display_message(request, _(u'Text "%(text_title)s" has been imported')%{"text_title":text.get_latest_version().title})
+ return None, HttpResponseRedirect(reverse('text-view', args=[text.key]))
+ else:
+ form = createForm()
+
+ return None, render_to_response('site/text_create_import.html', {'form' : form}, context_instance=RequestContext(request))
+
+
@has_global_perm('can_create_text')
def text_create_upload(request):
text, rep = _text_create_upload(request, CreateTextUploadForm)
return rep
+def text_create_import(request):
+ text, rep = _text_create_import(request, CreateTextImportForm)
+ return rep
+
def create_text(user, data):
text = Text.objects.create_text(title=data['title'],
format=data['format'],
@@ -142,4 +282,4 @@
# save updated (attach links) text content
text_version.content = text_content
text_version.save()
- return text
\ No newline at end of file
+ return text