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