~ubuntu-branches/ubuntu/oneiric/moin/oneiric-security

« back to all changes in this revision

Viewing changes to MoinMoin/action/__init__.py

  • Committer: Bazaar Package Importer
  • Author(s): Jamie Strandboge
  • Date: 2010-03-30 12:55:34 UTC
  • mfrom: (0.1.17 sid)
  • Revision ID: james.westby@ubuntu.com-20100330125534-4c2ufc1rok24447l
Tags: 1.9.2-2ubuntu1
* Merge from Debian testing (LP: #521834). Based on work by Stefan Ebner.
  Remaining changes:
 - Remove python-xml from Suggests field, the package isn't anymore in
   sys.path.
 - Demote fckeditor from Recommends to Suggests; the code was previously
   embedded in moin, but it was also disabled, so there's no reason for us
   to pull this in by default currently. Note: This isn't necessary anymore
   but needs a MIR for fckeditor, so postpone dropping this change until
   lucid+1
* debian/rules:
  - Replace hardcoded python2.5 with python* and hardcore python2.6 for ln
* debian/control.in: drop versioned depends on cdbs

Show diffs side-by-side

added added

removed removed

Lines of Context:
18
18
    Additionally to the usual stuff, we provide an ActionBase class here with
19
19
    some of the usual base functionality for an action, like checking
20
20
    actions_excluded, making and checking tickets, rendering some form,
21
 
    displaying errors and doing stuff after an action.
 
21
    displaying errors and doing stuff after an action. Also utility functions
 
22
    regarding actions are located here.
22
23
 
23
24
    @copyright: 2000-2004 Juergen Hermann <jh@web.de>,
24
25
                2006 MoinMoin:ThomasWaldmann
 
26
                2008 MoinMoin:FlorianKrupicka
25
27
    @license: GNU GPL, see COPYING for details.
26
28
"""
27
29
 
 
30
import re
 
31
 
28
32
from MoinMoin.util import pysupport
29
33
from MoinMoin import config, wikiutil
30
34
from MoinMoin.Page import Page
 
35
from MoinMoin.support.python_compatibility import set
31
36
 
32
37
# create a list of extension actions from the package directory
33
38
modules = pysupport.getPackageModules(__file__)
88
93
            return True
89
94
        # Require a valid ticket. Make outside attacks harder by
90
95
        # requiring two full HTTP transactions
91
 
        ticket = self.form.get('ticket', [''])[0]
 
96
        ticket = self.form.get('ticket', '')
92
97
        return wikiutil.checkTicket(self.request, ticket)
93
98
 
94
99
    # UI ---------------------------------------------------------------------
134
139
 
135
140
        d = {
136
141
            'method': self.method,
137
 
            'baseurl': self.request.getScriptname(),
 
142
            'url': self.request.href(self.pagename),
138
143
            'enctype': self.enctype,
139
144
            'error_html': error_html,
140
145
            'actionname': self.actionname,
141
 
            'pagename': self.pagename,
142
 
            'pagename_quoted': wikiutil.quoteWikinameURL(self.pagename),
143
146
            'ticket_html': ticket_html,
144
147
            'user_html': self.get_form_html(buttons_html),
145
148
        }
146
149
 
147
150
        form_html = '''
148
151
%(error_html)s
149
 
<form action="%(baseurl)s/%(pagename_quoted)s" method="%(method)s" enctype="%(enctype)s">
 
152
<form action="%(url)s" method="%(method)s" enctype="%(enctype)s">
150
153
<div>
151
154
<input type="hidden" name="action" value="%(actionname)s">
152
155
%(ticket_html)s
227
230
 
228
231
# Builtin Actions ------------------------------------------------------------
229
232
 
 
233
MIMETYPE_CRE = re.compile('[a-zA-Z0-9.+\-]{1,100}/[a-zA-Z0-9.+\-]{1,100}')
 
234
 
230
235
def do_raw(pagename, request):
231
236
    """ send raw content of a page (e.g. wiki markup) """
232
237
    if not request.user.may.read(pagename):
233
238
        Page(request, pagename).send_page()
234
239
    else:
235
240
        rev = request.rev or 0
236
 
        Page(request, pagename, rev=rev).send_raw()
 
241
        mimetype = request.values.get('mimetype', None)
 
242
        if mimetype and not MIMETYPE_CRE.match(mimetype):
 
243
            mimetype = None
 
244
        Page(request, pagename, rev=rev).send_raw(mimetype=mimetype)
237
245
 
238
 
def do_show(pagename, request, content_only=0, count_hit=1, cacheable=1, print_mode=0):
239
 
    """ show a page, either current revision or the revision given by rev form value.
 
246
def do_show(pagename, request, content_only=0, count_hit=1, cacheable=1, print_mode=0, mimetype=u'text/html'):
 
247
    """ show a page, either current revision or the revision given by "rev=" value.
240
248
        if count_hit is non-zero, we count the request for statistics.
241
249
    """
242
250
    # We must check if the current page has different ACLs.
243
251
    if not request.user.may.read(pagename):
244
252
        Page(request, pagename).send_page()
245
253
    else:
246
 
        mimetype = request.form.get('mimetype', [u"text/html"])[0]
 
254
        mimetype = request.values.get('mimetype', mimetype)
247
255
        rev = request.rev or 0
248
256
        if rev == 0:
249
257
            request.cacheable = cacheable
254
262
        )
255
263
 
256
264
def do_format(pagename, request):
257
 
    """ send a page using a specific formatter given by mimetype form key.
 
265
    """ send a page using a specific formatter given by "mimetype=" value.
258
266
        Since 5.5.2006 this functionality is also done by do_show, but do_format
259
267
        has a default of text/plain when no format is given.
260
268
        It also does not count in statistics and also does not set the cacheable flag.
261
269
        DEPRECATED: remove this action when we don't need it any more for compatibility.
262
270
    """
263
 
    if 'mimetype' not in request.form:
264
 
        request.form['mimetype'] = [u"text/plain"]
265
 
    do_show(pagename, request, count_hit=0, cacheable=0)
 
271
    do_show(pagename, request, count_hit=0, cacheable=0, mimetype=u'text/plain')
266
272
 
267
273
def do_content(pagename, request):
268
274
    """ same as do_show, but we only show the content """
269
275
    # XXX temporary fix to make it work until Page.send_page gets refactored
270
 
    request.setHttpHeader("Content-Type: text/html; charset=%s" % config.charset)
271
 
    request.setHttpHeader('Status: 200 OK')
272
 
    request.emit_http_headers()
 
276
    request.mimetype = 'text/html'
 
277
    request.status_code = 200
273
278
    do_show(pagename, request, count_hit=0, content_only=1)
274
279
 
275
280
def do_print(pagename, request):
283
288
def do_refresh(pagename, request):
284
289
    """ Handle refresh action """
285
290
    # Without arguments, refresh action will refresh the page text_html cache.
286
 
    arena = request.form.get('arena', ['Page.py'])[0]
 
291
    arena = request.values.get('arena', 'Page.py')
287
292
    if arena == 'Page.py':
288
293
        arena = Page(request, pagename)
289
 
    key = request.form.get('key', ['text_html'])[0]
 
294
    key = request.values.get('key', 'text_html')
290
295
 
291
296
    # Remove cache entry (if exists), and send the page
292
297
    from MoinMoin import caching
296
301
 
297
302
def do_goto(pagename, request):
298
303
    """ redirect to another page """
299
 
    target = request.form.get('target', [''])[0]
 
304
    target = request.values.get('target', '')
300
305
    request.http_redirect(Page(request, target).url(request))
301
306
 
302
307
# Dispatching ----------------------------------------------------------------
303
 
def getNames(cfg):
304
 
    if not hasattr(cfg.cache, 'action_names'):
305
 
        lnames = names[:]
306
 
        lnames.extend(wikiutil.getPlugins('action', cfg))
307
 
        cfg.cache.action_names = lnames # remember it
308
 
    return cfg.cache.action_names
 
308
def get_names(config):
 
309
    """ Get a list of known actions.
 
310
 
 
311
    @param config: a config object
 
312
    @rtype: set
 
313
    @return: set of known actions
 
314
    """
 
315
    if not hasattr(config.cache, 'action_names'):
 
316
        actions = names[:]
 
317
        actions.extend(wikiutil.getPlugins('action', config))
 
318
        actions = set([action for action in actions
 
319
                      if not action in config.actions_excluded])
 
320
        config.cache.action_names = actions # remember it
 
321
    return config.cache.action_names
309
322
 
310
323
def getHandler(request, action, identifier="execute"):
311
 
    """ return a handler function for a given action or None """
 
324
    """ return a handler function for a given action or None.
 
325
 
 
326
    TODO: remove request dependency
 
327
    """
 
328
    cfg = request.cfg
312
329
    # check for excluded actions
313
 
    if action in request.cfg.actions_excluded:
 
330
    if action in cfg.actions_excluded:
314
331
        return None
315
332
 
316
333
    try:
317
 
        handler = wikiutil.importPlugin(request.cfg, "action", action, identifier)
 
334
        handler = wikiutil.importPlugin(cfg, "action", action, identifier)
318
335
    except wikiutil.PluginMissingError:
319
336
        handler = globals().get('do_' + action)
320
337
 
321
338
    return handler
322
339
 
 
340
def get_available_actions(config, page, user):
 
341
        """ Get a list of actions available on a particular page
 
342
        for a particular user.
 
343
 
 
344
        The set does not contain actions that starts with lower case.
 
345
        Themes use this set to display the actions to the user.
 
346
 
 
347
        @param config: a config object (for the per-wiki actions)
 
348
        @param page: the page to which the actions should apply
 
349
        @param user: the user which wants to apply an action
 
350
        @rtype: set
 
351
        @return: set of avaiable actions
 
352
        """
 
353
        if not user.may.read(page.page_name):
 
354
            return []
 
355
 
 
356
 
 
357
        actions = get_names(config)
 
358
 
 
359
        # Filter non ui actions (starts with lower case letter)
 
360
        actions = [action for action in actions if not action[0].islower()]
 
361
 
 
362
        # Filter actions by page type, acl and user state
 
363
        excluded = []
 
364
        if (page.isUnderlayPage() and not page.isStandardPage()) or \
 
365
                not user.may.write(page.page_name) or \
 
366
                not user.may.delete(page.page_name):
 
367
                # Prevent modification of underlay only pages, or pages
 
368
                # the user can't write and can't delete
 
369
                excluded = [u'RenamePage', u'DeletePage', ] # AttachFile must NOT be here!
 
370
        return set([action for action in actions if not action in excluded])
 
371
 
 
372