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.