Attachment 'DropBox-1.2.py'

Download

   1 # -*- coding: iso-8859-1 -*-
   2 """
   3     MoinMoin - DropBox action Version 1.2, 29.10.2014
   4     [a modification of AttachFile action]
   5 
   6     For documentation and examples see:
   7     
   8     http://rileylink.local/pb/MoinMoin_Matters
   9 
  10     History:
  11     
  12     Version 1.2 - 29.10.2014: fixed bug in del|get|view links
  13     
  14     Version 1.1 - 02.07.2014: added sort option; case sensitivity of option
  15                               values removed.
  16     Version 1.0 - 15.05.2011: initial version.
  17 
  18     @copyright: 2011, 2014 Ian Riley <ian@riley.asia>
  19     @license: GNU GPL, see COPYING for details.
  20 
  21     Based on AttachFile action
  22 
  23     @copyright: 2001 by Ken Sugino (sugino@mediaone.net),
  24                 2001-2004 by Juergen Hermann <jh@web.de>,
  25                 2005 MoinMoin:AlexanderSchremmer,
  26                 2005 DiegoOngaro at ETSZONE (diego@etszone.com),
  27                 2005-2007 MoinMoin:ReimarBauer,
  28                 2007-2008 MoinMoin:ThomasWaldmann
  29     @license: GNU GPL, see COPYING for details.
  30 """
  31 
  32 from operator import itemgetter
  33 from MoinMoin.action.AttachFile import *
  34 
  35 action_name = __name__.split('.')[-1]
  36 
  37 #############################################################################
  38 ### External interface - these are called from the core code
  39 #############################################################################
  40 
  41 def get_action(request, filename, do):
  42     generic_do_mapping = {
  43         # do -> action
  44         'get': action_name,
  45         'view': action_name,
  46         'del': action_name,
  47         'upload_form': action_name,
  48     }
  49     basename, ext = os.path.splitext(filename)
  50     do_mapping = request.cfg.extensions_mapping.get(ext, {})
  51     action = do_mapping.get(do, None)
  52     if action is None:
  53         # we have no special support for this,
  54         # look up whether we have generic support:
  55         action = generic_do_mapping.get(do, None)
  56     return action
  57 
  58 def getAttachUrl(pagename, filename, request, addts=0, do='get'):
  59     """ Get URL that points to attachment `filename` of page `pagename`.
  60         For upload url, call with do='upload_form'.
  61         Returns the URL to do the specified "do" action or None,
  62         if this action is not supported.
  63     """
  64     action = get_action(request, filename, do)
  65     if action:
  66         args = dict(action=action, do=do, target=filename)
  67         if do not in ['get', 'view', # harmless
  68                       'modify', # just renders the applet html, which has own ticket
  69                       'move', # renders rename form, which has own ticket
  70             ]:
  71             # create a ticket for the not so harmless operations
  72             # we need action= here because the current action (e.g. "show" page
  73             # with a macro AttachList) may not be the linked-to action, e.g.
  74             # "AttachFile". Also, AttachList can list attachments of another page,
  75             # thus we need to give pagename= also.
  76             args['ticket'] = wikiutil.createTicket(request,
  77                                                    pagename=pagename, action=action_name)
  78         url = request.href(pagename, **args)
  79         return url
  80 
  81 #############################################################################
  82 ### Internal helpers
  83 #############################################################################
  84 def _get_filesource(request, pagename, filename):
  85     """ Look up the user who attached the file
  86 
  87         Returns userid and username tuple.
  88     """
  89     from MoinMoin.logfile import editlog
  90     from MoinMoin import user
  91     
  92     log = editlog.EditLog(request, rootpagename=pagename)
  93     result = '', ''
  94     count = 0
  95     for line in log.reverse():
  96         count += 1
  97         if line.action in ('ATTNEW', 'ATTDEL', ):
  98             foundname = wikiutil.url_unquote(line.extra)
  99             if foundname == filename:
 100                 # just the user's name
 101                 result = line.userid, user.User(request, line.userid, auth_method="editlog:53").name
 102 
 103                 # link to user's homepage or email depending on preferences
 104                 # this would be OK if users all had homepages.
 105                 #result = line.userid, line.getEditor(request)
 106 
 107                 # unknown user
 108                 if '' in result:
 109                   result = None,'unknown user'
 110                 break
 111     return result
 112 
 113 def _access_file(pagename, request):
 114     """ Check form parameter `target` and return a tuple of
 115         `(pagename, filename, filepath)` for an existing attachment.
 116 
 117         Return `(pagename, None, None)` if an error occurs.
 118     """
 119     _ = request.getText
 120 
 121     error = None
 122     if not request.values.get('target'):
 123         error = _("Filename of upload not specified!")
 124     else:
 125         filename = wikiutil.taintfilename(request.values['target'])
 126         fpath = getFilename(request, pagename, filename)
 127 
 128         if os.path.isfile(fpath):
 129             return (pagename, filename, fpath)
 130         error = _("Upload '%(filename)s' does not exist!") % {'filename': filename}
 131 
 132     error_msg(pagename, request, error)
 133     return (pagename, None, None)
 134 
 135 def _build_filelist(request, pagename, sumonly, readonly, mime_type='*',
 136                     owners='*', sort='*'):
 137     _ = request.getText
 138     fmt = request.html_formatter
 139 
 140     import urlparse
 141     qs = urlparse.parse_qs(request.environ.get('QUERY_STRING'))
 142     owners = owners.lower()
 143     sort = sort.lower() 
 144     if owners == '*':
 145         if 'owners' in qs:
 146             owners = qs['owners'][0]
 147         else:
 148             owners = 'all'
 149     if sort == '*':
 150         if 'sort' in qs:
 151             sort = qs['sort'][0]
 152     
 153     user_id = request.user.valid and request.user.id or ''
 154 
 155     # access directory
 156     attach_dir = getAttachDir(request, pagename)
 157     files = _get_files(request, pagename)
 158 
 159     if mime_type != '*':
 160         files = [fname for fname in files if mime_type == mimetypes.guess_type(fname)[0]]
 161 
 162     label_del = _("del")
 163     label_get = _("get")
 164     label_view = _("view")
 165 
 166     may_read = request.user.may.read(pagename)
 167     may_attach = request.user.may.attach(pagename)
 168     may_delete = request.user.may.delete(pagename)
 169     may_detach = request.user.may.detach(pagename)
 170 
 171     links = []
 172     html = []
 173 
 174     if files:
 175         flist = []
 176         index = -1
 177         space = 0
 178         latest_time = None
 179         latest_file = 0
 180         count = 0
 181 
 182         for file in files:
 183             owner = _get_filesource(request, pagename, file)
 184             usersfile = owner[0] == user_id
 185             ownercheck = (usersfile and (owners in ["self", "all"])) or \
 186                          ((not usersfile) and (owners in ["other", "all"]))
 187             if not ownercheck:
 188                 continue
 189             index += 1
 190             mt = wikiutil.MimeType(filename=file)
 191             fullpath = os.path.join(attach_dir, file).encode(config.charset)
 192             st = os.stat(fullpath)
 193             if st.st_mtime > latest_time:
 194                 latest_time = st.st_mtime
 195                 latest_file = index             
 196             fdict= {'i': index,
 197                     'file': wikiutil.escape(file),
 198                     'owner_id': owner[0],
 199                     'ownername': owner[1],
 200                     'usersfile': usersfile,
 201                     'ownercheck': ownercheck,
 202                     'fullpath': fullpath,
 203                     'viewlink': (fmt.url(1, getAttachUrl(pagename, file, request, do='view')) +
 204                                  fmt.text(wikiutil.escape(file)) +
 205                                  fmt.url(0)),
 206                     'base': os.path.splitext(file)[0],
 207                     'ext':  os.path.splitext(file)[1],
 208                     'fsize': float(st.st_size) / 1024,
 209                     'fmtime': request.user.getFormattedDateTime(st.st_mtime),
 210                     'latest': False,
 211                     'deletable': (may_delete or 
 212                                  (may_detach and usersfile)) and 
 213                                  not readonly,
 214                    } 
 215             flist.append(fdict)
 216 
 217         if flist:
 218             flist[latest_file]['latest'] = True
 219  
 220             if sort == 'date':
 221                 flist = sorted(flist, key=itemgetter('fmtime'))
 222             elif sort == 'size':
 223                 flist = sorted(flist, key=itemgetter('fsize')) 
 224             elif sort == 'type':
 225                 flist = sorted(flist, key=itemgetter('ext', 'file'))
 226             elif sort == 'owner':
 227                 flist = sorted(flist, key=itemgetter('ownername', 'file')) 
 228 
 229             if not sumonly:
 230                 html.append(fmt.bullet_list(1))
 231 
 232             for fdict in flist:
 233                 if not fdict['ownercheck']:
 234                     continue
 235                 count += 1
 236                 space += fdict['fsize']
 237                 if fdict['latest']:
 238                     latest = fdict['fmtime']
 239                 if fdict['deletable']:
 240                     links.append(fmt.url(1, getAttachUrl(pagename, fdict['file'], request, do='del')) +
 241                                  fmt.text(label_del) +
 242                                  fmt.url(0))
 243 
 244                 links.append(fmt.url(1, getAttachUrl(pagename, fdict['file'], request)) +
 245                              fmt.text(label_get) +
 246                              fmt.url(0))
 247 
 248                 links.append(fmt.url(1, getAttachUrl(pagename, fdict['file'], request, do='view')) +
 249                              fmt.text(label_view) +
 250                              fmt.url(0))
 251 
 252                 if not sumonly:
 253                     html.append(fmt.listitem(1))
 254                     html.append("%(viewlink)s " % fdict)
 255                     html.append("[ %s ]" % "&nbsp;| ".join(links))
 256                     html.append(" %(fmtime)s, %(fsize).1f KB" % fdict)
 257                     html.append(", uploaded by %(ownername)s" % fdict)
 258                     html.append(fmt.listitem(0))
 259                     links = []
 260             if not sumonly:
 261                 html.append(fmt.bullet_list(0))
 262             if count == 1:
 263                 uploadtxt = 'upload'
 264             else:
 265                 uploadtxt = 'uploads'
 266             html.append(fmt.text(_("%(count)s %(uploadtxt)s stored, \
 267                                     totalling %(fsize)s KB, \
 268                                     latest dated %(fmttime)s") % {
 269                         'count': count,
 270                         'uploadtxt': uploadtxt,
 271                         'fsize': "%.1f" % space,
 272                         'fmttime': latest}))
 273         else:
 274             html.append("%s %s stored" % (0, 'uploads'))
 275     else:
 276         html.append("%s %s stored" % (0, 'uploads'))
 277 
 278     return ''.join(html)
 279 
 280 def _get_files(request, pagename):
 281     attach_dir = getAttachDir(request, pagename)
 282     if os.path.isdir(attach_dir):
 283         files = [fn.decode(config.charset) for fn in os.listdir(attach_dir)]
 284         files.sort()
 285     else:
 286         files = []
 287     return files
 288 
 289 def _get_filelist(request, pagename, mime_type='*', owners='*', sort='*'):
 290     # set sumonly=0, ie false
 291     return _build_filelist(request, pagename, 0, 0, mime_type, owners, sort)
 292 
 293 def _get_info(request, pagename, mime_type='*', owners='*'):
 294     # set sumonly=1, ie true
 295     return _build_filelist(request, pagename, 1, 0, mime_type, owners, sort='*')
 296 
 297 #############################################################################
 298 ### Create parts of the Web interface
 299 #############################################################################
 300 
 301 def send_uploadform(pagename, request):
 302     """ Send the HTML code for the list of already stored attachments and
 303         the file upload form.
 304     """
 305     _ = request.getText
 306 
 307     if not request.user.may.read(pagename):
 308         request.write('<p>%s</p>' % _('You are not allowed to view this page.'))
 309         return
 310 
 311     writeable = request.user.may.attach(pagename)
 312     overwriteable = request.user.may.detach(pagename)
 313     may_delete = request.user.may.delete(pagename)
 314 
 315     # First send out the upload new attachment form on top of everything else.
 316     # This avoids usability issues if you have to scroll down a lot to upload
 317     # a new file when the page already has lots of attachments:
 318     if writeable:
 319         request.write('<h2>' + _("New Upload") + '</h2>')
 320     if writeable and not overwriteable:
 321         request.write("""
 322 <form action="%(url)s" method="POST" enctype="multipart/form-data">
 323 <dl>
 324 <dt>%(upload_label_file)s</dt>
 325 <dd><input type="file" name="file" size="50"></dd>
 326 <dt>%(upload_label_target)s</dt>
 327 <dd><input type="text" name="target" size="50" value="%(target)s"></dd>
 328 </dl>
 329 %(textcha)s
 330 <p>
 331 <input type="hidden" name="action" value="%(action_name)s">
 332 <input type="hidden" name="do" value="upload">
 333 <input type="hidden" name="ticket" value="%(ticket)s">
 334 <input type="submit" value="%(upload_button)s">
 335 </p>
 336 </form>
 337 """ % {
 338     'url': request.href(pagename),
 339     'action_name': action_name,
 340     'upload_label_file': _('File to upload'),
 341     'upload_label_target': _('Rename to'),
 342     'target': wikiutil.escape(request.values.get('target', ''), 1),
 343     'upload_button': _('Upload'),
 344     'textcha': TextCha(request).render(),
 345     'ticket': wikiutil.createTicket(request),
 346 })
 347     if overwriteable:
 348         request.write("""
 349 <form action="%(url)s" method="POST" enctype="multipart/form-data">
 350 <dl>
 351 <dt>%(upload_label_file)s</dt>
 352 <dd><input type="file" name="file" size="50"></dd>
 353 <dt>%(upload_label_target)s</dt>
 354 <dd><input type="text" name="target" size="50" value="%(target)s"></dd>
 355 <dt>%(upload_label_overwrite)s</dt>
 356 <dd><input type="checkbox" name="overwrite" value="1" %(overwrite_checked)s></dd>
 357 </dl>
 358 %(textcha)s
 359 <p>
 360 <input type="hidden" name="action" value="%(action_name)s">
 361 <input type="hidden" name="do" value="upload">
 362 <input type="hidden" name="ticket" value="%(ticket)s">
 363 <input type="submit" value="%(upload_button)s">
 364 </p>
 365 </form>
 366 """ % {
 367     'url': request.href(pagename),
 368     'action_name': action_name,
 369     'upload_label_file': _('File to upload'),
 370     'upload_label_target': _('Rename to'),
 371     'target': wikiutil.escape(request.values.get('target', ''), 1),
 372     'upload_label_overwrite': _('Overwrite existing upload of same name'),
 373     'overwrite_checked': ('', 'checked')[request.form.get('overwrite', '0') == '1'],
 374     'upload_button': _('Upload'),
 375     'textcha': TextCha(request).render(),
 376     'ticket': wikiutil.createTicket(request),
 377 })
 378 
 379     request.write('<h2>' + _("Uploaded Files") + '</h2>')
 380     if writeable and overwriteable and may_delete:
 381         request.write('<p>%s</p>' % _('You can upload, download and delete files.'))
 382         request.write('<h3>' + _("Your uploads") + '</h3>')
 383         request.write(_get_filelist(request, pagename, owners="Self", sort="*"))
 384         request.write('<h3>' + _("Other uploads") + '</h3>')
 385         request.write(_get_filelist(request, pagename, owners="Other", sort="*"))
 386     elif writeable and overwriteable :
 387         request.write('<p>%s</p>' % _('You can upload and download files, and delete your own files.'))
 388         request.write('<h3>' + _("Your uploads") + '</h3>')
 389         request.write(_get_filelist(request, pagename, owners="Self", sort="*"))
 390         request.write('<h3>' + _("Other uploads") + '</h3>')
 391         request.write(_get_filelist(request, pagename, owners="Other", sort="*"))
 392     elif writeable:
 393         request.write('<p>%s</p>' % _('You can upload and download, but not delete files.'))
 394         request.write(_get_filelist(request, pagename))
 395     elif not writeable:
 396         request.write('<p>%s</p>' % _('You can download, but not upload or delete files.'))
 397         request.write(_get_filelist(request, pagename))
 398 
 399 #############################################################################
 400 ### Web interface for file upload, viewing and deletion
 401 #############################################################################
 402 
 403 def execute(pagename, request):
 404     """ Main dispatcher for the 'DropBox' action. """
 405     _ = request.getText
 406 
 407     do = request.values.get('do', 'upload_form')
 408     handler = globals().get('_do_%s' % do)
 409     if handler:
 410         msg = handler(pagename, request)
 411     else:
 412         msg = _('Unsupported DropBox sub-action: %s') % do
 413     if msg:
 414         error_msg(pagename, request, msg)
 415 
 416 
 417 def _do_upload_form(pagename, request):
 418     upload_form(pagename, request)
 419 
 420 def upload_form(pagename, request, msg=''):
 421     if msg:
 422         msg = wikiutil.escape(msg)
 423     _ = request.getText
 424 
 425     # Use user interface language for this generated page
 426     request.setContentLanguage(request.lang)
 427     request.theme.add_msg(msg, "dialog")
 428     request.theme.send_title(_('Uploads for "%(pagename)s"') % {'pagename': pagename}, pagename=pagename)
 429     request.write('<div id="content">\n') # start content div
 430     send_uploadform(pagename, request)
 431     request.write('</div>\n') # end content div
 432     request.theme.send_footer(pagename)
 433     request.theme.send_closing_html()
 434 
 435 def _do_upload(pagename, request):
 436     _ = request.getText
 437 
 438     if not wikiutil.checkTicket(request, request.form.get('ticket', '')):
 439         return _('Please use the interactive user interface to use action %(actionname)s!') % {'actionname': 'DropBox.upload' }
 440 
 441     # Currently we only check TextCha for upload (this is what spammers ususally do),
 442     # but it could be extended to more/all attachment write access
 443     if not TextCha(request).check_answer_from_form():
 444         return _('TextCha: Wrong answer! Go back and try again...')
 445 
 446     form = request.form
 447 
 448     file_upload = request.files.get('file')
 449     if not file_upload:
 450         # This might happen when trying to upload file names
 451         # with non-ascii characters on Safari.
 452         return _("No file content. Delete non ASCII characters from the file name and try again.")
 453 
 454     try:
 455         overwrite = int(form.get('overwrite', '0'))
 456     except:
 457         overwrite = 0
 458 
 459     if not request.user.may.attach(pagename):
 460         return _('You are not allowed to upload a file to this page.')
 461 
 462     if overwrite and not request.user.may.detach(pagename):
 463         return _('You are not allowed to overwrite a file previously uploaded to this page.')
 464 
 465     target = form.get('target', u'').strip()
 466     if not target:
 467         target = file_upload.filename or u''
 468 
 469     target = wikiutil.clean_input(target)
 470 
 471     if not target:
 472         return _("Filename of upload not specified!")
 473 
 474     # add the attachment
 475     try:
 476         target, bytes = add_attachment(request, pagename, target, file_upload.stream, overwrite=overwrite)
 477         msg = _("Upload '%(target)s' (remote name '%(filename)s')"
 478                 " with %(bytes)d bytes saved.") % {
 479                 'target': target, 'filename': file_upload.filename, 'bytes': bytes}
 480     except AttachmentAlreadyExists:
 481         msg = _("Upload '%(target)s' (remote name '%(filename)s') already exists.") % {
 482             'target': target, 'filename': file_upload.filename}
 483 
 484     # return attachment list
 485     upload_form(pagename, request, msg)
 486 
 487 
 488 def _do_del(pagename, request):
 489     _ = request.getText
 490 
 491     if not wikiutil.checkTicket(request, request.args.get('ticket', '')):
 492         return _('Please use the interactive user interface to use action %(actionname)s!') % {'actionname': 'DropBox.del' }
 493 
 494     pagename, filename, fpath = _access_file(pagename, request)
 495     if not request.user.may.detach(pagename):
 496         return _('You are not allowed to delete uploads from this page.')
 497     if not filename:
 498         return # error msg already sent in _access_file
 499 
 500     remove_attachment(request, pagename, filename)
 501 
 502     upload_form(pagename, request, msg=_("Upload '%(filename)s' deleted.") % {'filename': filename})
 503 
 504 
 505 def _do_get(pagename, request):
 506     _ = request.getText
 507 
 508     pagename, filename, fpath = _access_file(pagename, request)
 509     if not request.user.may.read(pagename):
 510         return _('You are not allowed to download from this page.')
 511     if not filename:
 512         return # error msg already sent in _access_file
 513 
 514     timestamp = datetime.datetime.fromtimestamp(os.path.getmtime(fpath))
 515     if_modified = request.if_modified_since
 516     if if_modified and if_modified >= timestamp:
 517         request.status_code = 304
 518     else:
 519         mt = wikiutil.MimeType(filename=filename)
 520         content_type = mt.content_type()
 521         mime_type = mt.mime_type()
 522 
 523         # TODO: fix the encoding here, plain 8 bit is not allowed according to the RFCs
 524         # There is no solution that is compatible to IE except stripping non-ascii chars
 525         filename_enc = filename.encode(config.charset)
 526 
 527         # for dangerous files (like .html), when we are in danger of cross-site-scripting attacks,
 528         # we just let the user store them to disk ('attachment').
 529         # For safe files, we directly show them inline (this also works better for IE).
 530         dangerous = mime_type in request.cfg.mimetypes_xss_protect
 531         content_dispo = dangerous and 'attachment' or 'inline'
 532 
 533         now = time.time()
 534         request.headers['Date'] = http_date(now)
 535         request.headers['Content-Type'] = content_type
 536         request.headers['Last-Modified'] = http_date(timestamp)
 537         request.headers['Expires'] = http_date(now - 365 * 24 * 3600)
 538         request.headers['Content-Length'] = os.path.getsize(fpath)
 539         content_dispo_string = '%s; filename="%s"' % (content_dispo, filename_enc)
 540         request.headers['Content-Disposition'] = content_dispo_string
 541 
 542         # send data
 543         request.send_file(open(fpath, 'rb'))
 544 
 545 def send_viewfile(pagename, request):
 546     _ = request.getText
 547     fmt = request.html_formatter
 548 
 549     pagename, filename, fpath = _access_file(pagename, request)
 550     if not filename:
 551         return
 552 
 553     request.write('<h2>' + _("Upload '%(filename)s'") % {'filename': filename} + '</h2>')
 554     # show a download link above the content
 555     label = _('Download')
 556     link = (fmt.url(1, getAttachUrl(pagename, filename, request, do='get'), css_class="download") +
 557             fmt.text(label) +
 558             fmt.url(0))
 559     request.write('%s<br><br>' % link)
 560 
 561     if filename.endswith('.tdraw') or filename.endswith('.adraw'):
 562         request.write(fmt.attachment_drawing(filename, ''))
 563         return
 564 
 565     mt = wikiutil.MimeType(filename=filename)
 566 
 567     # distinguishs if browser needs a plugin in place
 568     if mt.major == 'image' and mt.minor in config.browser_supported_images:
 569         url = getAttachUrl(pagename, filename, request)
 570         request.write('<img src="%s" alt="%s">' % (
 571             wikiutil.escape(url, 1),
 572             wikiutil.escape(filename, 1)))
 573         return
 574     elif mt.major == 'text':
 575         ext = os.path.splitext(filename)[1]
 576         Parser = wikiutil.getParserForExtension(request.cfg, ext)
 577         if Parser is not None:
 578             try:
 579                 content = file(fpath, 'r').read()
 580                 content = wikiutil.decodeUnknownInput(content)
 581                 colorizer = Parser(content, request, filename=filename)
 582                 colorizer.format(request.formatter)
 583                 return
 584             except IOError:
 585                 pass
 586 
 587         request.write(request.formatter.preformatted(1))
 588         # If we have text but no colorizing parser we try to decode file contents.
 589         content = open(fpath, 'r').read()
 590         content = wikiutil.decodeUnknownInput(content)
 591         content = wikiutil.escape(content)
 592         request.write(request.formatter.text(content))
 593         request.write(request.formatter.preformatted(0))
 594         return
 595 
 596     try:
 597         package = packages.ZipPackage(request, fpath)
 598         if package.isPackage():
 599             request.write("<pre><b>%s</b>\n%s</pre>" % (_("Package script:"), wikiutil.escape(package.getScript())))
 600             return
 601 
 602         if zipfile.is_zipfile(fpath) and mt.minor == 'zip':
 603             zf = zipfile.ZipFile(fpath, mode='r')
 604             request.write("<pre>%-46s %19s %12s\n" % (_("File Name"), _("Modified")+" "*5, _("Size")))
 605             for zinfo in zf.filelist:
 606                 date = "%d-%02d-%02d %02d:%02d:%02d" % zinfo.date_time
 607                 request.write(wikiutil.escape("%-46s %s %12d\n" % (zinfo.filename, date, zinfo.file_size)))
 608             request.write("</pre>")
 609             return
 610     except RuntimeError:
 611         # We don't want to crash with a traceback here (an exception
 612         # here could be caused by an uploaded defective zip file - and
 613         # if we crash here, the user does not get a UI to remove the
 614         # defective zip file again).
 615         # RuntimeError is raised by zipfile stdlib module in case of
 616         # problems (like inconsistent slash and backslash usage in the
 617         # archive).
 618         logging.exception("An exception within zip file upload handling occurred:")
 619         return
 620 
 621     from MoinMoin import macro
 622     from MoinMoin.parser.text import Parser
 623 
 624     macro.request = request
 625     macro.formatter = request.html_formatter
 626     p = Parser("##\n", request)
 627     m = macro.Macro(p)
 628 
 629     # use EmbedObject to view valid mime types
 630     if mt is None:
 631         request.write('<p>' + _("Unknown file type, cannot display this upload inline.") + '</p>')
 632         link = (fmt.url(1, getAttachUrl(pagename, filename, request)) +
 633                 fmt.text(filename) +
 634                 fmt.url(0))
 635         request.write('For using an external program follow this link %s' % link)
 636         return
 637     request.write(m.execute('EmbedObject', u'target="%s", pagename="%s"' % (filename, pagename)))
 638     return
 639 
 640 def _do_view(pagename, request):
 641     _ = request.getText
 642 
 643     orig_pagename = pagename
 644     pagename, filename, fpath = _access_file(pagename, request)
 645     if not request.user.may.read(pagename):
 646         return _('You are not allowed to view uploads from this page.')
 647     if not filename:
 648         return
 649 
 650     request.formatter.page = Page(request, pagename)
 651 
 652     # send header & title
 653     # Use user interface language for this generated page
 654     request.setContentLanguage(request.lang)
 655     title = _('upload:%(filename)s of %(pagename)s') % {
 656         'filename': filename, 'pagename': pagename}
 657     request.theme.send_title(title, pagename=pagename)
 658 
 659     # send body
 660     request.write(request.formatter.startContent())
 661     send_viewfile(orig_pagename, request)
 662     send_uploadform(pagename, request)
 663     request.write(request.formatter.endContent())
 664 
 665     request.theme.send_footer(pagename)
 666     request.theme.send_closing_html()

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