Attachment 'IncludeWithAttachment20070727.py'

Download

   1 # -*- coding: iso-8859-1 -*-
   2 """
   3     MoinMoin - Include macro with support for attachments
   4 
   5     @copyright: 2006 RaphaelBossek
   6     @copyright: 2000-2004 by Jürgen Hermann <jh@web.de>
   7     @copyright: 2000-2001 by Richard Jones <richard@bizarsoftware.com.au>
   8     @license: GNU GPL, see COPYING for details.
   9 
  10     2006-11-17  RaphaelBossek
  11     * Release v1.0.0
  12     * Added support for attachments.
  13 """
  14 
  15 #Dependencies = ["pages"] # included page
  16 Dependencies = ["time"] # works around MoinMoinBugs/TableOfContentsLacksLinks
  17 
  18 import os, re, StringIO, codecs
  19 from MoinMoin import wikiutil
  20 from MoinMoin.Page import Page
  21 from MoinMoin.util import web
  22 from MoinMoin.action import AttachFile
  23 from MoinMoinCandies import RedirectOutputRequest
  24 
  25 _sysmsg = '<p><strong class="%s">%s</strong></p>'
  26 
  27 ## keep in sync with TableOfContents macro!
  28 _arg_heading = r'(,\s*heading=(?P<hquote>[\'"])(?P<heading>[^,]+)(?P=hquote))?'
  29 _arg_level = r'(,\s*level=(?P<level>\d*))?'
  30 _arg_from = r'(,\s*from=(?P<fquote>[\'"])(?P<from>[^,]+?)(?P=fquote))?'
  31 _arg_to = r'(,\s*to=(?P<tquote>[\'"])(?P<to>[^,]+?)(?P=tquote))?'
  32 _arg_sort = r'(,\s*sort=(?P<sort>(ascending|descending)))?'
  33 _arg_items = r'(,\s*items=(?P<items>\d+))?'
  34 _arg_skipitems = r'(,\s*skipitems=(?P<skipitems>\d+))?'
  35 _arg_titlesonly = r'(,\s*(?P<titlesonly>titlesonly))?'
  36 _arg_editlink = r'(,\s*(?P<editlink>editlink))?'
  37 _arg_encoding = r'(,\s*encoding=(?P<encoding>[^,]+))?'
  38 _arg_parser = r'(,\s*parser=(?P<parser>[^,]+))?'
  39 _args_re_pattern = r'^(?P<name>[^,]+)(' + _arg_heading + _arg_level + _arg_from + _arg_to + _arg_sort + _arg_items + _arg_skipitems + _arg_titlesonly + _arg_editlink + _arg_encoding + _arg_parser + ')?$'
  40 
  41 _title_re = r"^(?P<heading>\s*(?P<hmarker>=+)\s.*\s(?P=hmarker))$"
  42 
  43 def extract_titles(body, title_re):
  44     titles = []
  45     for title, _ in title_re.findall(body):
  46         h = title.strip()
  47         level = 1
  48         while h[level:level+1] == '=': level = level+1
  49         depth = min(5, level)
  50         title_text = h[level:-level].strip()
  51         titles.append((title_text, level))
  52     return titles
  53 
  54 def execute(macro, text, args_re=re.compile(_args_re_pattern), title_re=re.compile(_title_re, re.M), called_by_toc=0):
  55     request = macro.request
  56     _ = request.getText
  57 
  58     # return immediately if getting links for the current page
  59     if request.mode_getpagelinks:
  60         return ''
  61 
  62     # parse and check arguments
  63     args = text and args_re.match(text)
  64     if not text:
  65         return (_sysmsg % ('error', _('Missing arguments!')))
  66     elif not args:
  67         return (_sysmsg % ('error', _('XXX Invalid include arguments args="%s", text="%s" _args_re_pattern="%s"!')) % (args, text, _args_re_pattern,))
  68 
  69     # prepare including page
  70     result = []
  71     # Not 1.5 compatible: print_mode = request.action in ("print", "format")
  72     print_mode = macro.request.form.get(u'action', [u''])[0] in ("print", "format")
  73     this_page = macro.formatter.page
  74     if not hasattr(this_page, '_macroInclude_pagelist'):
  75         this_page._macroInclude_pagelist = {}
  76 
  77     # Get list of pages/files to include.
  78     filelist = []
  79     pagelist = []
  80     page_name = args.group('name')
  81     if page_name.startswith('attachment:'):
  82         file_name = page_name[11:]
  83         filelist = [file_name]
  84     else:
  85         inc_name = wikiutil.AbsPageName(request, this_page.page_name, page_name)
  86         if page_name.startswith("^"):
  87             try:
  88                 inc_match = re.compile(inc_name)
  89             except re.error:
  90                 pass # treat as plain page name
  91             else:
  92                 # Get user filtered readable page list
  93                 pagelist = request.rootpage.getPageList(filter=inc_match.match)
  94         else:
  95             pagelist = [inc_name]
  96 
  97     # sort and limit page list
  98     pagelist.sort()
  99     sort_dir = args.group('sort')
 100     if sort_dir == 'descending':
 101         pagelist.reverse()
 102     max_items = args.group('items')
 103     if max_items:
 104         pagelist = pagelist[:int(max_items)]
 105 
 106     skipitems = 0
 107     if args.group("skipitems"):
 108         skipitems = int(args.group("skipitems"))
 109     titlesonly = args.group('titlesonly')
 110     editlink = args.group('editlink')
 111 
 112     # iterate over pages
 113     inc_pages = []
 114     for inc_name in pagelist:
 115         if not request.user.may.read(inc_name):
 116             continue
 117         if this_page._macroInclude_pagelist.has_key(inc_name):
 118             result.append(u'<p><strong class="error">Recursive include of "%s" forbidden</strong></p>' % (inc_name,))
 119             continue
 120         if skipitems:
 121             skipitems -= 1
 122             continue
 123         fmt = macro.formatter.__class__(request, is_included=True)
 124         fmt._base_depth = macro.formatter._base_depth
 125         inc_page = Page(request, inc_name, formatter=fmt)
 126         if not inc_page.exists():
 127             continue
 128         inc_page._macroInclude_pagelist = this_page._macroInclude_pagelist
 129 
 130         inc_pages.append(inc_page)
 131 
 132     parser = args.group(u'parser')
 133 
 134     # Iterate over file attachemnts.
 135     for inc_name in filelist:
 136         pagename, attach_fname = AttachFile.absoluteName (inc_name, this_page.page_name)
 137         abspagename = wikiutil.AbsPageName (macro.request, this_page.page_name, pagename)
 138         attach_fsfname = AttachFile.getFilename (request, abspagename, attach_fname)
 139         inc_name = abspagename + u'/' + attach_fname
 140         if os.path.isfile(attach_fsfname):
 141             from MoinMoin import config
 142             fmt = macro.formatter.__class__(request, is_included=True)
 143             fmt._base_depth = macro.formatter._base_depth
 144             inc_page = Page(request, this_page.page_name + '-attachment-' + inc_name, formatter=fmt)
 145             inc_page._macroInclude_pagelist = this_page._macroInclude_pagelist
 146             attach_encoding = args.group('encoding')
 147             if not attach_encoding:
 148                 attach_encoding = config.charset
 149             try:
 150                 infile = codecs.open(attach_fsfname, 'rb', attach_encoding)
 151                 if parser:
 152                     rawcontent = "{{{#!" + parser + "\n"
 153                 else:
 154                     rawcontent = ""
 155                 rawcontent = rawcontent + infile.read()
 156                 if parser:
 157                     rawcontent = rawcontent + "\n}}}\n"
 158                 inc_page.set_body(rawcontent)
 159                 inc_pages.append(inc_page)
 160             except UnicodeEncodeError, err:
 161                 pass
 162             except UnicodeDecodeError, err:
 163                 pass
 164         else:
 165             #attach_url = AttachFile.getAttachUrl (abspagename, attach_fname, macro.request)
 166             result.append(macro.formatter.attachment_link(inc_name, u'---'))
 167 
 168     # Iterate over page contents.
 169     for inc_page in inc_pages:
 170         # check for "from" and "to" arguments (allowing partial includes)
 171         body = inc_page.get_raw_body() + '\n'
 172         from_pos = 0
 173         to_pos = -1
 174         from_re = args.group('from')
 175         if from_re:
 176             try:
 177                 from_match = re.compile(from_re, re.M).search(body)
 178             except re.error, e:
 179                 ##result.append("*** fe=%s ***" % e)
 180                 from_match = re.compile(re.escape(from_re), re.M).search(body)
 181             if from_match:
 182                 from_pos = from_match.end()
 183             else:
 184                 result.append(_sysmsg % ('warning', 'Include: ' + _('Nothing found for "%s"!')) % from_re)
 185         to_re = args.group('to')
 186         if to_re:
 187             try:
 188                 to_match = re.compile(to_re, re.M).search(body, from_pos)
 189             except re.error:
 190                 to_match = re.compile(re.escape(to_re), re.M).search(body, from_pos)
 191             if to_match:
 192                 to_pos = to_match.start()
 193             else:
 194                 result.append(_sysmsg % ('warning', 'Include: ' + _('Nothing found for "%s"!')) % to_re)
 195 
 196         if titlesonly:
 197             newbody = []
 198             levelstack = []
 199             for title, level in extract_titles(body[from_pos:to_pos], title_re):
 200                 if levelstack:
 201                     if level > levelstack[-1]:
 202                         result.append(macro.formatter.bullet_list(1))
 203                         levelstack.append(level)
 204                     else:
 205                         while levelstack and level < levelstack[-1]:
 206                             result.append(macro.formatter.bullet_list(0))
 207                             levelstack.pop()
 208                         if not levelstack or level != levelstack[-1]:
 209                             result.append(macro.formatter.bullet_list(1))
 210                             levelstack.append(level)
 211                 else:
 212                     result.append(macro.formatter.bullet_list(1))
 213                     levelstack.append(level)
 214                 result.append(macro.formatter.listitem(1))
 215                 result.append(inc_page.link_to(request, title))
 216                 result.append(macro.formatter.listitem(0))
 217             while levelstack:
 218                 result.append(macro.formatter.bullet_list(0))
 219                 levelstack.pop()
 220             continue
 221 
 222         if from_pos or to_pos != -1:
 223             inc_page.set_raw_body(body[from_pos:to_pos], modified=True)
 224         ##result.append("*** f=%s t=%s ***" % (from_re, to_re))
 225         ##result.append("*** f=%d t=%d ***" % (from_pos, to_pos))
 226 
 227         if called_by_toc:
 228             result.append(inc_page.get_raw_body())
 229             continue
 230 
 231         if not hasattr(request, "_Include_backto"):
 232             request._Include_backto = this_page.page_name
 233 
 234         # do headings
 235         level = None
 236         if args.group('heading') and args.group('hquote'):
 237             heading = args.group('htext') or inc_page.split_title(request)
 238             level = 1
 239             if args.group('level'):
 240                 level = int(args.group('level'))
 241             if print_mode:
 242                 result.append(macro.formatter.heading(1, level) +
 243                               macro.formatter.text(heading) +
 244                               macro.formatter.heading(0, level))
 245             else:
 246                 import sha
 247                 from MoinMoin import config
 248                 # this heading id might produce duplicate ids,
 249                 # if the same page is included multiple times
 250                 # Encode stuf we feed into sha module.
 251                 pntt = (inc_name + heading).encode(config.charset)
 252                 hid = "head-" + sha.new(pntt).hexdigest()
 253                 request._page_headings.setdefault(pntt, 0)
 254                 request._page_headings[pntt] += 1
 255                 if request._page_headings[pntt] > 1:
 256                     hid += '-%d'%(request._page_headings[pntt],)
 257                 result.append(
 258                     #macro.formatter.heading(1, level, hid,
 259                     #    icons=edit_icon.replace('<img ', '<img align="right" ')) +
 260                     macro.formatter.heading(1, level, id=hid) +
 261                     inc_page.link_to(request, heading, css_class="include-heading-link") +
 262                     macro.formatter.heading(0, level)
 263                 )
 264 
 265         # set or increment include marker
 266         this_page._macroInclude_pagelist[inc_name] = \
 267             this_page._macroInclude_pagelist.get(inc_name, 0) + 1
 268 
 269         # Output the included page
 270         ror = RedirectOutputRequest(request)
 271         ror.start(sent_headers=True)
 272         try:
 273             cid = request.makeUniqueID("Include_%s" % wikiutil.quoteWikinameURL(inc_page.page_name))
 274             inc_page.send_page(ror, content_only=1, content_id=cid, omit_footnotes=True)
 275             result.append(ror.getoutput())
 276         except UnicodeDecodeError, e:
 277             result.append(_sysmsg % ('error', _('Encoding %s error: %s' % (attach_encoding, e,))))
 278 
 279         # decrement or remove include marker
 280         if this_page._macroInclude_pagelist[inc_name] > 1:
 281             this_page._macroInclude_pagelist[inc_name] = \
 282                 this_page._macroInclude_pagelist[inc_name] - 1
 283         else:
 284             del this_page._macroInclude_pagelist[inc_name]
 285 
 286         # if no heading and not in print mode, then output a helper link
 287         if editlink and not (level or print_mode):
 288             result.extend([
 289                 macro.formatter.div(1, css_class="include-link"),
 290                 inc_page.link_to(request, '[%s]' % (inc_name,), css_class="include-page-link"),
 291                 inc_page.link_to(request, '[%s]' % (_('edit'),), css_class="include-edit-link", querystr={'action': 'edit', 'backto': request._Include_backto}),
 292                 macro.formatter.div(0),
 293             ])
 294         # XXX page.link_to is wrong now, it escapes the edit_icon html as it escapes normal text
 295 
 296     # return include text
 297     return ''.join(result)
 298 
 299 # vim:ts=4:sw=4:et

Attached Files

To refer to attachments on a page, use attachment:filename, as shown below in the list of files. Do NOT use the URL of the [get] link, since this is subject to change and can break easily.
  • [get | view] (2009-03-01 11:39:57, 0.9 KB) [[attachment:1_9-devel_local_server_config.bundle]]
  • [get | view] (2007-07-27 20:50:57, 12.4 KB) [[attachment:IncludeWithAttachment20070727.py]]
  • [get | view] (2007-09-25 12:38:06, 18.2 KB) [[attachment:raphaelbossek.jpg]]
  • [get | view] (2007-08-15 20:55:02, 2.5 KB) [[attachment:test_parser_unicode.py]]
  • [get | view] (2007-07-27 20:49:55, 1.4 KB) [[attachment:text_xslt.patch]]
  • [get | view] (2007-08-10 20:44:42, 1.7 KB) [[attachment:text_xslt.py.txt]]
  • [get | view] (2007-08-09 20:16:03, 2.3 KB) [[attachment:utf8bug.py]]
 All files | Selected Files: delete move to page copy to page

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