Attachment 'PDF-1.3.py'
Download 1 # -*- coding: iso-8859-1 -*-
2 """
3 MoinMoin - PageAsPDF action Version 1.3, 19.02.2013
4
5 @copyright: 2013 Ian Riley <ian.riley@internode.on.net>
6
7 History:
8
9 Version 1.3 - 19.02.2013: enabled call from guestpass action.
10
11 Version 1.2 - 12.02.2013: enabled pragma settings for options.
12
13 Version 1.1 - 12.02.2013: added option to show the subrocess call.
14
15 Version 1.0 - 06.02.2013: initial version.
16
17 incorporting code from:
18
19 @copyright: 2001 by Ken Sugino (sugino@mediaone.net),
20 2001-2004 by Juergen Hermann <jh@web.de>,
21 2005 MoinMoin:AlexanderSchremmer,
22 2005 DiegoOngaro at ETSZONE (diego@etszone.com),
23 2005-2007 MoinMoin:ReimarBauer,
24 2007-2008 MoinMoin:ThomasWaldmann
25
26 @license: GNU GPL, see COPYING for details.
27 """
28 import os, time, codecs, datetime
29 from subprocess import call
30 from werkzeug import http_date
31 from MoinMoin import config, wikiutil
32 from MoinMoin.Page import Page
33
34 action_name = __name__.split('.')[-1]
35 actname = {'actname': action_name}
36
37 class Options():
38 def __init__(self):
39 # Option Defaults: wiki and wkhtmltopdf Order
40 self.values = {'margin-top': ['20mm', '10mm', 1],
41 'margin-bottom': ['20mm', '10mm', 2],
42 'margin-left': ['10mm', '10mm', 3],
43 'margin-right': ['10mm', '10mm', 4],
44 'page-height': ['297mm', '297mm', 5],
45 'page-size': ['A4', 'A4', 6],
46 'page-width': ['210mm', '210mm', 7],
47 'title': ['[pagename]', '', 8],
48 'header-font-name': ['Arial', 'Arial', 9],
49 'header-font-size': ['9', '12', 10],
50 'header-spacing': ['10', '0', 11],
51 'header-line': [False, False, 12],
52 'header-left': ['[pagename]', '', 13],
53 'header-center': ['', '', 14],
54 'header-right': ['[date] [time]', '', 15],
55 'footer-font-name': ['Arial', 'Arial', 16],
56 'footer-font-size': ['9', '12', 17],
57 'footer-spacing': ['10', '', 18],
58 'footer-line': [False, False, 19],
59 'footer-left': ['[url]', '', 20],
60 'footer-center': ['', '', 21],
61 'footer-right': ['[page] of [topage]', '', 22],
62 }
63 def __repr__(self):
64 return str(self.formatted())
65
66 def update(self, new_opts = {}):
67 for k, v in new_opts.iteritems():
68 if k in self.values.keys():
69 if type(v) <> type(self.values[k][1]):
70 v = False
71 self.values[k][0] = v
72 return self.values
73
74 def replace(self, code, value):
75 code = '[%s]' % code
76 for k, v in self.values.iteritems():
77 if code in str(v[0]):
78 self.values[k][0] = v[0].replace(code, str(value))
79
80 def formatted(self):
81 values = sorted(self.values.iteritems(), key=lambda i: i[1][2])
82 couplets = [('--%s%s' % (k, [' %s' % v[0],''][type(v[0])==bool])).
83 split(' ', 1)
84 for k, v in values
85 if v[0] and (v[0] <> v[1])] #only if not app default
86 return [item for sublist in couplets for item in sublist] #flatten
87
88 def cookies(request):
89 triplets = [['--cookie', k, str(v)] for k, v in request.cookies.iteritems()]
90 return [item for sublist in triplets for item in sublist] #flatten
91
92 def page_options(request):
93 args = [str(args[4:]).split(' ',1)
94 for verb, args in request.page.meta
95 if verb == 'pragma' and args.startswith('pdf ')]
96 options = {}
97 for i, option in enumerate(args):
98 option[0] = option[0].replace('centre', 'center')
99 if len(option) == 1:
100 args[i].append(True)
101 options[option[0]] = option[1]
102 return options
103
104 def make_pdf(pagename, request, show='pdf', guestpass=False):
105
106 filename = '%s.pdf' % pagename.replace('/','-')
107 pdf_datetime = request.user.getFormattedDateTime(time.time())
108 pdf_date = request.user.getFormattedDate(time.time())
109 pdf_time = pdf_datetime.replace(pdf_date, '').strip()
110
111 options = Options()
112 options.update(page_options(request))
113
114 #prepare for subprocess call
115 #set app to local path for wkhtmltopdf
116 #TODO do this from wikiconfig
117 app = '/Applications/wkhtmltopdf.app/Contents/MacOS/wkhtmltopdf'
118 if not guestpass:
119 querystr={'action': 'print'}
120 else:
121 querystr={'action': 'GuestPass', 'pass': guestpass, 'print': '1'}
122 url = (request.url_root + request.page.url(request,
123 querystr=querystr, relative=True))
124 clean_url = (request.url_root + request.page.url(request, relative=True)).replace('%20',' ')
125 fpath = request.rootpage.getPagePath('wiki-page.pdf', isfile=1)
126
127 options.replace('pagename', pagename)
128 options.replace('url', clean_url)
129 # overide to give user not server date/time
130 options.replace('date', pdf_date)
131 options.replace('time', pdf_time)
132
133 params = ([app, '-q'] +
134 options.formatted() +
135 [url] +
136 cookies(request) +
137 [fpath])
138
139 #make and respond to subprocess call
140 if show == 'call' and request.user.may.admin(pagename):
141 for i, p in enumerate(params):
142 if ' ' in p:
143 params[i] = '"%s"' % p
144 request.theme.add_msg(' '.join(params), 'info')
145 elif show == 'pdf':
146 call_error = call(params)
147 if call_error and not guestpass: #TODO remove this second test once resolved
148 msg = '%(actname)s failed.' % actname
149 request.theme.add_msg(msg, 'error')
150 else:
151 filename_enc = filename.encode(config.charset)
152 timestamp = datetime.datetime.fromtimestamp(os.path.getmtime(fpath))
153 mt = wikiutil.MimeType(filename=filename)
154 content_type = mt.content_type()
155 mime_type = mt.mime_type()
156 now = time.time()
157 request.headers['Date'] = http_date(now)
158 request.headers['Content-Type'] = content_type
159 request.headers['Last-Modified'] = http_date(timestamp)
160 request.headers['Expires'] = http_date(now - 365 * 24 * 3600)
161 request.headers['Content-Length'] = os.path.getsize(fpath)
162 content_dispo_string = '%s; filename="%s"' % ('inline', filename_enc)
163 request.headers['Content-Disposition'] = content_dispo_string
164 # send data
165 request.send_file(open(fpath, 'rb'))
166 else:
167 msg = '%(actname)s show request invalid.' % actname
168 request.theme.add_msg(msg, 'error')
169 return
170
171 def execute(pagename, request):
172
173 if request.user.may.read(pagename):
174 show = request.values.get('show', 'pdf')
175 make_pdf(pagename, request, show)
176
177 Page(request, pagename).send_page()
You are not allowed to attach a file to this page.