~ubuntu-branches/ubuntu/natty/moin/natty-updates

« back to all changes in this revision

Viewing changes to MoinMoin/config/multiconfig.py

  • Committer: Bazaar Package Importer
  • Author(s): Jonas Smedegaard
  • Date: 2008-06-22 21:17:13 UTC
  • mto: This revision was merged to the branch mainline in revision 18.
  • Revision ID: james.westby@ubuntu.com-20080622211713-inlv5k4eifxckelr
ImportĀ upstreamĀ versionĀ 1.7.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
4
4
 
5
5
    @copyright: 2000-2004 Juergen Hermann <jh@web.de>,
6
6
                2005-2008 MoinMoin:ThomasWaldmann.
7
 
                2008      MoinMoin:JohannesBerg
8
7
    @license: GNU GPL, see COPYING for details.
9
8
"""
10
9
 
16
15
from MoinMoin import log
17
16
logging = log.getLogger(__name__)
18
17
 
19
 
from MoinMoin import config, error, util, wikiutil, web
20
 
from MoinMoin import datastruct
21
 
from MoinMoin.auth import MoinAuth
 
18
from MoinMoin import config, error, util, wikiutil
22
19
import MoinMoin.auth as authmodule
23
20
import MoinMoin.events as events
24
21
from MoinMoin.events import PageChangedEvent, PageRenamedEvent
25
22
from MoinMoin.events import PageDeletedEvent, PageCopiedEvent
26
23
from MoinMoin.events import PageRevertedEvent, FileAttachedEvent
27
 
import MoinMoin.web.session
 
24
from MoinMoin import session
28
25
from MoinMoin.packages import packLine
29
26
from MoinMoin.security import AccessControlList
30
27
from MoinMoin.support.python_compatibility import set
51
48
        raise
52
49
    except IndentationError, err:
53
50
        logging.exception('Your source code / config file is not correctly indented!')
54
 
        msg = """IndentationError: %(err)s
 
51
        msg = '''IndentationError: %(err)s
55
52
 
56
 
The configuration files are Python modules. Therefore, whitespace is
 
53
The configuration files are python modules. Therefore, whitespace is
57
54
important. Make sure that you use only spaces, no tabs are allowed here!
58
55
You have to use four spaces at the beginning of the line mostly.
59
 
""" % {
 
56
''' % {
60
57
    'err': err,
61
58
}
62
59
        raise error.ConfigurationError(msg)
71
68
    """ Return url matching regular expression
72
69
 
73
70
    Import wikis list from farmconfig on the first call and compile the
74
 
    regexes. Later just return the cached regex list.
 
71
    regexes. Later then return the cached regex list.
75
72
 
76
73
    @rtype: list of tuples of (name, compiled re object)
77
74
    @return: url to wiki config name matching list
127
124
        logging.info("using wiki config: %s" % os.path.abspath(module.__file__))
128
125
    except ImportError, err:
129
126
        logging.exception('Could not import.')
130
 
        msg = """ImportError: %(err)s
 
127
        msg = '''ImportError: %(err)s
131
128
 
132
129
Check that the file is in the same directory as the server script. If
133
130
it is not, you must add the path of the directory where the file is
137
134
Check that the configuration file name is either "wikiconfig.py" or the
138
135
module name specified in the wikis list in farmconfig.py. Note that the
139
136
module name does not include the ".py" suffix.
140
 
""" % {
 
137
''' % {
141
138
    'err': err,
142
139
}
143
140
        raise error.ConfigurationError(msg)
144
141
    except AttributeError, err:
145
142
        logging.exception('An exception occured.')
146
 
        msg = """AttributeError: %(err)s
 
143
        msg = '''AttributeError: %(err)s
147
144
 
148
145
Could not find required "Config" class in "%(name)s.py".
149
146
 
151
148
made a syntax or spelling error.
152
149
 
153
150
Another reason for this could be a name clash. It is not possible to have
154
 
config names like e.g. stats.py - because that collides with MoinMoin/stats/ -
 
151
config names like e.g. stats.py - because that colides with MoinMoin/stats/ -
155
152
have a look into your MoinMoin code directory what other names are NOT
156
153
possible.
157
154
 
158
155
Please check your configuration file. As an example for correct syntax,
159
156
use the wikiconfig.py file from the distribution.
160
 
""" % {
 
157
''' % {
161
158
    'name': name,
162
159
    'err': err,
163
160
}
164
161
        raise error.ConfigurationError(msg)
165
162
 
 
163
    # postprocess configuration
 
164
    # 'setuid' special auth method auth method can log out
 
165
    cfg.auth_can_logout = ['setuid']
 
166
    cfg.auth_login_inputs = []
 
167
    found_names = []
 
168
    for auth in cfg.auth:
 
169
        if not auth.name:
 
170
            raise error.ConfigurationError("Auth methods must have a name.")
 
171
        if auth.name in found_names:
 
172
            raise error.ConfigurationError("Auth method names must be unique.")
 
173
        found_names.append(auth.name)
 
174
        if auth.logout_possible and auth.name:
 
175
            cfg.auth_can_logout.append(auth.name)
 
176
        for input in auth.login_inputs:
 
177
            if not input in cfg.auth_login_inputs:
 
178
                cfg.auth_login_inputs.append(input)
 
179
    cfg.auth_have_login = len(cfg.auth_login_inputs) > 0
 
180
 
166
181
    return cfg
167
182
 
168
183
 
206
221
    pass
207
222
 
208
223
 
209
 
class ConfigFunctionality(object):
210
 
    """ Configuration base class with config class behaviour.
211
 
 
212
 
        This class contains the functionality for the DefaultConfig
213
 
        class for the benefit of the WikiConfig macro.
 
224
class DefaultConfig(object):
 
225
    """ default config values
 
226
 
 
227
        When adding new config attributes, PLEASE use a name with the TOPIC as prefix,
 
228
        so it will sort naturally. E.g. use "actions_excluded", not "excluded_actions".
 
229
 
 
230
        Also, please keep it (roughly) sorted (except if you have good reasons to group otherwise).
214
231
    """
215
232
 
216
 
    # attributes of this class that should not be shown
217
 
    # in the WikiConfig() macro.
218
 
    cfg_mtime = None
219
 
    siteid = None
220
 
    cache = None
221
 
    mail_enabled = None
222
 
    jabber_enabled = None
223
 
    auth_can_logout = None
224
 
    auth_have_login = None
225
 
    auth_login_inputs = None
226
 
    _site_plugin_lists = None
227
 
    _iwid = None
228
 
    _iwid_full = None
229
 
    xapian_searchers = None
230
 
    moinmoin_dir = None
231
 
    # will be lazily loaded by interwiki code when needed (?)
232
 
    shared_intermap_files = None
 
233
    DesktopEdition = False # True gives all local users special powers - ONLY use for MMDE style usage!
 
234
 
 
235
    SecurityPolicy = None
 
236
 
 
237
    acl_hierarchic = False # True to use hierarchical ACLs
 
238
    # All acl_rights_* lines must use unicode!
 
239
    acl_rights_default = u"Trusted:read,write,delete,revert Known:read,write,delete,revert All:read,write"
 
240
    acl_rights_before = u""
 
241
    acl_rights_after = u""
 
242
    acl_rights_valid = ['read', 'write', 'delete', 'revert', 'admin']
 
243
 
 
244
    actions_excluded = ['xmlrpc',  # we do not want wiki admins unknowingly offering xmlrpc service
 
245
                        'MyPages',  # only works when used with a non-default SecurityPolicy (e.g. autoadmin)
 
246
                        'CopyPage',  # has questionable behaviour regarding subpages a user can't read, but can copy
 
247
                       ]
 
248
    allow_xslt = False
 
249
    antispam_master_url = "http://master.moinmo.in/?action=xmlrpc2"
 
250
 
 
251
    auth = [authmodule.MoinAuth()]
 
252
    # default to http and xmlrpc_applytoken to get old semantics
 
253
    # xmlrpc_applytoken shall be removed once that code is changed
 
254
    # to have proper session handling and use request.handle_auth()
 
255
    auth_methods_trusted = ['http', 'xmlrpc_applytoken']
 
256
 
 
257
    backup_compression = 'gz'
 
258
    backup_users = []
 
259
    backup_include = []
 
260
    backup_exclude = [
 
261
        r"(.+\.py(c|o)$)",
 
262
        r"%(cache_dir)s",
 
263
        r"%(/)spages%(/)s.+%(/)scache%(/)s[^%(/)s]+$" % {'/': os.sep},
 
264
        r"%(/)s(edit-lock|event-log|\.DS_Store)$" % {'/': os.sep},
 
265
        ]
 
266
    backup_storage_dir = '/tmp'
 
267
    backup_restore_target_dir = '/tmp'
 
268
 
 
269
    bang_meta = True
 
270
    caching_formats = ['text_html']
 
271
    changed_time_fmt = '%H:%M'
 
272
 
 
273
    # chars_{upper,lower,digits,spaces} see MoinMoin/util/chartypes.py
 
274
 
 
275
    # if you have gdchart, add something like
 
276
    # chart_options = {'width = 720, 'height': 540}
 
277
    chart_options = None
 
278
 
 
279
    config_check_enabled = False
 
280
 
 
281
    cookie_domain = None # use '.domain.tld" for a farm with hosts in that domain
 
282
    cookie_path = None   # use '/wikifarm" for a farm with pathes below that path
 
283
    cookie_lifetime = 12 # 12 hours from now
 
284
 
 
285
    data_dir = './data/'
 
286
    data_underlay_dir = './underlay/'
 
287
 
 
288
    date_fmt = '%Y-%m-%d'
 
289
    datetime_fmt = '%Y-%m-%d %H:%M:%S'
 
290
 
 
291
    default_markup = 'wiki'
 
292
    docbook_html_dir = r"/usr/share/xml/docbook/stylesheet/nwalsh/html/" # correct for debian sarge
 
293
 
 
294
    edit_bar = ['Edit', 'Comments', 'Discussion', 'Info', 'Subscribe', 'Quicklink', 'Attachments', 'ActionsMenu']
 
295
    editor_default = 'text' # which editor is called when nothing is specified
 
296
    editor_force = False # force using the default editor
 
297
    editor_ui = 'freechoice' # which editor links are shown on user interface
 
298
    editor_quickhelp = {
 
299
        # editor markup hints quickhelp
 
300
        # MUST be in wiki markup, even if the help is not for the wiki parser!
 
301
        'wiki': _(u"""\
 
302
 Emphasis:: <<Verbatim('')>>''italics''<<Verbatim('')>>; <<Verbatim(''')>>'''bold'''<<Verbatim(''')>>; <<Verbatim(''''')>>'''''bold italics'''''<<Verbatim(''''')>>; <<Verbatim('')>>''mixed ''<<Verbatim(''')>>'''''bold'''<<Verbatim(''')>> and italics''<<Verbatim('')>>; <<Verbatim(----)>> horizontal rule.
 
303
 Headings:: = Title 1 =; == Title 2 ==; === Title 3 ===; ==== Title 4 ====; ===== Title 5 =====.
 
304
 Lists:: space and one of: * bullets; 1., a., A., i., I. numbered items; 1.#n start numbering at n; space alone indents.
 
305
 Links:: <<Verbatim(JoinCapitalizedWords)>>; <<Verbatim([[target|linktext]])>>.
 
306
 Tables:: || cell text |||| cell text spanning 2 columns ||;    no trailing white space allowed after tables or titles.
 
307
 
 
308
(!) For more help, see HelpOnEditing or SyntaxReference.
 
309
"""),
 
310
        'rst': _("""\
 
311
{{{
 
312
Emphasis: *italic* **bold** ``monospace``
 
313
 
 
314
Headings: Heading 1  Heading 2  Heading 3
 
315
          =========  ---------  ~~~~~~~~~
 
316
 
 
317
Horizontal rule: ----
 
318
 
 
319
Links: TrailingUnderscore_ `multi word with backticks`_ external_
 
320
 
 
321
.. _external: http://external-site.example.org/foo/
 
322
 
 
323
Lists: * bullets; 1., a. numbered items.
 
324
}}}
 
325
(!) For more help, see the
 
326
[[http://docutils.sourceforge.net/docs/user/rst/quickref.html|reStructuredText Quick Reference]].
 
327
"""),
 
328
        'creole': _(u"""\
 
329
 Emphasis:: <<Verbatim(//)>>''italics''<<Verbatim(//)>>; <<Verbatim(**)>>'''bold'''<<Verbatim(**)>>; <<Verbatim(**//)>>'''''bold italics'''''<<Verbatim(//**)>>; <<Verbatim(//)>>''mixed ''<<Verbatim(**)>>'''''bold'''<<Verbatim(**)>> and italics''<<Verbatim(//)>>;
 
330
 Horizontal Rule:: <<Verbatim(----)>>
 
331
 Force Linebreak:: <<Verbatim(\\\\)>>
 
332
 Headings:: = Title 1 =; == Title 2 ==; === Title 3 ===; ==== Title 4 ====; ===== Title 5 =====.
 
333
 Lists:: * bullets; ** sub-bullets; # numbered items; ## numbered sub items.
 
334
 Links:: <<Verbatim([[target]])>>; <<Verbatim([[target|linktext]])>>.
 
335
 Tables:: |= header text | cell text | more cell text |;
 
336
 
 
337
(!) For more help, see HelpOnEditing or HelpOnCreoleSyntax.
 
338
"""),
 
339
    }
 
340
    edit_locking = 'warn 10' # None, 'warn <timeout mins>', 'lock <timeout mins>'
 
341
    edit_ticketing = True
 
342
    edit_rows = 20
 
343
 
 
344
    hacks = {} # { 'feature1': value1, ... }
 
345
               # Configuration for features still in development.
 
346
               # For boolean stuff just use config like this:
 
347
               #   hacks = { 'feature': True, ...}
 
348
               # and in the code use:
 
349
               #   if cfg.hacks.get('feature', False): <doit>
 
350
               # A non-existing hack key should ever mean False, None, "", [] or {}!
 
351
 
 
352
    history_count = (100, 200) # (default_revisions_shown, max_revisions_shown)
 
353
 
 
354
    hosts_deny = []
 
355
 
 
356
    html_head = ''
 
357
    html_head_queries = '''<meta name="robots" content="noindex,nofollow">\n'''
 
358
    html_head_posts   = '''<meta name="robots" content="noindex,nofollow">\n'''
 
359
    html_head_index   = '''<meta name="robots" content="index,follow">\n'''
 
360
    html_head_normal  = '''<meta name="robots" content="index,nofollow">\n'''
 
361
    html_pagetitle = None
 
362
 
 
363
    interwikiname = None # our own interwikiname. choose wisely and never change!
 
364
    interwiki_preferred = [] # list of wiki names to show at top of interwiki list
 
365
 
 
366
    language_default = 'en'
 
367
    language_ignore_browser = False # ignore browser settings, use language_default
 
368
                                    # or user prefs
 
369
 
 
370
    logo_string = None # can be either just some text or a piece of html shown as "logo"
 
371
 
 
372
    log_reverse_dns_lookups = True  # if we do reverse dns lookups for logging hostnames
 
373
                                    # instead of just IPs
 
374
    log_timing = False # log infos about timing of actions, good to analyze load conditions
 
375
 
 
376
    mail_from = None # u'Juergen Wiki <noreply@jhwiki.org>'
 
377
    mail_login = None # "user pwd" if you need to use SMTP AUTH when using your mail server
 
378
    mail_smarthost = None # your SMTP mail server
 
379
    mail_sendmail = None # "/usr/sbin/sendmail -t -i" to not use SMTP, but sendmail
 
380
 
 
381
    mail_import_secret = "" # a shared secret also known to the mail importer xmlrpc script
 
382
    mail_import_subpage_template = u"$from-$date-$subject" # used for mail import
 
383
    mail_import_pagename_search = ['subject', 'to', ] # where to look for target pagename (and in which order)
 
384
    mail_import_pagename_envelope = u"%s" # use u"+ %s/" to add "+ " and "/" automatically
 
385
    mail_import_pagename_regex = r'\[\[([^\]]*)\]\]' # how to find/extract the pagename from the subject
 
386
    mail_import_wiki_addrs = [] # the e-mail addresses for e-mails that should go into the wiki
 
387
 
 
388
    # some dangerous mimetypes (we don't use "content-disposition: inline" for them when a user
 
389
    # downloads such attachments, because the browser might execute e.g. Javascript contained
 
390
    # in the HTML and steal your moin session cookie or do other nasty stuff)
 
391
    mimetypes_xss_protect = [
 
392
        'text/html',
 
393
        'application/x-shockwave-flash',
 
394
        'application/xhtml+xml',
 
395
    ]
 
396
 
 
397
    mimetypes_embed = [
 
398
        'application/x-dvi',
 
399
        'application/postscript',
 
400
        'application/pdf',
 
401
        'application/ogg',
 
402
        'application/vnd.visio',
 
403
        'image/x-ms-bmp',
 
404
        'image/svg+xml',
 
405
        'image/tiff',
 
406
        'image/x-photoshop',
 
407
        'audio/mpeg',
 
408
        'audio/midi',
 
409
        'audio/x-wav',
 
410
        'video/fli',
 
411
        'video/mpeg',
 
412
        'video/quicktime',
 
413
        'video/x-msvideo',
 
414
        'chemical/x-pdb',
 
415
        'x-world/x-vrml',
 
416
    ]
 
417
 
 
418
 
 
419
    navi_bar = [u'RecentChanges', u'FindPage', u'HelpContents', ]
 
420
    nonexist_qm = False
 
421
 
 
422
    notification_bot_uri = None # uri of the jabber bot
 
423
 
 
424
    # OpenID server support
 
425
    openid_server_enabled = False
 
426
    openid_server_restricted_users_group = None
 
427
    openid_server_enable_user = False
 
428
 
 
429
    page_credits = [
 
430
        # Feel free to add other credits, but PLEASE do NOT change or remove
 
431
        # the following links - you help us by keeping them "as is":
 
432
        '<a href="http://moinmo.in/" title="This site uses the MoinMoin Wiki software.">MoinMoin Powered</a>',
 
433
        '<a href="http://moinmo.in/Python" title="MoinMoin is written in Python.">Python Powered</a>',
 
434
 
 
435
        # Optional credits:
 
436
        # if you think it can be maybe misunderstood as applying to content or topic of your wiki,
 
437
        # feel free to remove this one:
 
438
        '<a href="http://moinmo.in/GPL" title="MoinMoin is GPL licensed.">GPL licensed</a>',
 
439
 
 
440
        # if you don't need/want to check the html output, feel free to remove this one:
 
441
        '<a href="http://validator.w3.org/check?uri=referer" title="Click here to validate this page.">Valid HTML 4.01</a>',
 
442
        ]
 
443
 
 
444
    # you can put some pieces of html at specific places into the theme output:
 
445
    page_footer1 = ''
 
446
    page_footer2 = ''
 
447
    page_header1 = ''
 
448
    page_header2 = ''
 
449
 
 
450
    page_front_page = u'HelpOnLanguages' # this will make people choose a sane config
 
451
    page_local_spelling_words = u'LocalSpellingWords'
 
452
 
 
453
    # the following regexes should match the complete name when used in free text
 
454
    # the group 'all' shall match all, while the group 'key' shall match the key only
 
455
    # e.g. CategoryFoo -> group 'all' ==  CategoryFoo, group 'key' == Foo
 
456
    # moin's code will add ^ / $ at beginning / end when needed
 
457
    page_category_regex = ur'(?P<all>Category(?P<key>\S+))'
 
458
    page_dict_regex = ur'(?P<all>(?P<key>\S+)Dict)'
 
459
    page_group_regex = ur'(?P<all>(?P<key>\S+)Group)'
 
460
    page_template_regex = ur'(?P<all>(?P<key>\S+)Template)'
 
461
 
 
462
    page_license_enabled = False
 
463
    page_license_page = u'WikiLicense'
 
464
 
 
465
    # These icons will show in this order in the iconbar, unless they
 
466
    # are not relevant, e.g email icon when the wiki is not configured
 
467
    # for email.
 
468
    page_iconbar = ["up", "edit", "view", "diff", "info", "subscribe", "raw", "print", ]
 
469
 
 
470
    # Standard buttons in the iconbar
 
471
    page_icons_table = {
 
472
        # key           pagekey, querystr dict, title, icon-key
 
473
        'diff':        ('page', {'action': 'diff'}, _("Diffs"), "diff"),
 
474
        'info':        ('page', {'action': 'info'}, _("Info"), "info"),
 
475
        'edit':        ('page', {'action': 'edit'}, _("Edit"), "edit"),
 
476
        'unsubscribe': ('page', {'action': 'unsubscribe'}, _("UnSubscribe"), "unsubscribe"),
 
477
        'subscribe':   ('page', {'action': 'subscribe'}, _("Subscribe"), "subscribe"),
 
478
        'raw':         ('page', {'action': 'raw'}, _("Raw"), "raw"),
 
479
        'xml':         ('page', {'action': 'show', 'mimetype': 'text/xml'}, _("XML"), "xml"),
 
480
        'print':       ('page', {'action': 'print'}, _("Print"), "print"),
 
481
        'view':        ('page', {}, _("View"), "view"),
 
482
        'up':          ('page_parent_page', {}, _("Up"), "up"),
 
483
        }
 
484
 
 
485
 
 
486
    def password_checker(username, password):
 
487
        """ Check if a password is secure enough.
 
488
            We use a built-in check to get rid of the worst passwords.
 
489
 
 
490
            We do NOT use cracklib / python-crack here any more because it is
 
491
            not thread-safe (we experienced segmentation faults when using it).
 
492
 
 
493
            If you don't want to check passwords, use password_checker = None.
 
494
 
 
495
            @return: None if there is no problem with the password,
 
496
                     some string with an error msg, if the password is problematic.
 
497
        """
 
498
 
 
499
        try:
 
500
            # in any case, do a very simple built-in check to avoid the worst passwords
 
501
            if len(password) < 6:
 
502
                raise ValueError("Password too short.")
 
503
            if len(set(password)) < 4:
 
504
                raise ValueError("Password has not enough different characters.")
 
505
 
 
506
            username_lower = username.lower()
 
507
            password_lower = password.lower()
 
508
            if username in password or password in username or \
 
509
               username_lower in password_lower or password_lower in username_lower:
 
510
                raise ValueError("Password too easy (containment).")
 
511
 
 
512
            keyboards = (ur"`1234567890-=qwertyuiop[]\asdfghjkl;'zxcvbnm,./", # US kbd
 
513
                         ur"^1234567890ß“qwertzuiopļæ½+asdfghjklļæ½ļæ½#yxcvbnm,.-", # german kbd
 
514
                        ) # add more keyboards!
 
515
            for kbd in keyboards:
 
516
                rev_kbd = kbd[::-1]
 
517
                if password in kbd or password in rev_kbd or \
 
518
                   password_lower in kbd or password_lower in rev_kbd:
 
519
                    raise ValueError("Password too easy (kbd sequence)")
 
520
            return None
 
521
        except ValueError, err:
 
522
            return str(err)
 
523
 
 
524
    password_checker = staticmethod(password_checker)
 
525
 
 
526
    quicklinks_default = [] # preload user quicklinks with this page list
 
527
 
 
528
    refresh = None # (minimum_delay, type), e.g.: (2, 'internal')
 
529
    rss_cache = 60 # suggested caching time for RecentChanges RSS, in seconds
 
530
 
 
531
    search_results_per_page = 25
 
532
 
 
533
    session_handler = session.DefaultSessionHandler()
 
534
    session_id_handler = session.MoinCookieSessionIDHandler()
 
535
 
 
536
    shared_intermap = None # can be string or list of strings (filenames)
 
537
 
 
538
    show_hosts = True # show hostnames on RecentChanges / info/history action
 
539
    show_interwiki = False # show our interwiki name (usually in front of the page name)
 
540
    show_names = True # show editor names on RecentChanges / info/history action
 
541
    show_section_numbers = 0 # enumerate sections (headlines) by default?
 
542
    show_timings = False # show some timing stats (usually in the footer)
 
543
    show_version = False # show moin version info / (C) (depends on theme)
 
544
 
 
545
    sistersites = [
 
546
        #('Self', 'http://localhost:8080/?action=sisterpages'),
 
547
        #('EmacsWiki', 'http://www.emacswiki.org/cgi-bin/test?action=sisterpages'),
 
548
        #('JspWiki', 'http://www.jspwiki.org/SisterSites.jsp'),
 
549
    ] # list of (sistersitename, sisterpagelistfetchurl)
 
550
 
 
551
    siteid = 'default'
 
552
    sitename = u'Untitled Wiki' # Wiki identity
 
553
 
 
554
    stylesheets = [] # list of tuples (media, csshref) to insert after theme css, before user css
 
555
 
 
556
    _subscribable_events = None # A list of event types that user can subscribe to
 
557
    subscribed_pages_default = [] # preload user subscribed pages with this page list
 
558
    email_subscribed_events_default = [
 
559
        PageChangedEvent.__name__,
 
560
        PageRenamedEvent.__name__,
 
561
        PageDeletedEvent.__name__,
 
562
        PageCopiedEvent.__name__,
 
563
        PageRevertedEvent.__name__,
 
564
        FileAttachedEvent.__name__,
 
565
    ]
 
566
    jabber_subscribed_events_default = []
 
567
 
 
568
    superuser = [] # list of unicode user names that have super powers :)
 
569
 
 
570
    supplementation_page = False # use supplementation pages (show a link in the theme)?
 
571
    supplementation_page_name = u'Discussion' # name of suppl. subpage
 
572
    supplementation_page_template = u'DiscussionTemplate' # name of template used to create suppl. pages
 
573
 
 
574
    surge_action_limits = {# allow max. <count> <action> requests per <dt> secs
 
575
        # action: (count, dt)
 
576
        'all': (30, 30),
 
577
        'show': (30, 60),
 
578
        'recall': (10, 120),
 
579
        'raw': (20, 40),  # some people use this for css
 
580
        'AttachFile': (90, 60),
 
581
        'diff': (30, 60),
 
582
        'fullsearch': (10, 120),
 
583
        'edit': (30, 300), # can be lowered after making preview different from edit
 
584
        'rss_rc': (1, 60),
 
585
        'default': (30, 60),
 
586
    }
 
587
    surge_lockout_time = 3600 # secs you get locked out when you ignore warnings
 
588
 
 
589
    textchas = None # a data structure with site-specific questions/answers, see HelpOnTextChas
 
590
    textchas_disabled_group = None # e.g. u'NoTextChasGroup' if you are a member of this group, you don't get textchas
 
591
 
 
592
    theme_default = 'modern'
 
593
    theme_force = False
 
594
 
 
595
    traceback_show = True # if True, tracebacks are displayed in the web browser
 
596
    traceback_log_dir = None # if set to a directory path, tracebacks are written to files there
 
597
 
 
598
    trail_size = 5 # number of recently visited pagenames shown in the trail display
 
599
    tz_offset = 0.0 # default time zone offset in hours from UTC
 
600
 
 
601
    # a regex of HTTP_USER_AGENTS that should be excluded from logging
 
602
    # and receive a FORBIDDEN for anything except viewing a page
 
603
    # list must not contain 'java' because of twikidraw wanting to save drawing uses this useragent
 
604
    ua_spiders = ('archiver|cfetch|charlotte|crawler|curl|gigabot|googlebot|heritrix|holmes|htdig|httrack|httpunit|'
 
605
                  'intelix|jeeves|larbin|leech|libwww-perl|linkbot|linkmap|linkwalk|litefinder|mercator|'
 
606
                  'microsoft.url.control|mirror| mj12bot|msnbot|msrbot|neomo|nutbot|omniexplorer|puf|robot|scooter|seekbot|'
 
607
                  'sherlock|slurp|sitecheck|snoopy|spider|teleport|twiceler|voilabot|voyager|webreaper|wget|yeti')
 
608
 
 
609
    unzip_single_file_size = 2.0 * 1000 ** 2
 
610
    unzip_attachments_space = 200.0 * 1000 ** 2
 
611
    unzip_attachments_count = 101 # 1 zip file + 100 files contained in it
 
612
 
 
613
    url_mappings = {}
 
614
 
 
615
    # url_prefix is DEPRECATED and not used any more by the code.
 
616
    # it confused many people by its name and default value of '/wiki' to the
 
617
    # wrong conclusion that it is the url of the wiki (the dynamic) stuff,
 
618
    # but it was used to address the static stuff (images, css, js).
 
619
    # Thus we use the more clear url_prefix_static ['/moin_staticVVV'] setting now.
 
620
    # For a limited time, we still look at url_prefix - if it is not None, we
 
621
    # copy the value to url_prefix_static to ease transition.
 
622
    url_prefix = None
 
623
 
 
624
    # includes the moin version number, so we can have a unlimited cache lifetime
 
625
    # for the static stuff. if stuff changes on version upgrade, url will change
 
626
    # immediately and we have no problem with stale caches.
 
627
    url_prefix_static = config.url_prefix_static
 
628
    url_prefix_local = None # if None, use same value as url_prefix_static.
 
629
                            # must be same site as wiki engine (for e.g. JS permissions)
 
630
 
 
631
    # we could prefix actions to be able to exclude them by robots.txt:
 
632
    #url_prefix_action = 'action' # no leading or trailing '/'
 
633
    url_prefix_action = None # compatiblity
 
634
 
 
635
    # allow disabling certain userpreferences plugins
 
636
    userprefs_disabled = []
 
637
 
 
638
    user_autocreate = False # do we auto-create user profiles
 
639
    user_email_unique = True # do we check whether a user's email is unique?
 
640
    user_jid_unique = True # do we check whether a user's email is unique?
 
641
 
 
642
    user_homewiki = 'Self' # interwiki name for where user homepages are located
 
643
 
 
644
    user_checkbox_fields = [
 
645
        ('mailto_author', lambda _: _('Publish my email (not my wiki homepage) in author info')),
 
646
        ('edit_on_doubleclick', lambda _: _('Open editor on double click')),
 
647
        ('remember_last_visit', lambda _: _('After login, jump to last visited page')),
 
648
        ('show_comments', lambda _: _('Show comment sections')),
 
649
        ('show_nonexist_qm', lambda _: _('Show question mark for non-existing pagelinks')),
 
650
        ('show_page_trail', lambda _: _('Show page trail')),
 
651
        ('show_toolbar', lambda _: _('Show icon toolbar')),
 
652
        ('show_topbottom', lambda _: _('Show top/bottom links in headings')),
 
653
        ('show_fancy_diff', lambda _: _('Show fancy diffs')),
 
654
        ('wikiname_add_spaces', lambda _: _('Add spaces to displayed wiki names')),
 
655
        ('remember_me', lambda _: _('Remember login information')),
 
656
 
 
657
        ('disabled', lambda _: _('Disable this account forever')),
 
658
        # if an account is disabled, it may be used for looking up
 
659
        # id -> username for page info and recent changes, but it
 
660
        # is not usable for the user any more:
 
661
    ]
 
662
 
 
663
    user_checkbox_defaults = {'mailto_author':       0,
 
664
                              'edit_on_doubleclick': 0,
 
665
                              'remember_last_visit': 0,
 
666
                              'show_comments':       0,
 
667
                              'show_nonexist_qm':    nonexist_qm,
 
668
                              'show_page_trail':     1,
 
669
                              'show_toolbar':        1,
 
670
                              'show_topbottom':      0,
 
671
                              'show_fancy_diff':     1,
 
672
                              'wikiname_add_spaces': 0,
 
673
                              'remember_me':         1,
 
674
                             }
 
675
 
 
676
    # don't let the user change those
 
677
    # user_checkbox_disable = ['disabled']
 
678
    user_checkbox_disable = []
 
679
 
 
680
    # remove those checkboxes:
 
681
    #user_checkbox_remove = ['edit_on_doubleclick', 'show_nonexist_qm', 'show_toolbar', 'show_topbottom',
 
682
    #                        'show_fancy_diff', 'wikiname_add_spaces', 'remember_me', 'disabled',]
 
683
    user_checkbox_remove = []
 
684
 
 
685
    user_form_fields = [
 
686
        ('name', _('Name'), "text", "36", _("(Use FirstnameLastname)")),
 
687
        ('aliasname', _('Alias-Name'), "text", "36", ''),
 
688
        ('email', _('Email'), "text", "36", ''),
 
689
        ('jid', _('Jabber ID'), "text", "36", ''),
 
690
        ('css_url', _('User CSS URL'), "text", "40", _('(Leave it empty for disabling user CSS)')),
 
691
        ('edit_rows', _('Editor size'), "text", "3", ''),
 
692
    ]
 
693
 
 
694
    user_form_defaults = {# key: default - do NOT remove keys from here!
 
695
        'name': '',
 
696
        'aliasname': '',
 
697
        'password': '',
 
698
        'password2': '',
 
699
        'email': '',
 
700
        'jid': '',
 
701
        'css_url': '',
 
702
        'edit_rows': "20",
 
703
    }
 
704
 
 
705
    # don't let the user change those, but show them:
 
706
    #user_form_disable = ['name', 'aliasname', 'email',]
 
707
    user_form_disable = []
 
708
 
 
709
    # remove those completely:
 
710
    #user_form_remove = ['password', 'password2', 'css_url', 'logout', 'create', 'account_sendmail',]
 
711
    user_form_remove = []
 
712
 
 
713
    # attributes we do NOT save to the userpref file
 
714
    user_transient_fields = ['id', 'valid', 'may', 'auth_username', 'password', 'password2', 'auth_method', 'auth_attribs', ]
 
715
 
 
716
    xapian_search = False
 
717
    xapian_index_dir = None
 
718
    xapian_stemming = False
 
719
    xapian_index_history = False
233
720
 
234
721
    def __init__(self, siteid):
235
722
        """ Init Config instance """
251
738
            name = dirname + '_dir'
252
739
            if not getattr(self, name, None):
253
740
                setattr(self, name, os.path.abspath(os.path.join(data_dir, dirname)))
254
 
        # directories below cache_dir (using __dirname__ to avoid conflicts)
255
 
        for dirname in ('session', ):
256
 
            name = dirname + '_dir'
257
 
            if not getattr(self, name, None):
258
 
                setattr(self, name, os.path.abspath(os.path.join(self.cache_dir, '__%s__' % dirname)))
259
741
 
260
742
        # Try to decode certain names which allow unicode
261
743
        self._decode()
272
754
        self.cache.page_group_regexact = re.compile(u'^%s$' % self.page_group_regex, re.UNICODE)
273
755
        self.cache.page_template_regexact = re.compile(u'^%s$' % self.page_template_regex, re.UNICODE)
274
756
 
275
 
        self.cache.ua_spiders = self.ua_spiders and re.compile(self.ua_spiders, re.IGNORECASE)
 
757
        self.cache.ua_spiders = self.ua_spiders and re.compile(self.ua_spiders, re.I)
276
758
 
277
759
        self._check_directories()
278
760
 
282
764
                     Please change it in your wiki configuration and try again."""
283
765
            raise error.ConfigurationError(msg)
284
766
 
285
 
        # moin < 1.9 used cookie_lifetime = <float> (but converted it to int) for logged-in users and
286
 
        # anonymous_session_lifetime = <float> or None for anon users
287
 
        # moin >= 1.9 uses cookie_lifetime = (<float>, <float>) - first is anon, second is logged-in
288
 
        if not (isinstance(self.cookie_lifetime, tuple) and len(self.cookie_lifetime) == 2):
289
 
            logging.error("wiki configuration has an invalid setting: " +
290
 
                          "cookie_lifetime = %r" % (self.cookie_lifetime, ))
291
 
            try:
292
 
                anon_lifetime = self.anonymous_session_lifetime
293
 
                logging.warning("wiki configuration has an unsupported setting: " +
294
 
                                "anonymous_session_lifetime = %r - " % anon_lifetime +
295
 
                                "please remove it.")
296
 
                if anon_lifetime is None:
297
 
                    anon_lifetime = 0
298
 
                anon_lifetime = float(anon_lifetime)
299
 
            except:
300
 
                # if anything goes wrong, use default value
301
 
                anon_lifetime = 0
302
 
            try:
303
 
                logged_in_lifetime = int(self.cookie_lifetime)
304
 
            except:
305
 
                # if anything goes wrong, use default value
306
 
                logged_in_lifetime = 12
307
 
            self.cookie_lifetime = (anon_lifetime, logged_in_lifetime)
308
 
            logging.warning("using cookie_lifetime = %r - " % (self.cookie_lifetime, ) +
309
 
                            "please fix your wiki configuration.")
310
 
 
311
767
        self._loadPluginModule()
312
768
 
313
769
        # Preparse user dicts
332
788
            except ImportError:
333
789
                self.chart_options = None
334
790
 
335
 
        # "Render As Docbook" requires python-xml.
336
 
        if 'RenderAsDocbook' not in self.actions_excluded:
337
 
            try:
338
 
                from xml.dom.ext.reader import Sax
339
 
            except ImportError:
340
 
                # this will also remove it from the actions menu:
341
 
                self.actions_excluded.append('RenderAsDocbook')
342
 
 
343
 
        # 'setuid' special auth method auth method can log out
344
 
        self.auth_can_logout = ['setuid']
345
 
        self.auth_login_inputs = []
346
 
        found_names = []
347
 
        for auth in self.auth:
348
 
            if not auth.name:
349
 
                raise error.ConfigurationError("Auth methods must have a name.")
350
 
            if auth.name in found_names:
351
 
                raise error.ConfigurationError("Auth method names must be unique.")
352
 
            found_names.append(auth.name)
353
 
            if auth.logout_possible and auth.name:
354
 
                self.auth_can_logout.append(auth.name)
355
 
            for input in auth.login_inputs:
356
 
                if not input in self.auth_login_inputs:
357
 
                    self.auth_login_inputs.append(input)
358
 
        self.auth_have_login = len(self.auth_login_inputs) > 0
359
 
        self.auth_methods = found_names
 
791
        # post process
360
792
 
361
793
        # internal dict for plugin `modules' lists
362
794
        self._site_plugin_lists = {}
364
796
        # we replace any string placeholders with config values
365
797
        # e.g u'%(page_front_page)s' % self
366
798
        self.navi_bar = [elem % self for elem in self.navi_bar]
 
799
        self.backup_exclude = [elem % self for elem in self.backup_exclude]
367
800
 
368
801
        # check if python-xapian is installed
369
802
        if self.xapian_search:
378
811
 
379
812
        # check if mail is possible and set flag:
380
813
        self.mail_enabled = (self.mail_smarthost is not None or self.mail_sendmail is not None) and self.mail_from
381
 
        self.mail_enabled = self.mail_enabled and True or False
382
814
 
383
815
        # check if jabber bot is available and set flag:
384
816
        self.jabber_enabled = self.notification_bot_uri is not None
385
817
 
386
818
        # if we are to use the jabber bot, instantiate a server object for future use
387
819
        if self.jabber_enabled:
 
820
 
 
821
            errmsg = "You must set a (long) secret string to send notifications!"
 
822
            try:
 
823
                if not self.secret:
 
824
                    raise error.ConfigurationError(errmsg)
 
825
            except AttributeError, err:
 
826
                raise error.ConfigurationError(errmsg)
 
827
 
388
828
            from xmlrpclib import Server
389
829
            self.notification_server = Server(self.notification_bot_uri, )
390
830
 
395
835
        self.cache.acl_rights_default = AccessControlList(self, [self.acl_rights_default])
396
836
        self.cache.acl_rights_after = AccessControlList(self, [self.acl_rights_after])
397
837
 
 
838
        if self.url_prefix is not None: # remove this code when url_prefix setting is removed
 
839
            self.url_prefix_static = self.url_prefix
 
840
 
398
841
        action_prefix = self.url_prefix_action
399
842
        if action_prefix is not None and action_prefix.endswith('/'): # make sure there is no trailing '/'
400
843
            self.url_prefix_action = action_prefix[:-1]
402
845
        if self.url_prefix_local is None:
403
846
            self.url_prefix_local = self.url_prefix_static
404
847
 
405
 
        if self.url_prefix_fckeditor is None:
406
 
            self.url_prefix_fckeditor = self.url_prefix_local + '/applets/FCKeditor'
407
 
 
408
 
        if self.secrets is None:  # admin did not setup a real secret, so make up something
409
 
            self.secrets = self.calc_secrets()
410
 
 
411
 
        secret_key_names = ['action/cache', 'wikiutil/tickets', 'xmlrpc/ProcessMail', 'xmlrpc/RemoteScript', ]
412
 
        if self.jabber_enabled:
413
 
            secret_key_names.append('jabberbot')
414
 
 
415
 
        secret_min_length = 10
416
 
        if isinstance(self.secrets, str):
417
 
            if len(self.secrets) < secret_min_length:
418
 
                raise error.ConfigurationError("The secrets = '...' wiki config setting is a way too short string (minimum length is %d chars)!" % (
419
 
                    secret_min_length))
420
 
            # for lazy people: set all required secrets to same value
421
 
            secrets = {}
422
 
            for key in secret_key_names:
423
 
                secrets[key] = self.secrets
424
 
            self.secrets = secrets
425
 
 
426
 
        # we check if we have all secrets we need and that they have minimum length
427
 
        for secret_key_name in secret_key_names:
428
 
            try:
429
 
                secret = self.secrets[secret_key_name]
430
 
                if len(secret) < secret_min_length:
431
 
                    raise ValueError
432
 
            except (KeyError, ValueError):
433
 
                raise error.ConfigurationError("You must set a (at least %d chars long) secret string for secrets['%s']!" % (
434
 
                    secret_min_length, secret_key_name))
435
 
 
436
 
    def calc_secrets(self):
437
 
        """ make up some 'secret' using some config values """
438
 
        varnames = ['data_dir', 'data_underlay_dir', 'language_default',
439
 
                    'mail_smarthost', 'mail_from', 'page_front_page',
440
 
                    'theme_default', 'sitename', 'logo_string',
441
 
                    'interwikiname', 'user_homewiki', 'acl_rights_before', ]
442
 
        secret = ''
443
 
        for varname in varnames:
444
 
            var = getattr(self, varname, None)
445
 
            if isinstance(var, (str, unicode)):
446
 
                secret += repr(var)
447
 
        return secret
448
 
 
449
 
    _meta_dict = None
 
848
 
450
849
    def load_meta_dict(self):
451
850
        """ The meta_dict contains meta data about the wiki instance. """
452
 
        if self._meta_dict is None:
 
851
        if getattr(self, "_meta_dict", None) is None:
453
852
            self._meta_dict = wikiutil.MetaDict(os.path.join(self.data_dir, 'meta'), self.cache_dir)
454
853
        return self._meta_dict
455
854
    meta_dict = property(load_meta_dict)
464
863
    iwid = make_iwid_property("_iwid")
465
864
    iwid_full = make_iwid_property("_iwid_full")
466
865
 
 
866
    # lazily load a list of events a user can subscribe to
 
867
    def make_subscribable_events_prop():
 
868
        def getter(self):
 
869
            if getattr(self, "_subscribable_events", None) is None:
 
870
                self._subscribable_events = events.get_subscribable_events()
 
871
            return getattr(self, "_subscribable_events")
 
872
 
 
873
        def setter(self, new_events):
 
874
            self._subscribable_events = new_events
 
875
 
 
876
        return property(getter, setter)
 
877
    subscribable_events = make_subscribable_events_prop()
 
878
 
467
879
    # lazily create a list of event handlers
468
 
    _event_handlers = None
469
880
    def make_event_handlers_prop():
470
881
        def getter(self):
471
 
            if self._event_handlers is None:
 
882
            if getattr(self, "_event_handlers", None) is None:
472
883
                self._event_handlers = events.get_handlers(self)
473
 
            return self._event_handlers
 
884
            return getattr(self, "_event_handlers")
474
885
 
475
886
        def setter(self, new_handlers):
476
887
            self._event_handlers = new_handlers
535
946
        config files.
536
947
        """
537
948
        charset = 'utf-8'
538
 
        message = u"""
 
949
        message = u'''
539
950
"%(name)s" configuration variable is a string, but should be
540
951
unicode. Use %(name)s = u"value" syntax for unicode variables.
541
952
 
542
953
Also check your "-*- coding -*-" line at the top of your configuration
543
954
file. It should match the actual charset of the configuration file.
544
 
"""
 
955
'''
545
956
 
546
957
        decode_names = (
547
 
            'sitename', 'interwikiname', 'user_homewiki', 'logo_string', 'navi_bar',
548
 
            'page_front_page', 'page_category_regex', 'page_dict_regex',
 
958
            'sitename', 'logo_string', 'navi_bar', 'page_front_page',
 
959
            'page_category_regex', 'page_dict_regex',
549
960
            'page_group_regex', 'page_template_regex', 'page_license_page',
550
961
            'page_local_spelling_words', 'acl_rights_default',
551
962
            'acl_rights_before', 'acl_rights_after', 'mail_from'
588
999
 
589
1000
            path_pages = os.path.join(path, "pages")
590
1001
            if not (os.path.isdir(path_pages) and os.access(path_pages, mode)):
591
 
                msg = """
 
1002
                msg = '''
592
1003
%(attr)s "%(path)s" does not exist, or has incorrect ownership or
593
1004
permissions.
594
1005
 
598
1009
 
599
1010
It is recommended to use absolute paths and not relative paths. Check
600
1011
also the spelling of the directory name.
601
 
""" % {'attr': attr, 'path': path, }
 
1012
''' % {'attr': attr, 'path': path, }
602
1013
                raise error.ConfigurationError(msg)
603
1014
 
604
1015
    def _loadPluginModule(self):
605
 
        """
606
 
        import all plugin modules
 
1016
        """ import plugin module under configname.plugin
607
1017
 
608
1018
        To be able to import plugin from arbitrary path, we have to load
609
1019
        the base package once using imp.load_module. Later, we can use
610
1020
        standard __import__ call to load plugins in this package.
611
1021
 
612
 
        Since each configured plugin path has unique plugins, we load the
613
 
        plugin packages as "moin_plugin_<sha1(path)>.plugin".
 
1022
        Since each wiki has unique plugins, we load the plugin package
 
1023
        under the wiki configuration module, named self.siteid.
614
1024
        """
615
1025
        import imp
616
 
        from MoinMoin.support.python_compatibility import hash_new
617
 
 
618
 
        plugin_dirs = [self.plugin_dir] + self.plugin_dirs
619
 
        self._plugin_modules = []
620
 
 
 
1026
 
 
1027
        name = self.siteid + '.plugin'
621
1028
        try:
622
1029
            # Lock other threads while we check and import
623
1030
            imp.acquire_lock()
624
1031
            try:
625
 
                for pdir in plugin_dirs:
626
 
                    csum = 'p_%s' % hash_new('sha1', pdir).hexdigest()
627
 
                    modname = '%s.%s' % (self.siteid, csum)
628
 
                    # If the module is not loaded, try to load it
629
 
                    if not modname in sys.modules:
630
 
                        # Find module on disk and try to load - slow!
631
 
                        abspath = os.path.abspath(pdir)
632
 
                        parent_dir, pname = os.path.split(abspath)
633
 
                        fp, path, info = imp.find_module(pname, [parent_dir])
634
 
                        try:
635
 
                            # Load the module and set in sys.modules
636
 
                            module = imp.load_module(modname, fp, path, info)
637
 
                            setattr(sys.modules[self.siteid], 'csum', module)
638
 
                        finally:
639
 
                            # Make sure fp is closed properly
640
 
                            if fp:
641
 
                                fp.close()
642
 
                    if modname not in self._plugin_modules:
643
 
                        self._plugin_modules.append(modname)
 
1032
                # If the module is not loaded, try to load it
 
1033
                if not name in sys.modules:
 
1034
                    # Find module on disk and try to load - slow!
 
1035
                    plugin_parent_dir = os.path.abspath(os.path.join(self.plugin_dir, '..'))
 
1036
                    fp, path, info = imp.find_module('plugin', [plugin_parent_dir])
 
1037
                    try:
 
1038
                        # Load the module and set in sys.modules
 
1039
                        module = imp.load_module(name, fp, path, info)
 
1040
                        sys.modules[self.siteid].plugin = module
 
1041
                    finally:
 
1042
                        # Make sure fp is closed properly
 
1043
                        if fp:
 
1044
                            fp.close()
644
1045
            finally:
645
1046
                imp.release_lock()
646
1047
        except ImportError, err:
647
 
            msg = """
648
 
Could not import plugin package "%(path)s" because of ImportError:
 
1048
            msg = '''
 
1049
Could not import plugin package "%(path)s/plugin" because of ImportError:
649
1050
%(err)s.
650
1051
 
651
1052
Make sure your data directory path is correct, check permissions, and
652
1053
that the data/plugin directory has an __init__.py file.
653
 
""" % {
654
 
    'path': pdir,
 
1054
''' % {
 
1055
    'path': self.data_dir,
655
1056
    'err': str(err),
656
1057
}
657
1058
            raise error.ConfigurationError(msg)
671
1072
        """ Make it possible to access a config object like a dict """
672
1073
        return getattr(self, item)
673
1074
 
674
 
 
675
 
class DefaultConfig(ConfigFunctionality):
676
 
    """ Configuration base class with default config values
677
 
        (added below)
678
 
    """
679
 
    # Do not add anything into this class. Functionality must
680
 
    # be added above to avoid having the methods show up in
681
 
    # the WikiConfig macro. Settings must be added below to
682
 
    # the options dictionary.
683
 
 
684
 
 
685
 
def _default_password_checker(cfg, request, username, password):
686
 
    """ Check if a password is secure enough.
687
 
        We use a built-in check to get rid of the worst passwords.
688
 
 
689
 
        We do NOT use cracklib / python-crack here any more because it is
690
 
        not thread-safe (we experienced segmentation faults when using it).
691
 
 
692
 
        If you don't want to check passwords, use password_checker = None.
693
 
 
694
 
        @return: None if there is no problem with the password,
695
 
                 some unicode object with an error msg, if the password is problematic.
696
 
    """
697
 
    _ = request.getText
698
 
    # in any case, do a very simple built-in check to avoid the worst passwords
699
 
    if len(password) < 6:
700
 
        return _("Password is too short.")
701
 
    if len(set(password)) < 4:
702
 
        return _("Password has not enough different characters.")
703
 
 
704
 
    username_lower = username.lower()
705
 
    password_lower = password.lower()
706
 
    if username in password or password in username or \
707
 
       username_lower in password_lower or password_lower in username_lower:
708
 
        return _("Password is too easy (password contains name or name contains password).")
709
 
 
710
 
    keyboards = (ur"`1234567890-=qwertyuiop[]\asdfghjkl;'zxcvbnm,./", # US kbd
711
 
                 ur"^1234567890ß“qwertzuiopļæ½+asdfghjklļæ½ļæ½#yxcvbnm,.-", # german kbd
712
 
                ) # add more keyboards!
713
 
    for kbd in keyboards:
714
 
        rev_kbd = kbd[::-1]
715
 
        if password in kbd or password in rev_kbd or \
716
 
           password_lower in kbd or password_lower in rev_kbd:
717
 
            return _("Password is too easy (keyboard sequence).")
718
 
    return None
719
 
 
720
 
 
721
 
class DefaultExpression(object):
722
 
    def __init__(self, exprstr):
723
 
        self.text = exprstr
724
 
        self.value = eval(exprstr)
725
 
 
726
 
 
727
 
#
728
 
# Options that are not prefixed automatically with their
729
 
# group name, see below (at the options dict) for more
730
 
# information on the layout of this structure.
731
 
#
732
 
options_no_group_name = {
733
 
  # =========================================================================
734
 
  'attachment_extension': ("Mapping of attachment extensions to actions", None,
735
 
  (
736
 
   ('extensions_mapping',
737
 
       {'.tdraw': {'modify': 'twikidraw'},
738
 
        '.adraw': {'modify': 'anywikidraw'},
739
 
       }, "file extension -> do -> action"),
740
 
  )),
741
 
  # ==========================================================================
742
 
  'datastruct': ('Datastruct settings', None, (
743
 
    ('dicts', lambda cfg, request: datastruct.WikiDicts(request),
744
 
     "function f(cfg, request) that returns a backend which is used to access dicts definitions."),
745
 
    ('groups', lambda cfg, request: datastruct.WikiGroups(request),
746
 
     "function f(cfg, request) that returns a backend which is used to access groups definitions."),
747
 
  )),
748
 
  # ==========================================================================
749
 
  'session': ('Session settings', "Session-related settings, see HelpOnSessions.", (
750
 
    ('session_service', DefaultExpression('web.session.FileSessionService()'),
751
 
     "The session service."),
752
 
    ('cookie_name', None,
753
 
     'The variable part of the session cookie name. (None = determine from URL, siteidmagic = use siteid, any other string = use that)'),
754
 
    ('cookie_secure', None,
755
 
     'Use secure cookie. (None = auto-enable secure cookie for https, True = ever use secure cookie, False = never use secure cookie).'),
756
 
    ('cookie_httponly', False,
757
 
     'Use a httponly cookie that can only be used by the server, not by clientside scripts.'),
758
 
    ('cookie_domain', None,
759
 
     'Domain used in the session cookie. (None = do not specify domain).'),
760
 
    ('cookie_path', None,
761
 
     'Path used in the session cookie (None = auto-detect). Please only set if you know exactly what you are doing.'),
762
 
    ('cookie_lifetime', (0, 12),
763
 
     'Session lifetime [h] of (anonymous, logged-in) users (see HelpOnSessions for details).'),
764
 
  )),
765
 
  # ==========================================================================
766
 
  'auth': ('Authentication / Authorization / Security settings', None, (
767
 
    ('superuser', [],
768
 
     "List of trusted user names with wiki system administration super powers (not to be confused with ACL admin rights!). Used for e.g. software installation, language installation via SystemPagesSetup and more. See also HelpOnSuperUser."),
769
 
    ('auth', DefaultExpression('[MoinAuth()]'),
770
 
     "list of auth objects, to be called in this order (see HelpOnAuthentication)"),
771
 
    ('auth_methods_trusted', ['http', 'given', 'xmlrpc_applytoken'], # Note: 'http' auth method is currently just a redirect to 'given'
772
 
     'authentication methods for which users should be included in the special "Trusted" ACL group.'),
773
 
    ('secrets', None, """Either a long shared secret string used for multiple purposes or a dict {"purpose": "longsecretstring", ...} for setting up different shared secrets for different purposes. If you don't setup own secret(s), a secret string will be auto-generated from other config settings."""),
774
 
    ('DesktopEdition',
775
 
     False,
776
 
     "if True, give all local users special powers - ''only use this for a local desktop wiki!''"),
777
 
    ('SecurityPolicy',
778
 
     None,
779
 
     "Class object hook for implementing security restrictions or relaxations"),
780
 
    ('actions_excluded',
781
 
     ['xmlrpc',  # we do not want wiki admins unknowingly offering xmlrpc service
782
 
      'MyPages',  # only works when used with a non-default SecurityPolicy (e.g. autoadmin)
783
 
      'CopyPage',  # has questionable behaviour regarding subpages a user can't read, but can copy
784
 
     ],
785
 
     "Exclude unwanted actions (list of strings)"),
786
 
 
787
 
    ('allow_xslt', False,
788
 
     "if True, enables XSLT processing via 4Suite (note that this enables anyone with enough know-how to insert '''arbitrary HTML''' into your wiki, which is why it defaults to `False`)"),
789
 
 
790
 
    ('password_checker', DefaultExpression('_default_password_checker'),
791
 
     'checks whether a password is acceptable (default check is length >= 6, at least 4 different chars, no keyboard sequence, not username used somehow (you can switch this off by using `None`)'),
792
 
 
793
 
  )),
794
 
  # ==========================================================================
795
 
  'spam_leech_dos': ('Anti-Spam/Leech/DOS',
796
 
  'These settings help limiting ressource usage and avoiding abuse.',
797
 
  (
798
 
    ('hosts_deny', [], "List of denied IPs; if an IP ends with a dot, it denies a whole subnet (class A, B or C)"),
799
 
    ('surge_action_limits',
800
 
     {# allow max. <count> <action> requests per <dt> secs
801
 
        # action: (count, dt)
802
 
        'all': (30, 30), # all requests (except cache/AttachFile action) count for this limit
803
 
        'default': (30, 60), # default limit for actions without a specific limit
804
 
        'show': (30, 60),
805
 
        'recall': (10, 120),
806
 
        'raw': (20, 40),  # some people use this for css
807
 
        'diff': (30, 60),
808
 
        'fullsearch': (10, 120),
809
 
        'edit': (30, 300), # can be lowered after making preview different from edit
810
 
        'rss_rc': (1, 60),
811
 
        # The following actions are often used for images - to avoid pages with lots of images
812
 
        # (like photo galleries) triggering surge protection, we assign rather high limits:
813
 
        'AttachFile': (300, 30),
814
 
        'cache': (600, 30), # cache action is very cheap/efficient
815
 
     },
816
 
     "Surge protection tries to deny clients causing too much load/traffic, see HelpOnConfiguration/SurgeProtection."),
817
 
    ('surge_lockout_time', 3600, "time [s] someone gets locked out when ignoring the warnings"),
818
 
 
819
 
    ('textchas', None,
820
 
     "Spam protection setup using site-specific questions/answers, see HelpOnSpam."),
821
 
    ('textchas_disabled_group', None,
822
 
     "Name of a group of trusted users who do not get asked !TextCha questions."),
823
 
 
824
 
    ('antispam_master_url', "http://master.moinmo.in/?action=xmlrpc2",
825
 
     "where antispam security policy fetches spam pattern updates (if it is enabled)"),
826
 
 
827
 
    # a regex of HTTP_USER_AGENTS that should be excluded from logging
828
 
    # and receive a FORBIDDEN for anything except viewing a page
829
 
    # list must not contain 'java' because of twikidraw wanting to save drawing uses this useragent
830
 
    ('ua_spiders',
831
 
     ('archiver|cfetch|charlotte|crawler|curl|gigabot|googlebot|heritrix|holmes|htdig|httrack|httpunit|'
832
 
      'intelix|jeeves|larbin|leech|libwww-perl|linkbot|linkmap|linkwalk|litefinder|mercator|'
833
 
      'microsoft.url.control|mirror| mj12bot|msnbot|msrbot|neomo|nutbot|omniexplorer|puf|robot|scooter|seekbot|'
834
 
      'sherlock|slurp|sitecheck|snoopy|spider|teleport|twiceler|voilabot|voyager|webreaper|wget|yeti'),
835
 
     "A regex of HTTP_USER_AGENTs that should be excluded from logging and are not allowed to use actions."),
836
 
 
837
 
    ('unzip_single_file_size', 2.0 * 1000 ** 2,
838
 
     "max. size of a single file in the archive which will be extracted [bytes]"),
839
 
    ('unzip_attachments_space', 200.0 * 1000 ** 2,
840
 
     "max. total amount of bytes can be used to unzip files [bytes]"),
841
 
    ('unzip_attachments_count', 101,
842
 
     "max. number of files which are extracted from the zip file"),
843
 
  )),
844
 
  # ==========================================================================
845
 
  'style': ('Style / Theme / UI related',
846
 
  'These settings control how the wiki user interface will look like.',
847
 
  (
848
 
    ('sitename', u'Untitled Wiki',
849
 
     "Short description of your wiki site, displayed below the logo on each page, and used in RSS documents as the channel title [Unicode]"),
850
 
    ('interwikiname', None, "unique and stable InterWiki name (prefix, moniker) of the site [Unicode], or None"),
851
 
    ('logo_string', None, "The wiki logo top of page, HTML is allowed (`<img>` is possible as well) [Unicode]"),
852
 
    ('html_pagetitle', None, "Allows you to set a specific HTML page title (if None, it defaults to the value of `sitename`)"),
853
 
    ('navi_bar', [u'RecentChanges', u'FindPage', u'HelpContents', ],
854
 
     'Most important page names. Users can add more names in their quick links in user preferences. To link to URL, use `u"[[url|link title]]"`, to use a shortened name for long page name, use `u"[[LongLongPageName|title]]"`. [list of Unicode strings]'),
855
 
 
856
 
    ('theme_default', 'modernized',
857
 
     "the name of the theme that is used by default (see HelpOnThemes)"),
858
 
    ('theme_force', False,
859
 
     "if True, do not allow to change the theme"),
860
 
 
861
 
    ('stylesheets', [],
862
 
     "List of tuples (media, csshref) to insert after theme css, before user css, see HelpOnThemes."),
863
 
 
864
 
    ('supplementation_page', False,
865
 
     "if True, show a link to the supplementation page in the theme"),
866
 
    ('supplementation_page_name', u'Discussion',
867
 
     "default name of the supplementation (sub)page [unicode]"),
868
 
    ('supplementation_page_template', u'DiscussionTemplate',
869
 
     "default template used for creation of the supplementation page [unicode]"),
870
 
 
871
 
    ('interwiki_preferred', [], "In dialogues, show those wikis at the top of the list."),
872
 
    ('sistersites', [], "list of tuples `('WikiName', 'sisterpagelist_fetch_url')`"),
873
 
 
874
 
    ('trail_size', 5,
875
 
     "Number of pages in the trail of visited pages"),
876
 
 
877
 
    ('page_footer1', '', "Custom HTML markup sent ''before'' the system footer."),
878
 
    ('page_footer2', '', "Custom HTML markup sent ''after'' the system footer."),
879
 
    ('page_header1', '', "Custom HTML markup sent ''before'' the system header / title area but after the body tag."),
880
 
    ('page_header2', '', "Custom HTML markup sent ''after'' the system header / title area (and body tag)."),
881
 
 
882
 
    ('changed_time_fmt', '%H:%M', "Time format used on Recent``Changes for page edits within the last 24 hours"),
883
 
    ('date_fmt', '%Y-%m-%d', "System date format, used mostly in Recent``Changes"),
884
 
    ('datetime_fmt', '%Y-%m-%d %H:%M:%S', 'Default format for dates and times (when the user has no preferences or chose the "default" date format)'),
885
 
    ('chart_options', None, "If you have gdchart, use something like chart_options = {'width': 720, 'height': 540}"),
886
 
 
887
 
    ('edit_bar', ['Edit', 'Comments', 'Discussion', 'Info', 'Subscribe', 'Quicklink', 'Attachments', 'ActionsMenu'],
888
 
     'list of edit bar entries'),
889
 
    ('history_count', (100, 200, 5, 10, 25, 50), "Number of revisions shown for info/history action (default_count_shown, max_count_shown, [other values shown as page size choices]). At least first two values (default and maximum) should be provided. If additional values are provided, user will be able to change number of items per page in the UI."),
890
 
    ('history_paging', True, "Enable paging functionality for info action's history display."),
891
 
 
892
 
    ('show_hosts', True,
893
 
     "if True, show host names and IPs. Set to False to hide them."),
894
 
    ('show_interwiki', False,
895
 
     "if True, let the theme display your interwiki name"),
896
 
    ('show_names', True,
897
 
     "if True, show user names in the revision history and on Recent``Changes. Set to False to hide them."),
898
 
    ('show_section_numbers', False,
899
 
     'show section numbers in headings by default'),
900
 
    ('show_timings', False, "show some timing values at bottom of a page"),
901
 
    ('show_version', False, "show moin's version at the bottom of a page"),
902
 
    ('show_rename_redirect', False, "if True, offer creation of redirect pages when renaming wiki pages"),
903
 
 
904
 
    ('packagepages_actions_excluded',
905
 
     ['setthemename',  # related to questionable theme stuff, see below
906
 
      'copythemefile', # maybe does not work, e.g. if no fs write permissions or real theme file path is unknown to moin
907
 
      'installplugin', # code installation, potentially dangerous
908
 
      'renamepage',    # dangerous with hierarchical acls
909
 
      'deletepage',    # dangerous with hierarchical acls
910
 
      'delattachment', # dangerous, no revisioning
911
 
     ],
912
 
     'list with excluded package actions (e.g. because they are dangerous / questionable)'),
913
 
 
914
 
    ('page_credits',
915
 
     [
916
 
       '<a href="http://moinmo.in/" title="This site uses the MoinMoin Wiki software.">MoinMoin Powered</a>',
917
 
       '<a href="http://moinmo.in/Python" title="MoinMoin is written in Python.">Python Powered</a>',
918
 
       '<a href="http://moinmo.in/GPL" title="MoinMoin is GPL licensed.">GPL licensed</a>',
919
 
       '<a href="http://validator.w3.org/check?uri=referer" title="Click here to validate this page.">Valid HTML 4.01</a>',
920
 
     ],
921
 
     'list with html fragments with logos or strings for crediting.'),
922
 
 
923
 
    # These icons will show in this order in the iconbar, unless they
924
 
    # are not relevant, e.g email icon when the wiki is not configured
925
 
    # for email.
926
 
    ('page_iconbar', ["up", "edit", "view", "diff", "info", "subscribe", "raw", "print", ],
927
 
     'list of icons to show in iconbar, valid values are only those in page_icons_table. Available only in classic theme.'),
928
 
 
929
 
    # Standard buttons in the iconbar
930
 
    ('page_icons_table',
931
 
     {
932
 
        # key           pagekey, querystr dict, title, icon-key
933
 
        'diff': ('page', {'action': 'diff'}, _("Diffs"), "diff"),
934
 
        'info': ('page', {'action': 'info'}, _("Info"), "info"),
935
 
        'edit': ('page', {'action': 'edit'}, _("Edit"), "edit"),
936
 
        'unsubscribe': ('page', {'action': 'unsubscribe'}, _("UnSubscribe"), "unsubscribe"),
937
 
        'subscribe': ('page', {'action': 'subscribe'}, _("Subscribe"), "subscribe"),
938
 
        'raw': ('page', {'action': 'raw'}, _("Raw"), "raw"),
939
 
        'xml': ('page', {'action': 'show', 'mimetype': 'text/xml'}, _("XML"), "xml"),
940
 
        'print': ('page', {'action': 'print'}, _("Print"), "print"),
941
 
        'view': ('page', {}, _("View"), "view"),
942
 
        'up': ('page_parent_page', {}, _("Up"), "up"),
943
 
     },
944
 
     "dict of {'iconname': (url, title, icon-img-key), ...}. Available only in classic theme."),
945
 
 
946
 
  )),
947
 
  # ==========================================================================
948
 
  'editor': ('Editor related', None, (
949
 
    ('editor_default', 'text', "Editor to use by default, 'text' or 'gui'"),
950
 
    ('editor_force', False, "if True, force using the default editor"),
951
 
    ('editor_ui', 'freechoice', "Editor choice shown on the user interface, 'freechoice' or 'theonepreferred'"),
952
 
    ('page_license_enabled', False, 'if True, show a license hint in page editor.'),
953
 
    ('page_license_page', u'WikiLicense', 'Page linked from the license hint. [Unicode]'),
954
 
    ('edit_locking', 'warn 10', "Editor locking policy: `None`, `'warn <timeout in minutes>'`, or `'lock <timeout in minutes>'`"),
955
 
    ('edit_ticketing', True, None),
956
 
    ('edit_rows', 20, "Default height of the edit box"),
957
 
 
958
 
  )),
959
 
  # ==========================================================================
960
 
  'paths': ('Paths', None, (
961
 
    ('data_dir', './data/', "Path to the data directory containing your (locally made) wiki pages."),
962
 
    ('data_underlay_dir', './underlay/', "Path to the underlay directory containing distribution system and help pages."),
963
 
    ('cache_dir', None, "Directory for caching, by default computed from `data_dir`/cache."),
964
 
    ('session_dir', None, "Directory for session storage, by default computed to be `cache_dir`/__session__."),
965
 
    ('user_dir', None, "Directory for user storage, by default computed to be `data_dir`/user."),
966
 
    ('plugin_dir', None, "Plugin directory, by default computed to be `data_dir`/plugin."),
967
 
    ('plugin_dirs', [], "Additional plugin directories."),
968
 
 
969
 
    ('docbook_html_dir', r"/usr/share/xml/docbook/stylesheet/nwalsh/html/",
970
 
     'Path to the directory with the Docbook to HTML XSLT files (optional, used by the docbook parser). The default value is correct for Debian Etch.'),
971
 
    ('shared_intermap', None,
972
 
     "Path to a file containing global InterWiki definitions (or a list of such filenames)"),
973
 
  )),
974
 
  # ==========================================================================
975
 
  'urls': ('URLs', None, (
976
 
    # includes the moin version number, so we can have a unlimited cache lifetime
977
 
    # for the static stuff. if stuff changes on version upgrade, url will change
978
 
    # immediately and we have no problem with stale caches.
979
 
    ('url_prefix_static', config.url_prefix_static,
980
 
     "used as the base URL for icons, css, etc. - includes the moin version number and changes on every release. This replaces the deprecated and sometimes confusing `url_prefix = '/wiki'` setting."),
981
 
    ('url_prefix_local', None,
982
 
     "used as the base URL for some Javascript - set this to a URL on same server as the wiki if your url_prefix_static points to a different server."),
983
 
    ('url_prefix_fckeditor', None,
984
 
     "used as the base URL for FCKeditor - similar to url_prefix_local, but just for FCKeditor."),
985
 
 
986
 
    ('url_prefix_action', None,
987
 
     "Use 'action' to enable action URL generation to be compatible with robots.txt. It will generate .../action/info/PageName?action=info then. Recommended for internet wikis."),
988
 
 
989
 
    ('notification_bot_uri', None, "URI of the Jabber notification bot."),
990
 
 
991
 
    ('url_mappings', {},
992
 
     "lookup table to remap URL prefixes (dict of {{{'prefix': 'replacement'}}}); especially useful in intranets, when whole trees of externally hosted documents move around"),
993
 
 
994
 
  )),
995
 
  # ==========================================================================
996
 
  'pages': ('Special page names', None, (
997
 
    ('page_front_page', u'LanguageSetup',
998
 
     "Name of the front page. We don't expect you to keep the default. Just read LanguageSetup in case you're wondering... [Unicode]"),
999
 
 
1000
 
    # the following regexes should match the complete name when used in free text
1001
 
    # the group 'all' shall match all, while the group 'key' shall match the key only
1002
 
    # e.g. CategoryFoo -> group 'all' ==  CategoryFoo, group 'key' == Foo
1003
 
    # moin's code will add ^ / $ at beginning / end when needed
1004
 
    ('page_category_regex', ur'(?P<all>Category(?P<key>(?!Template)\S+))',
1005
 
     'Pagenames exactly matching this regex are regarded as Wiki categories [Unicode]'),
1006
 
    ('page_dict_regex', ur'(?P<all>(?P<key>\S+)Dict)',
1007
 
     'Pagenames exactly matching this regex are regarded as pages containing variable dictionary definitions [Unicode]'),
1008
 
    ('page_group_regex', ur'(?P<all>(?P<key>\S+)Group)',
1009
 
     'Pagenames exactly matching this regex are regarded as pages containing group definitions [Unicode]'),
1010
 
    ('page_template_regex', ur'(?P<all>(?P<key>\S+)Template)',
1011
 
     'Pagenames exactly matching this regex are regarded as pages containing templates for new pages [Unicode]'),
1012
 
 
1013
 
    ('page_local_spelling_words', u'LocalSpellingWords',
1014
 
     'Name of the page containing user-provided spellchecker words [Unicode]'),
1015
 
  )),
1016
 
  # ==========================================================================
1017
 
  'user': ('User Preferences related', None, (
1018
 
    ('quicklinks_default', [],
1019
 
     'List of preset quicklinks for a newly created user accounts. Existing accounts are not affected by this option whereas changes in navi_bar do always affect existing accounts. Preset quicklinks can be removed by the user in the user preferences menu, navi_bar settings not.'),
1020
 
    ('subscribed_pages_default', [],
1021
 
     "List of pagenames used for presetting page subscriptions for newly created user accounts."),
1022
 
 
1023
 
    ('email_subscribed_events_default',
1024
 
     [
1025
 
        PageChangedEvent.__name__,
1026
 
        PageRenamedEvent.__name__,
1027
 
        PageDeletedEvent.__name__,
1028
 
        PageCopiedEvent.__name__,
1029
 
        PageRevertedEvent.__name__,
1030
 
        FileAttachedEvent.__name__,
1031
 
     ], None),
1032
 
    ('jabber_subscribed_events_default', [], None),
1033
 
 
1034
 
    ('tz_offset', 0.0,
1035
 
     "default time zone offset in hours from UTC"),
1036
 
 
1037
 
    ('userprefs_disabled', [],
1038
 
     "Disable the listed user preferences plugins."),
1039
 
  )),
1040
 
  # ==========================================================================
1041
 
  'various': ('Various', None, (
1042
 
    ('bang_meta', True, 'if True, enable {{{!NoWikiName}}} markup'),
1043
 
    ('caching_formats', ['text_html'], "output formats that are cached; set to [] to turn off caching (useful for development)"),
1044
 
 
1045
 
    ('config_check_enabled', False, "if True, check configuration for unknown settings."),
1046
 
 
1047
 
    ('default_markup', 'wiki', 'Default page parser / format (name of module in `MoinMoin.parser`)'),
1048
 
 
1049
 
    ('html_head', '', "Additional <HEAD> tags, see HelpOnThemes."),
1050
 
    ('html_head_queries', '<meta name="robots" content="noindex,nofollow">\n',
1051
 
     "Additional <HEAD> tags for requests with query strings, like actions."),
1052
 
    ('html_head_posts', '<meta name="robots" content="noindex,nofollow">\n',
1053
 
     "Additional <HEAD> tags for POST requests."),
1054
 
    ('html_head_index', '<meta name="robots" content="index,follow">\n',
1055
 
     "Additional <HEAD> tags for some few index pages."),
1056
 
    ('html_head_normal', '<meta name="robots" content="index,nofollow">\n',
1057
 
     "Additional <HEAD> tags for most normal pages."),
1058
 
 
1059
 
    ('language_default', 'en', "Default language for user interface and page content, see HelpOnLanguages."),
1060
 
    ('language_ignore_browser', False, "if True, ignore user's browser language settings, see HelpOnLanguages."),
1061
 
 
1062
 
    ('log_remote_addr', True,
1063
 
     "if True, log the remote IP address (and maybe hostname)."),
1064
 
    ('log_reverse_dns_lookups', True,
1065
 
     "if True, do a reverse DNS lookup on page SAVE. If your DNS is broken, set this to False to speed up SAVE."),
1066
 
    ('log_timing', False,
1067
 
     "if True, add timing infos to the log output to analyse load conditions"),
1068
 
 
1069
 
    # some dangerous mimetypes (we don't use "content-disposition: inline" for them when a user
1070
 
    # downloads such attachments, because the browser might execute e.g. Javascript contained
1071
 
    # in the HTML and steal your moin session cookie or do other nasty stuff)
1072
 
    ('mimetypes_xss_protect',
1073
 
     [
1074
 
       'text/html',
1075
 
       'application/x-shockwave-flash',
1076
 
       'application/xhtml+xml',
1077
 
     ],
1078
 
     '"content-disposition: inline" isn\'t used for them when a user downloads such attachments'),
1079
 
 
1080
 
    ('mimetypes_embed',
1081
 
     [
1082
 
       'application/x-dvi',
1083
 
       'application/postscript',
1084
 
       'application/pdf',
1085
 
       'application/ogg',
1086
 
       'application/vnd.visio',
1087
 
       'image/x-ms-bmp',
1088
 
       'image/svg+xml',
1089
 
       'image/tiff',
1090
 
       'image/x-photoshop',
1091
 
       'audio/mpeg',
1092
 
       'audio/midi',
1093
 
       'audio/x-wav',
1094
 
       'video/fli',
1095
 
       'video/mpeg',
1096
 
       'video/quicktime',
1097
 
       'video/x-msvideo',
1098
 
       'chemical/x-pdb',
1099
 
       'x-world/x-vrml',
1100
 
     ],
1101
 
     'mimetypes that can be embedded by the [[HelpOnMacros/EmbedObject|EmbedObject macro]]'),
1102
 
 
1103
 
    ('refresh', None,
1104
 
     "refresh = (minimum_delay_s, targets_allowed) enables use of `#refresh 5 PageName` processing instruction, targets_allowed must be either `'internal'` or `'external'`"),
1105
 
    ('rss_cache', 60, "suggested caching time for Recent''''''Changes RSS, in second"),
1106
 
 
1107
 
    ('search_results_per_page', 25, "Number of hits shown per page in the search results"),
1108
 
 
1109
 
    ('siteid', 'default', None),
1110
 
  )),
1111
 
}
1112
 
 
1113
 
#
1114
 
# The 'options' dict carries default MoinMoin options. The dict is a
1115
 
# group name to tuple mapping.
1116
 
# Each group tuple consists of the following items:
1117
 
#   group section heading, group help text, option list
1118
 
#
1119
 
# where each 'option list' is a tuple or list of option tuples
1120
 
#
1121
 
# each option tuple consists of
1122
 
#   option name, default value, help text
1123
 
#
1124
 
# All the help texts will be displayed by the WikiConfigHelp() macro.
1125
 
#
1126
 
# Unlike the options_no_group_name dict, option names in this dict
1127
 
# are automatically prefixed with "group name '_'" (i.e. the name of
1128
 
# the group they are in and an underscore), e.g. the 'hierarchic'
1129
 
# below creates an option called "acl_hierarchic".
1130
 
#
1131
 
# If you need to add a complex default expression that results in an
1132
 
# object and should not be shown in the __repr__ form in WikiConfigHelp(),
1133
 
# you can use the DefaultExpression class, see 'auth' above for example.
1134
 
#
1135
 
#
1136
 
options = {
1137
 
    'acl': ('Access control lists',
1138
 
    'ACLs control who may do what, see HelpOnAccessControlLists.',
1139
 
    (
1140
 
      ('hierarchic', False, 'True to use hierarchical ACLs'),
1141
 
      ('rights_default', u"Trusted:read,write,delete,revert Known:read,write,delete,revert All:read,write",
1142
 
       "ACL used if no ACL is specified on the page"),
1143
 
      ('rights_before', u"",
1144
 
       "ACL that is processed before the on-page/default ACL"),
1145
 
      ('rights_after', u"",
1146
 
       "ACL that is processed after the on-page/default ACL"),
1147
 
      ('rights_valid', ['read', 'write', 'delete', 'revert', 'admin'],
1148
 
       "Valid tokens for right sides of ACL entries."),
1149
 
    )),
1150
 
 
1151
 
    'xapian': ('Xapian search', "Configuration of the Xapian based indexed search, see HelpOnXapian.", (
1152
 
      ('search', False,
1153
 
       "True to enable the fast, indexed search (based on the Xapian search library)"),
1154
 
      ('index_dir', None,
1155
 
       "Directory where the Xapian search index is stored (None = auto-configure wiki local storage)"),
1156
 
      ('stemming', False,
1157
 
       "True to enable Xapian word stemmer usage for indexing / searching."),
1158
 
      ('index_history', False,
1159
 
       "True to enable indexing of non-current page revisions."),
1160
 
    )),
1161
 
 
1162
 
    'user': ('Users / User settings', None, (
1163
 
      ('email_unique', True,
1164
 
       "if True, check email addresses for uniqueness and don't accept duplicates."),
1165
 
      ('jid_unique', True,
1166
 
       "if True, check Jabber IDs for uniqueness and don't accept duplicates."),
1167
 
 
1168
 
      ('homewiki', u'Self',
1169
 
       "interwiki name of the wiki where the user home pages are located [Unicode] - useful if you have ''many'' users. You could even link to nonwiki \"user pages\" if the wiki username is in the target URL."),
1170
 
 
1171
 
      ('checkbox_fields',
1172
 
       [
1173
 
        ('mailto_author', lambda _: _('Publish my email (not my wiki homepage) in author info')),
1174
 
        ('edit_on_doubleclick', lambda _: _('Open editor on double click')),
1175
 
        ('remember_last_visit', lambda _: _('After login, jump to last visited page')),
1176
 
        ('show_comments', lambda _: _('Show comment sections')),
1177
 
        ('show_nonexist_qm', lambda _: _('Show question mark for non-existing pagelinks')),
1178
 
        ('show_page_trail', lambda _: _('Show page trail')),
1179
 
        ('show_toolbar', lambda _: _('Show icon toolbar')),
1180
 
        ('show_topbottom', lambda _: _('Show top/bottom links in headings')),
1181
 
        ('show_fancy_diff', lambda _: _('Show fancy diffs')),
1182
 
        ('wikiname_add_spaces', lambda _: _('Add spaces to displayed wiki names')),
1183
 
        ('remember_me', lambda _: _('Remember login information')),
1184
 
 
1185
 
        ('disabled', lambda _: _('Disable this account forever')),
1186
 
        # if an account is disabled, it may be used for looking up
1187
 
        # id -> username for page info and recent changes, but it
1188
 
        # is not usable for the user any more:
1189
 
       ],
1190
 
       "Describes user preferences, see HelpOnConfiguration/UserPreferences."),
1191
 
 
1192
 
      ('checkbox_defaults',
1193
 
       {
1194
 
        'mailto_author': 0,
1195
 
        'edit_on_doubleclick': 1,
1196
 
        'remember_last_visit': 0,
1197
 
        'show_comments': 0,
1198
 
        'show_nonexist_qm': False,
1199
 
        'show_page_trail': 1,
1200
 
        'show_toolbar': 1,
1201
 
        'show_topbottom': 0,
1202
 
        'show_fancy_diff': 1,
1203
 
        'wikiname_add_spaces': 0,
1204
 
        'remember_me': 1,
1205
 
       },
1206
 
       "Defaults for user preferences, see HelpOnConfiguration/UserPreferences."),
1207
 
 
1208
 
      ('checkbox_disable', [],
1209
 
       "Disable user preferences, see HelpOnConfiguration/UserPreferences."),
1210
 
 
1211
 
      ('checkbox_remove', [],
1212
 
       "Remove user preferences, see HelpOnConfiguration/UserPreferences."),
1213
 
 
1214
 
      ('form_fields',
1215
 
       [
1216
 
        ('name', _('Name'), "text", "36", _("(Use FirstnameLastname)")),
1217
 
        ('aliasname', _('Alias-Name'), "text", "36", ''),
1218
 
        ('email', _('Email'), "text", "36", ''),
1219
 
        ('jid', _('Jabber ID'), "text", "36", ''),
1220
 
        ('css_url', _('User CSS URL'), "text", "40", _('(Leave it empty for disabling user CSS)')),
1221
 
        ('edit_rows', _('Editor size'), "text", "3", ''),
1222
 
       ],
1223
 
       None),
1224
 
 
1225
 
      ('form_defaults',
1226
 
       {# key: default - do NOT remove keys from here!
1227
 
        'name': '',
1228
 
        'aliasname': '',
1229
 
        'password': '',
1230
 
        'password2': '',
1231
 
        'email': '',
1232
 
        'jid': '',
1233
 
        'css_url': '',
1234
 
        'edit_rows': "20",
1235
 
       },
1236
 
       None),
1237
 
 
1238
 
      ('form_disable', [], "list of field names used to disable user preferences form fields"),
1239
 
 
1240
 
      ('form_remove', [], "list of field names used to remove user preferences form fields"),
1241
 
 
1242
 
      ('transient_fields',
1243
 
       ['id', 'valid', 'may', 'auth_username', 'password', 'password2', 'auth_method', 'auth_attribs', ],
1244
 
       "User object attributes that are not persisted to permanent storage (internal use)."),
1245
 
    )),
1246
 
 
1247
 
    'openidrp': ('OpenID Relying Party',
1248
 
        'These settings control the built-in OpenID Relying Party (client).',
1249
 
    (
1250
 
      ('allowed_op', [], "List of forced providers"),
1251
 
    )),
1252
 
 
1253
 
    'openid_server': ('OpenID Server',
1254
 
        'These settings control the built-in OpenID Identity Provider (server).',
1255
 
    (
1256
 
      ('enabled', False, "True to enable the built-in OpenID server."),
1257
 
      ('restricted_users_group', None, "If set to a group name, the group members are allowed to use the wiki as an OpenID provider. (None = allow for all users)"),
1258
 
      ('enable_user', False, "If True, the OpenIDUser processing instruction is allowed."),
1259
 
    )),
1260
 
 
1261
 
    'mail': ('Mail settings',
1262
 
        'These settings control outgoing and incoming email from and to the wiki.',
1263
 
    (
1264
 
      ('from', None, "Used as From: address for generated mail."),
1265
 
      ('login', None, "'username userpass' for SMTP server authentication (None = don't use auth)."),
1266
 
      ('smarthost', None, "Address of SMTP server to use for sending mail (None = don't use SMTP server)."),
1267
 
      ('sendmail', None, "sendmail command to use for sending mail (None = don't use sendmail)"),
1268
 
 
1269
 
      ('import_subpage_template', u"$from-$date-$subject", "Create subpages using this template when importing mail."),
1270
 
      ('import_pagename_search', ['subject', 'to', ], "Where to look for target pagename specification."),
1271
 
      ('import_pagename_envelope', u"%s", "Use this to add some fixed prefix/postfix to the generated target pagename."),
1272
 
      ('import_pagename_regex', r'\[\[([^\]]*)\]\]', "Regular expression used to search for target pagename specification."),
1273
 
      ('import_wiki_addrs', [], "Target mail addresses to consider when importing mail"),
1274
 
    )),
1275
 
 
1276
 
    'backup': ('Backup settings',
1277
 
        'These settings control how the backup action works and who is allowed to use it.',
1278
 
    (
1279
 
      ('compression', 'gz', 'What compression to use for the backup ("gz" or "bz2").'),
1280
 
      ('users', [], 'List of trusted user names who are allowed to get a backup.'),
1281
 
      ('include', [], 'List of pathes to backup.'),
1282
 
      ('exclude', lambda self, filename: False, 'Function f(self, filename) that tells whether a file should be excluded from backup. By default, nothing is excluded.'),
1283
 
    )),
1284
 
}
1285
 
 
1286
 
def _add_options_to_defconfig(opts, addgroup=True):
1287
 
    for groupname in opts:
1288
 
        group_short, group_doc, group_opts = opts[groupname]
1289
 
        for name, default, doc in group_opts:
1290
 
            if addgroup:
1291
 
                name = groupname + '_' + name
1292
 
            if isinstance(default, DefaultExpression):
1293
 
                default = default.value
1294
 
            setattr(DefaultConfig, name, default)
1295
 
 
1296
 
_add_options_to_defconfig(options)
1297
 
_add_options_to_defconfig(options_no_group_name, False)
1298
 
 
1299
1075
# remove the gettext pseudo function
1300
1076
del _
1301
1077