Browse Source

Several minor improvements to CSV importing and exporting.

Dan Helfman 9 years ago
parent
commit
e6fbbfec41

+ 1
- 0
NEWS View File

@@ -2,6 +2,7 @@
2 2
  * When you export your notebook as an HTML or CSV file, the saved filename is
3 3
    now based on the name of your notebook, for instance "my-to-do-list.html"
4 4
    or "ideas-for-my-novel.csv".
5
+ * Several minor improvements to CSV importing and exporting.
5 6
  * Converted the existing HTML and CSV export features to work as separate
6 7
    export plugins. This means that a new export format can be implemented as
7 8
    a new plugin.

+ 14
- 2
plugins/export_csv/__init__.py View File

@@ -1,18 +1,30 @@
1
+import re
1 2
 import csv
2 3
 from cStringIO import StringIO
3 4
 from model.User import User
4 5
 
5 6
 
7
+FILE_LINK_PATTERN = re.compile( u'<a\s+href="[^"]*\/files\/download\?file_id=[^"]+"[^>]*>', re.IGNORECASE )
8
+IMAGE_PATTERN = re.compile( u'<img [^>]* ?/?>', re.IGNORECASE )
9
+NEWLINE_PATTERN = re.compile( u'[\r\n]+' )
10
+
11
+
6 12
 def export( database, notebook, notes, response_headers ):
7 13
   """
8 14
   Format the given notes as a CSV file and return it as a streaming generator.
9 15
   """
10 16
   buffer = StringIO()
11
-  writer = csv.writer( buffer )
17
+  writer = csv.writer( buffer, quoting = csv.QUOTE_NONNUMERIC )
12 18
 
13 19
   response_headers[ u"Content-Disposition" ] = u"attachment; filename=%s.csv" % notebook.friendly_id
14 20
   response_headers[ u"Content-Type" ] = u"text/csv;charset=utf-8"
15 21
 
22
+  def prepare_contents( contents ):
23
+    contents = FILE_LINK_PATTERN.sub( '<a>', contents )
24
+    contents = IMAGE_PATTERN.sub( '', contents )
25
+    contents = NEWLINE_PATTERN.sub( ' ', contents )
26
+    return contents.strip()
27
+
16 28
   def stream():
17 29
     writer.writerow( ( u"contents", u"title", u"note_id", u"startup", u"username", u"revision_date" ) )
18 30
     yield buffer.getvalue()
@@ -24,7 +36,7 @@ def export( database, notebook, notes, response_headers ):
24 36
         user = database.load( User, note.user_id )
25 37
 
26 38
       writer.writerow( (
27
-        note.contents and note.contents.strip().encode( "utf8" ) or None,
39
+        note.contents and prepare_contents( note.contents ).encode( "utf8" ) or None,
28 40
         note.title and note.title.strip().encode( "utf8" ) or None,
29 41
         note.object_id,
30 42
         note.startup and 1 or 0,

+ 17
- 2
plugins/export_csv/test/Test_export_csv.py View File

@@ -41,7 +41,7 @@ class Test_export_csv( object ):
41 41
     self.note2 = Note.create( note_id, u"<h3>other title</h3>whee", notebook_id = self.notebook.object_id, user_id = self.user.object_id )
42 42
     self.database.save( self.note2, commit = False )
43 43
 
44
-  def test_export_csv( self, note_contents = None ):
44
+  def test_export_csv( self, note_contents = None, expected_contents = None ):
45 45
     if not note_contents:
46 46
       note_contents = u"<h3>blah</h3>foo"
47 47
 
@@ -87,7 +87,10 @@ class Test_export_csv( object ):
87 87
       expected_note = expected_notes[ note_count ]
88 88
 
89 89
       assert expected_note
90
-      assert contents.decode( "utf8" ) == expected_note.contents.strip()
90
+      if expected_contents and note_id == note3.object_id:
91
+        assert contents.decode( "utf8" ) == expected_contents.replace( "\n", " " ).strip()
92
+      else:
93
+        assert contents.decode( "utf8" ) == expected_note.contents.replace( "\n", " " ).strip()
91 94
 
92 95
       if expected_note.title:
93 96
         assert title.decode( "utf8" ) == expected_note.title.strip()
@@ -115,6 +118,18 @@ class Test_export_csv( object ):
115 118
   def test_export_csv_with_trailing_newline_in_contents( self ):
116 119
     self.test_export_csv( note_contents = u"<h3>blah</h3>foo\n" )
117 120
 
121
+  def test_export_csv_with_file_attachment_in_contents( self ):
122
+    self.test_export_csv(
123
+      note_contents = u"<h3>blah</h3>foo<a href=\"/files/download?file_id=blah&quote_filename=False\">file</a>",
124
+      expected_contents = "<h3>blah</h3>foo<a>file</a>",
125
+    )
126
+
127
+  def test_export_csv_with_image_in_contents( self ):
128
+    self.test_export_csv(
129
+      note_contents = u"<h3>blah</h3>foo<a href=\"/files/download?file_id=blah&quote_filename=False\"><img src=\"whee.png\" /></a>",
130
+      expected_contents = "<h3>blah</h3>foo<a></a>",
131
+    )
132
+
118 133
   def test_export_csv_with_blank_username( self ):
119 134
     self.user._User__username = None
120 135
     self.database.save( self.user )

+ 2
- 0
plugins/export_html/Html_file.py View File

@@ -5,6 +5,7 @@ from view.Tags import Html, Head, Title, Style, Meta, Body, H1, Div, Span, Hr, A
5 5
 
6 6
 class Html_file( Html ):
7 7
   NOTE_LINK_PATTERN = re.compile( u'<a\s+href="[^"]*(?:\/notebooks\/)?[^>]+[?&]note_id=([a-z0-9]*)"[^>]*>', re.IGNORECASE )
8
+  FILE_LINK_PATTERN = re.compile( u'<a\s+href="[^"]*\/files\/download\?file_id=[^"]+"[^>]*>', re.IGNORECASE )
8 9
   IMAGE_PATTERN = re.compile( u'<img [^>]* ?/?>', re.IGNORECASE )
9 10
 
10 11
   def __init__( self, notebook, notes ):
@@ -14,6 +15,7 @@ class Html_file( Html ):
14 15
     # images since they're not presently included with the download
15 16
     for note in notes:
16 17
       contents = self.NOTE_LINK_PATTERN.sub( r'<a href="#note_\1">', note.contents )
18
+      contents = self.FILE_LINK_PATTERN.sub( '<a>', contents )
17 19
       contents = self.IMAGE_PATTERN.sub( '', contents )
18 20
       relinked_notes[ note.object_id ] = contents
19 21
 

Loading…
Cancel
Save