Attachment 'GuestPass-1.0.py'

Download

   1 # -*- coding: iso-8859-1 -*-
   2 """
   3     MoinMoin - GuestPass action Version 1.0, 6.01.2013 
   4 
   5     @copyright: 2013 Ian Riley <ian.riley@internode.on.net>
   6     
   7     incorporting code from:
   8     
   9     @copyright: 2001 by Ken Sugino (sugino@mediaone.net),
  10                 2001-2004 by Juergen Hermann <jh@web.de>,
  11                 2005 MoinMoin:AlexanderSchremmer,
  12                 2005 DiegoOngaro at ETSZONE (diego@etszone.com),
  13                 2005-2010 MoinMoin:ReimarBauer,
  14                 2007-2008 MoinMoin:ThomasWaldmann
  15 
  16     @license: GNU GPL, see COPYING for details.
  17 """
  18 
  19 import datetime, os, time
  20 from MoinMoin import wikiutil, user
  21 from MoinMoin.Page import Page
  22 
  23 action_name = __name__.split('.')[-1]
  24 actname = {'actname': action_name}
  25 action = action_name.upper()
  26 
  27 def doCancel(pagename, request, msg = '', msg_class=None):
  28     thispage = Page(request, pagename)
  29     request.theme.add_msg(msg, msg_class)
  30     thispage.send_page()
  31     return 
  32 
  33 def createPass(pagename, request, passlog):
  34     _ = request.getText
  35     thispage = Page(request, pagename)
  36     user = request.user
  37 
  38     try: 
  39         all_may_read = thispage.getACL(request).may(request,'All','read')
  40     except:
  41         all_may_read = True # Fail safe position. Not sure if needed.
  42 
  43     if user.valid and user.may.write(pagename) and not all_may_read:
  44         pass_time_usecs = wikiutil.timestamp2version(time.time())
  45         username = user.name
  46         guestpass = passlog.add(request, pass_time_usecs, action, 
  47                                 pagename, username)
  48         msg = _('%(link)s guest pass created with expiry in %(expiry)s.') % {
  49             'link'  : guestpass.link_to(request),
  50             'expiry': guestpass.expiry_days()}
  51         request.theme.add_msg(msg, 'dialog')
  52     elif all_may_read:
  53         msg = _('A guest pass cannot be created for a public page.')
  54         request.theme.add_msg(msg, 'info')
  55     else:
  56         msg = _('You are not allowed to create a guest pass on this page.')
  57         request.theme.add_msg(msg, 'error')
  58     thispage.send_page()
  59     return 
  60 
  61 def retirePass(pagename, request, passlog, passcodes):
  62     _ = request.getText
  63     thispage = Page(request, pagename)
  64     user = request.user
  65 
  66     cnurret = False
  67     created = False
  68     retired = 0
  69     msg =''
  70     
  71     if not type(passcodes) is list:
  72         passcodes = [passcode]
  73     
  74     passlogPath = request.rootpage.getPagePath('pass-log', isfile=1)
  75 
  76     for passcode in passcodes:
  77         guestpass = getPass(pagename, request, passlog, passcode)
  78         #shouldn't need to check guestpass as it comes from HTML form 
  79         current = guestpass.is_current()
  80         created = user.id == guestpass.userid
  81 
  82         if current and created:     
  83             pass_time_usecs = wikiutil.timestamp2version(time.time())
  84             username = user.name
  85             passlog.add(request, pass_time_usecs, action, pagename, username,
  86                         passcode=passcode, lifespan=0)
  87             retired += 1            
  88         else:
  89             if not current and not created:
  90                 msg = _('Guest pass invalid.')
  91             if not current and created:
  92                 msg = _('Guest pass expired or already retired.')
  93             if current and not created:
  94                 msg = _('You are not allowed to retire a guest pass on this page.')
  95             request.theme.add_msg(msg, 'error')
  96             thispage.send_page()
  97             return
  98     if retired == 0:
  99         msg = _('No guest pass could be retired.')
 100     elif retired == 1:
 101         msg = _('Guest pass retired.')
 102     elif retired > 1:
 103         msg = _('Guest passes retired.')
 104     request.theme.add_msg(msg, 'info')
 105     thispage.send_page()    
 106     return
 107 
 108 def getPass(pagename, request, passlog, passcode):
 109     passlogPath = request.rootpage.getPagePath('pass-log', isfile=1)
 110     guestpass = False
 111     if passcode and os.path.exists(passlogPath):
 112         passlog.set_filter(pagename=pagename, passcode=passcode)
 113         for guestpass in passlog.reverse():
 114             return guestpass # latest record only
 115 
 116 def doPass(pagename, request, passlog, passcode):
 117     _ = request.getText
 118     from MoinMoin.widget.dialog import Dialog
 119     thispage = Page(request, pagename)
 120     
 121     if request.user.may.read(pagename): # ignore guestpass action
 122         thispage.send_page()
 123         return
 124 
 125     guestpass = getPass(pagename, request, passlog, passcode)
 126                
 127     if guestpass and guestpass.is_read_allowed(request):
 128         msg = _('%(link)s viewed with guest pass expiring in %(expiry)s.') % {
 129             'link'  : guestpass.link_to(request),
 130             'expiry': guestpass.expiry_days()}
 131         request.theme.add_msg(Dialog(request, content=msg), 'dialog')
 132         send_special = True
 133     else:
 134         msg = _('Invalid or expired guest pass.')
 135         request.theme.add_msg(msg, 'error')
 136         send_special = False
 137     thispage.send_page(send_special=send_special)
 138     return
 139     
 140 def _send_viewFile(pagename, request, fpath, filename, passcode):
 141     """Modified AttachFile.send_viewfile()
 142 
 143     To send views of files attached to a guest pass accessed page.
 144     
 145     Modified not to perform user and file checking. This is done by the caller.
 146         
 147     """
 148     import zipfile
 149     from MoinMoin import config, packages
 150     from MoinMoin.action.AttachFile import getAttachUrl
 151     _ = request.getText
 152     fmt = request.html_formatter
 153 
 154     querystr={'action': action_name, 'pass': passcode, 'show': filename, 'do': 'get' }
 155     download_link = Page(request, pagename).link_to(request, querystr=querystr,
 156         css_class='download', text=_('Download'))
 157 
 158     request.write('<h2>' + _("Attachment '%(filename)s'") % {'filename': filename} + '</h2>')
 159     request.write('%s<br><br>' % download_link)
 160 
 161     if filename.endswith('.tdraw') or filename.endswith('.adraw'):
 162         request.write(fmt.attachment_drawing(filename, ''))
 163         return
 164 
 165     mt = wikiutil.MimeType(filename=filename)
 166 
 167     # destinguishs if browser need a plugin in place
 168     if mt.major == 'image' and mt.minor in config.browser_supported_images:
 169         url = Page(request, pagename).url(request, querystr=querystr)
 170         request.write('<img src="%s" alt="%s">' % (
 171             url,
 172             #wikiutil.escape(url, 1),
 173             wikiutil.escape(filename, 1)))
 174         return
 175     elif mt.major == 'text':
 176         ext = os.path.splitext(filename)[1]
 177         Parser = wikiutil.getParserForExtension(request.cfg, ext)
 178         if Parser is not None:
 179             try:
 180                 content = file(fpath, 'r').read()
 181                 content = wikiutil.decodeUnknownInput(content)
 182                 colorizer = Parser(content, request, filename=filename)
 183                 colorizer.format(request.formatter)
 184                 return
 185             except IOError:
 186                 pass
 187 
 188         request.write(request.formatter.preformatted(1))
 189         # text but no colorizing parser try to decode file contents
 190         content = open(fpath, 'r').read()
 191         content = wikiutil.decodeUnknownInput(content)
 192         content = wikiutil.escape(content)
 193         request.write(request.formatter.text(content))
 194         request.write(request.formatter.preformatted(0))
 195         return
 196 
 197     try:
 198         package = packages.ZipPackage(request, fpath)
 199         if package.isPackage():
 200             request.write("<pre><b>%s</b>\n%s</pre>" % (_("Package script:"), 
 201                 wikiutil.escape(package.getScript())))
 202             return
 203 
 204         if zipfile.is_zipfile(fpath) and mt.minor == 'zip':
 205             zf = zipfile.ZipFile(fpath, mode='r')
 206             request.write("<pre>%-46s %19s %12s\n" % (_("File Name"),
 207                                                       _("Modified")+" "*5,
 208                                                       _("Size")))
 209             for zinfo in zf.filelist:
 210                 date = "%d-%02d-%02d %02d:%02d:%02d" % zinfo.date_time
 211                 request.write(wikiutil.escape("%-46s %s %12d\n" % (
 212                                         zinfo.filename, date, zinfo.file_size)))
 213             request.write("</pre>")
 214             return
 215     except RuntimeError:
 216         logging.exception("An exception within zip file attachment handling occurred:")
 217         return
 218         
 219     #not what we are prepared to show, so just force the do=get.
 220     _get_File(pagename, request, fpath, filename, passcode)
 221     
 222     return
 223 
 224 def _view_File(pagename, request, fpath, filename, passcode):
 225     """Modified AttachFile._do_view()
 226 
 227     To view files attached to a guest pass accessed page.
 228     
 229     Modified not to perform user and file checking. This is done by the caller.
 230         
 231     """
 232     _ = request.getText
 233     request.formatter.page = Page(request, pagename)
 234 
 235     request.setContentLanguage(request.lang)
 236     title = _('attachment:%(filename)s of %(pagename)s') % {
 237         'filename': filename, 'pagename': pagename}
 238     request.theme.send_title(title, pagename=pagename)
 239     request.write(request.formatter.startContent())
 240     _send_viewFile(pagename, request, fpath, filename, passcode)
 241     request.write(request.formatter.endContent())
 242     request.theme.send_footer(pagename)
 243     request.theme.send_closing_html()
 244     
 245 def _get_File(pagename, request, fpath, filename, passcode):
 246     """Modified AttachFile._do_get()
 247 
 248     To get files attached to a guest pass accessed page.
 249     
 250     Modified not to perform user and file checking. This is done by the caller.
 251         
 252     """
 253     from werkzeug import http_date
 254     from MoinMoin import config
 255 
 256     timestamp = datetime.datetime.fromtimestamp(os.path.getmtime(fpath))
 257     if_modified = request.if_modified_since
 258     if if_modified and if_modified >= timestamp:
 259         request.status_code = 304
 260     else:
 261         mt = wikiutil.MimeType(filename=filename)
 262         content_type = mt.content_type()
 263         mime_type = mt.mime_type()
 264         filename_enc = filename.encode(config.charset)
 265         dangerous = mime_type in request.cfg.mimetypes_xss_protect
 266         content_dispo = dangerous and 'attachment' or 'inline'
 267 
 268         now = time.time()
 269         request.headers['Date'] = http_date(now)
 270         request.headers['Content-Type'] = content_type
 271         request.headers['Last-Modified'] = http_date(timestamp)
 272         request.headers['Expires'] = http_date(now - 365 * 24 * 3600)
 273         request.headers['Content-Length'] = os.path.getsize(fpath)
 274         content_dispo_string = '%s; filename="%s"' % (content_dispo, filename_enc)
 275         request.headers['Content-Disposition'] = content_dispo_string
 276         request.send_file(open(fpath, 'rb'))
 277 
 278 def showAttachment(pagename, request, passlog, passcode, filename):
 279     from MoinMoin.action.AttachFile import getFilename
 280     _ = request.getText
 281     thispage = Page(request, pagename)
 282 
 283     do = request.values.get('do', 'view')
 284     if do not in ['get', 'view', ]:
 285         do = 'view' # the soft option
 286         
 287     guestpass = getPass(pagename, request, passlog, passcode)
 288 
 289     if guestpass and guestpass.is_read_allowed(request):
 290         msg = ''
 291         if not filename:
 292             msg = _('Filename of attachment not specified.')
 293         else:
 294             filename = wikiutil.taintfilename(filename)
 295             fpath = getFilename(request, pagename, filename)
 296             if not os.path.isfile(fpath):
 297                 msg = _('Attachment "%(filename)s" does not exist.') % {
 298                     'filename': filename}
 299         if msg:
 300             request.theme.add_msg(msg, 'error')
 301             thispage.send_page(send_special=True)
 302         else:
 303             if do == 'get':
 304                 _get_File(pagename, request, fpath, filename, passcode)
 305             else:
 306                 _view_File(pagename, request, fpath, filename, passcode)
 307     else:
 308         msg = _('Invalid or expired guest pass.')
 309         request.theme.add_msg(msg, 'error')
 310         success = False
 311         thispage.send_page()
 312         return
 313     
 314 def offerPass(pagename, request, passlog):
 315     from MoinMoin.widget.dialog import Dialog
 316     _ = request.getText
 317     thispage = Page(request, pagename)
 318     user = request.user
 319     try: 
 320         all_may_read = thispage.getACL(request).may(request,'All','read')
 321     except:
 322         all_may_read = True # Fail safe position. Not sure if needed.
 323 
 324     if user.valid and user.may.write(pagename) and not all_may_read:
 325         # get all current guest passes for this page and user
 326         passlogPath = request.rootpage.getPagePath('pass-log', isfile=1)
 327         html_passes = []
 328         expired = []
 329         passlog.set_filter(pagename=pagename, userid=user.id)
 330         for guestpass in passlog.reverse():
 331             if guestpass.is_current() and not guestpass.passcode in expired:
 332                 html_passes.append(
 333                     ('<option value="%(passcode)s">' + 
 334                      'Created %(dated)s expiring %(expiry)s' +
 335                      '</option>') % {'passcode': guestpass.passcode,
 336                                      'dated'   : guestpass.dated(user),
 337                                      'expiry'  : guestpass.expiry_days()})
 338             else:
 339                 expired.append(guestpass.passcode)
 340         n = min([3, len(html_passes)])
 341         d = {'url': request.href(pagename),
 342              'create_title' : _('Create guest pass'),
 343              'create_action': action_name, # &create=1
 344              'create_button': _('Create'),
 345              'retire_title' : _('Retire guest passes'),
 346              'retire_action': action_name, # &create=-1&pass=passcodes
 347              'retire_button': _('Retire'),
 348              'cancel_button': _('Cancel'),
 349              'pagename'     : pagename,
 350              'ticket'       : wikiutil.createTicket(request),
 351              'option_passes': ' '.join(html_passes),
 352              'len'          : n, }
 353         # include create form always 
 354         formhtml = ''' 
 355 <form method="POST" action="%(url)s">
 356 <strong>%(create_title)s</strong><br><br>
 357 <input type="hidden" name="action" value="%(create_action)s">
 358 <input type="hidden" name="create" value="1">
 359 <input type="hidden" name="ticket" value="%(ticket)s">
 360 <input type="submit" name="create" value="%(create_button)s">
 361 <input type="submit" name="cancel" value="%(cancel_button)s"><br><br>
 362 </form>''' % d
 363         if html_passes: 
 364             # only include retire form if some existing passes
 365             formhtml += '''
 366 <form method="POST" action="%(url)s">
 367 <strong>%(retire_title)s</strong><br><br>
 368 <input type="hidden" name="action" value="%(retire_action)s">
 369 <input type="hidden" name="create" value="-1">
 370 <input type="hidden" name="ticket" value="%(ticket)s">
 371 Your currently valid guest passes for %(pagename)s<br>
 372 <select name="pass" size="%(len)s" multiple>
 373 %(option_passes)s
 374 </select><br><br>
 375 Select guest pass then retire, if no longer needed.<br><br>
 376 <input type="submit" name="retire" value="%(retire_button)s">
 377 <input type="submit" name="cancel" value="%(cancel_button)s"><br><br>
 378 </form>''' % d
 379         request.theme.add_msg(Dialog(request, content=formhtml), 'dialog')
 380     elif all_may_read:
 381         msg = _('A guest pass cannot be created for a public page.')
 382         request.theme.add_msg(msg, 'info')
 383     else:
 384         msg = _('You are not allowed to create a guest pass on this page.')
 385         request.theme.add_msg(msg, 'error')
 386     thispage.send_page()
 387     return
 388 
 389 def execute(pagename, request):
 390     _ = request.getText
 391     passlogPath = request.rootpage.getPagePath('pass-log', isfile=1)
 392     PassLog = wikiutil.importWikiPlugin(request.cfg, 'logfile', 'passlog', 'PassLog')
 393     passlog = PassLog(request, filename=passlogPath, uid_override=None)
 394     
 395     post = request.method == 'POST'
 396     ticket = request.values.get('ticket', False)
 397     ticket_ok = ticket and (not(ticket) or wikiutil.checkTicket(request, ticket))
 398     passcode = request.values.get('pass', '')
 399     passcodes = request.values.getlist('pass')
 400     create = int(request.values.get('create', False))
 401     show = request.values.get('show', False)
 402     cancel = request.values.get('cancel', False)
 403     
 404     c = [post, bool(ticket), ticket_ok, bool(passcodes),
 405          create, bool(show), bool(cancel), ]
 406     if   c == [0, 0, 0, 0, 0, 0, 0, ]:
 407         offerPass(pagename, request, passlog)
 408     elif c == [0, 0, 0, 1, 0, 0, 0, ]:
 409         doPass(pagename, request, passlog, passcode)
 410     elif c == [0, 0, 0, 1, 0, 1, 0, ]:
 411         showAttachment(pagename, request, passlog, passcode, show)
 412     elif c == [1, 1, 1, 0, 1, 0, 0, ]:
 413         createPass(pagename, request, passlog)
 414     elif c == [1, 1, 1, 1,-1, 0, 0, ]:
 415         retirePass(pagename, request, passlog, passcodes)
 416     elif c == [0, 0, 0, 0, 0, 1, 0, ]:
 417         showAttachment(pagename, request, passlog, passcode, show)
 418     elif c[0:2] == [1, 1, 0, ]:
 419         msg = _('Use %(actname)s action only interactive interface') % actname
 420         doCancel(pagename, request, msg, 'error')    
 421     elif c[6]:
 422         msg = _('%(actname)s action cancelled.') % actname
 423         doCancel(pagename, request, msg, 'info')
 424     else:
 425         msg = _('%(actname)s values invalid, action cancelled') % actname
 426         doCancel(pagename, request, msg, 'error')

You are not allowed to attach a file to this page.