[wiki-lenny/share/] Hacking sauvage de MoinMoin fonctionnel
Plusieurs fichiers ont été sauvagement hacké pour que MoiMoin ait le comportement que l'on attend de lui au Cr@ns. * PageGraphicalEditor.py --- Pour interdire l'éditeur graphique sur certains pages * action/newaccount.py --- Pour interdre la création de compte depuis l'extérieur * formatter/__init__.py --- Pour pouvoir afficher des boîtes dans les différents formatters... * formatter/text_html.py --- ... ce qui n'est implémenté que dans le formatteur html pour l'instant. * security/__init__.py --- Pour n'autoriser l'accès en lecture qu'aux pages publiques depuis l'extérieur. darcs-hash:20081109154331-bd074-0c8a84ce7016e8a1ebe63795d377fe91065cb0b8.gz
This commit is contained in:
parent
73e1af5309
commit
cd5d080e49
10 changed files with 4410 additions and 0 deletions
411
wiki-lenny/share/PageGraphicalEditor.orig.py
Normal file
411
wiki-lenny/share/PageGraphicalEditor.orig.py
Normal file
|
@ -0,0 +1,411 @@
|
|||
# -*- coding: iso-8859-1 -*-
|
||||
"""
|
||||
MoinMoin - Call the GUI editor (FCKeditor)
|
||||
|
||||
Same as PageEditor, but we use the HTML based GUI editor here.
|
||||
|
||||
TODO:
|
||||
* see PageEditor.py
|
||||
|
||||
@copyright: 2006 Bastian Blank, Florian Festi,
|
||||
2006-2007 MoinMoin:ThomasWaldmann
|
||||
@license: GNU GPL, see COPYING for details.
|
||||
"""
|
||||
import re
|
||||
|
||||
from MoinMoin import PageEditor
|
||||
from MoinMoin import wikiutil
|
||||
from MoinMoin.Page import Page
|
||||
from MoinMoin.widget import html
|
||||
from MoinMoin.widget.dialog import Status
|
||||
from MoinMoin.util import web
|
||||
from MoinMoin.parser.text_moin_wiki import Parser as WikiParser
|
||||
|
||||
def execute(pagename, request):
|
||||
if not request.user.may.write(pagename):
|
||||
_ = request.getText
|
||||
request.theme.add_msg_('You are not allowed to edit this page.', "error")
|
||||
Page(request, pagename).send_page()
|
||||
return
|
||||
|
||||
PageGraphicalEditor(request, pagename).sendEditor()
|
||||
|
||||
|
||||
class PageGraphicalEditor(PageEditor.PageEditor):
|
||||
""" Same as PageEditor, but use the GUI editor (FCKeditor) """
|
||||
def word_rule(self):
|
||||
regex = re.compile(r"\(\?<![^)]*?\)")
|
||||
word_rule = regex.sub("", WikiParser.word_rule_js)
|
||||
return repr(word_rule)[1:]
|
||||
|
||||
def sendEditor(self, **kw):
|
||||
""" Send the editor form page.
|
||||
|
||||
@keyword preview: if given, show this text in preview mode
|
||||
@keyword staytop: don't go to #preview
|
||||
@keyword comment: comment field (when preview is true)
|
||||
"""
|
||||
from MoinMoin import i18n
|
||||
from MoinMoin.action import SpellCheck
|
||||
|
||||
request = self.request
|
||||
form = request.form
|
||||
_ = self._
|
||||
request.disableHttpCaching(level=2)
|
||||
request.emit_http_headers()
|
||||
|
||||
raw_body = ''
|
||||
msg = None
|
||||
conflict_msg = None
|
||||
edit_lock_message = None
|
||||
preview = kw.get('preview', None)
|
||||
staytop = kw.get('staytop', 0)
|
||||
|
||||
# check edit permissions
|
||||
if not request.user.may.write(self.page_name):
|
||||
msg = _('You are not allowed to edit this page.')
|
||||
elif not self.isWritable():
|
||||
msg = _('Page is immutable!')
|
||||
elif self.rev:
|
||||
# Trying to edit an old version, this is not possible via
|
||||
# the web interface, but catch it just in case...
|
||||
msg = _('Cannot edit old revisions!')
|
||||
else:
|
||||
# try to acquire edit lock
|
||||
ok, edit_lock_message = self.lock.acquire()
|
||||
if not ok:
|
||||
# failed to get the lock
|
||||
if preview is not None:
|
||||
edit_lock_message = _('The lock you held timed out. Be prepared for editing conflicts!'
|
||||
) + "<br>" + edit_lock_message
|
||||
else:
|
||||
msg = edit_lock_message
|
||||
|
||||
# Did one of the prechecks fail?
|
||||
if msg:
|
||||
request.theme.add_msg(msg, "error")
|
||||
self.send_page()
|
||||
return
|
||||
|
||||
# check if we want to load a draft
|
||||
use_draft = None
|
||||
if 'button_load_draft' in form:
|
||||
wanted_draft_timestamp = int(form.get('draft_ts', ['0'])[0])
|
||||
if wanted_draft_timestamp:
|
||||
draft = self._load_draft()
|
||||
if draft is not None:
|
||||
draft_timestamp, draft_rev, draft_text = draft
|
||||
if draft_timestamp == wanted_draft_timestamp:
|
||||
use_draft = draft_text
|
||||
|
||||
# Check for draft / normal / preview submit
|
||||
if use_draft is not None:
|
||||
title = _('Draft of "%(pagename)s"')
|
||||
# Propagate original revision
|
||||
rev = int(form['draft_rev'][0])
|
||||
self.set_raw_body(use_draft, modified=1)
|
||||
preview = use_draft
|
||||
elif preview is None:
|
||||
title = _('Edit "%(pagename)s"')
|
||||
else:
|
||||
title = _('Preview of "%(pagename)s"')
|
||||
# Propagate original revision
|
||||
rev = request.rev
|
||||
self.set_raw_body(preview, modified=1)
|
||||
|
||||
# send header stuff
|
||||
lock_timeout = self.lock.timeout / 60
|
||||
lock_page = wikiutil.escape(self.page_name, quote=1)
|
||||
lock_expire = _("Your edit lock on %(lock_page)s has expired!") % {'lock_page': lock_page}
|
||||
lock_mins = _("Your edit lock on %(lock_page)s will expire in # minutes.") % {'lock_page': lock_page}
|
||||
lock_secs = _("Your edit lock on %(lock_page)s will expire in # seconds.") % {'lock_page': lock_page}
|
||||
|
||||
# get request parameters
|
||||
try:
|
||||
text_rows = int(form['rows'][0])
|
||||
except StandardError:
|
||||
text_rows = self.cfg.edit_rows
|
||||
if request.user.valid:
|
||||
text_rows = int(request.user.edit_rows)
|
||||
|
||||
if preview is not None:
|
||||
# Check for editing conflicts
|
||||
if not self.exists():
|
||||
# page does not exist, are we creating it?
|
||||
if rev:
|
||||
conflict_msg = _('Someone else deleted this page while you were editing!')
|
||||
elif rev != self.current_rev():
|
||||
conflict_msg = _('Someone else changed this page while you were editing!')
|
||||
if self.mergeEditConflict(rev):
|
||||
conflict_msg = _("""Someone else saved this page while you were editing!
|
||||
Please review the page and save then. Do not save this page as it is!""")
|
||||
rev = self.current_rev()
|
||||
if conflict_msg:
|
||||
# We don't show preview when in conflict
|
||||
preview = None
|
||||
|
||||
elif self.exists():
|
||||
# revision of existing page
|
||||
rev = self.current_rev()
|
||||
else:
|
||||
# page creation
|
||||
rev = 0
|
||||
|
||||
self.setConflict(bool(conflict_msg))
|
||||
|
||||
# Page editing is done using user language
|
||||
request.setContentLanguage(request.lang)
|
||||
|
||||
# Get the text body for the editor field.
|
||||
# TODO: what about deleted pages? show the text of the last revision or use the template?
|
||||
if preview is not None:
|
||||
raw_body = self.get_raw_body()
|
||||
if use_draft:
|
||||
request.write(_("[Content loaded from draft]"), '<br>')
|
||||
elif self.exists():
|
||||
# If the page exists, we get the text from the page.
|
||||
# TODO: maybe warn if template argument was ignored because the page exists?
|
||||
raw_body = self.get_raw_body()
|
||||
elif 'template' in form:
|
||||
# If the page does not exist, we try to get the content from the template parameter.
|
||||
template_page = wikiutil.unquoteWikiname(form['template'][0])
|
||||
if request.user.may.read(template_page):
|
||||
raw_body = Page(request, template_page).get_raw_body()
|
||||
if raw_body:
|
||||
request.write(_("[Content of new page loaded from %s]") % (template_page, ), '<br>')
|
||||
else:
|
||||
request.write(_("[Template %s not found]") % (template_page, ), '<br>')
|
||||
else:
|
||||
request.write(_("[You may not read %s]") % (template_page, ), '<br>')
|
||||
|
||||
# Make backup on previews - but not for new empty pages
|
||||
if not use_draft and preview and raw_body:
|
||||
self._save_draft(raw_body, rev)
|
||||
|
||||
draft_message = None
|
||||
loadable_draft = False
|
||||
if preview is None:
|
||||
draft = self._load_draft()
|
||||
if draft is not None:
|
||||
draft_timestamp, draft_rev, draft_text = draft
|
||||
if draft_text != raw_body:
|
||||
loadable_draft = True
|
||||
page_rev = rev
|
||||
draft_timestamp_str = request.user.getFormattedDateTime(draft_timestamp)
|
||||
draft_message = _(u"'''<<BR>>Your draft based on revision %(draft_rev)d (saved %(draft_timestamp_str)s) can be loaded instead of the current revision %(page_rev)d by using the load draft button - in case you lost your last edit somehow without saving it.''' A draft gets saved for you when you do a preview, cancel an edit or unsuccessfully save.", wiki=True, percent=True) % locals()
|
||||
|
||||
# Setup status message
|
||||
status = [kw.get('msg', ''), conflict_msg, edit_lock_message, draft_message]
|
||||
status = [msg for msg in status if msg]
|
||||
status = ' '.join(status)
|
||||
status = Status(request, content=status)
|
||||
|
||||
request.theme.add_msg(status, "error")
|
||||
request.theme.send_title(
|
||||
title % {'pagename': self.split_title(), },
|
||||
page=self,
|
||||
html_head=self.lock.locktype and (
|
||||
PageEditor._countdown_js % {
|
||||
'countdown_script': request.theme.externalScript('countdown'),
|
||||
'lock_timeout': lock_timeout,
|
||||
'lock_expire': lock_expire,
|
||||
'lock_mins': lock_mins,
|
||||
'lock_secs': lock_secs,
|
||||
}) or '',
|
||||
editor_mode=1,
|
||||
)
|
||||
|
||||
request.write(request.formatter.startContent("content"))
|
||||
|
||||
# Generate default content for new pages
|
||||
if not raw_body:
|
||||
raw_body = _('Describe %s here.') % (self.page_name, )
|
||||
|
||||
# send form
|
||||
request.write('<form id="editor" method="post" action="%s/%s#preview">' % (
|
||||
request.getScriptname(),
|
||||
wikiutil.quoteWikinameURL(self.page_name),
|
||||
))
|
||||
|
||||
# yet another weird workaround for broken IE6 (it expands the text
|
||||
# editor area to the right after you begin to type...). IE sucks...
|
||||
# http://fplanque.net/2003/Articles/iecsstextarea/
|
||||
request.write('<fieldset style="border:none;padding:0;">')
|
||||
|
||||
request.write(unicode(html.INPUT(type="hidden", name="action", value="edit")))
|
||||
|
||||
# Send revision of the page our edit is based on
|
||||
request.write('<input type="hidden" name="rev" value="%d">' % (rev, ))
|
||||
|
||||
# Add src format (e.g. 'wiki') into a hidden form field, so that
|
||||
# we can load the correct converter after POSTing.
|
||||
request.write('<input type="hidden" name="format" value="%s">' % self.pi['format'])
|
||||
|
||||
# Create and send a ticket, so we can check the POST
|
||||
request.write('<input type="hidden" name="ticket" value="%s">' % wikiutil.createTicket(request))
|
||||
|
||||
# Save backto in a hidden input
|
||||
backto = form.get('backto', [None])[0]
|
||||
if backto:
|
||||
request.write(unicode(html.INPUT(type="hidden", name="backto", value=backto)))
|
||||
|
||||
# button bar
|
||||
button_spellcheck = '<input class="button" type="submit" name="button_spellcheck" value="%s">' % _('Check Spelling')
|
||||
|
||||
save_button_text = _('Save Changes')
|
||||
cancel_button_text = _('Cancel')
|
||||
|
||||
if self.cfg.page_license_enabled:
|
||||
request.write('<p><em>', _(
|
||||
"""By hitting '''%(save_button_text)s''' you put your changes under the %(license_link)s.
|
||||
If you don't want that, hit '''%(cancel_button_text)s''' to cancel your changes.""", wiki=True) % {
|
||||
'save_button_text': save_button_text,
|
||||
'cancel_button_text': cancel_button_text,
|
||||
'license_link': wikiutil.getLocalizedPage(request, self.cfg.page_license_page).link_to(request),
|
||||
}, '</em></p>')
|
||||
|
||||
request.write('''
|
||||
<input class="button" type="submit" name="button_save" value="%s">
|
||||
<input class="button" type="submit" name="button_preview" value="%s">
|
||||
<input class="button" type="submit" name="button_switch" value="%s">
|
||||
''' % (save_button_text, _('Preview'), _('Text mode'), ))
|
||||
|
||||
if loadable_draft:
|
||||
request.write('''
|
||||
<input class="button" type="submit" name="button_load_draft" value="%s" onClick="flgChange = false;">
|
||||
<input type="hidden" name="draft_ts" value="%d">
|
||||
<input type="hidden" name="draft_rev" value="%d">
|
||||
''' % (_('Load Draft'), draft_timestamp, draft_rev))
|
||||
|
||||
request.write('''
|
||||
%s
|
||||
<input class="button" type="submit" name="button_cancel" value="%s">
|
||||
<input type="hidden" name="editor" value="gui">
|
||||
''' % (button_spellcheck, cancel_button_text, ))
|
||||
if self.cfg.mail_enabled:
|
||||
request.write('''
|
||||
<script type="text/javascript">
|
||||
function toggle_trivial(CheckedBox)
|
||||
{
|
||||
TrivialBoxes = document.getElementsByName("trivial");
|
||||
for (var i = 0; i < TrivialBoxes.length; i++)
|
||||
TrivialBoxes[i].checked = CheckedBox.checked;
|
||||
}
|
||||
</script>
|
||||
|
||||
<input type="checkbox" name="trivial" id="chktrivialtop" value="1" %(checked)s onclick="toggle_trivial(this)">
|
||||
<label for="chktrivialtop">%(label)s</label>
|
||||
''' % {
|
||||
'checked': ('', 'checked')[form.get('trivial', ['0'])[0] == '1'],
|
||||
'label': _("Trivial change"),
|
||||
})
|
||||
|
||||
from MoinMoin.security.textcha import TextCha
|
||||
request.write(TextCha(request).render())
|
||||
|
||||
self.sendconfirmleaving() # TODO update state of flgChange to make this work, see PageEditor
|
||||
|
||||
# Add textarea with page text
|
||||
lang = self.pi.get('language', request.cfg.language_default)
|
||||
contentlangdirection = i18n.getDirection(lang) # 'ltr' or 'rtl'
|
||||
uilanguage = request.lang
|
||||
url_prefix_static = request.cfg.url_prefix_static
|
||||
url_prefix_local = request.cfg.url_prefix_local
|
||||
wikipage = wikiutil.quoteWikinameURL(self.page_name)
|
||||
fckbasepath = url_prefix_local + '/applets/FCKeditor'
|
||||
wikiurl = request.getScriptname()
|
||||
if not wikiurl or wikiurl[-1] != '/':
|
||||
wikiurl += '/'
|
||||
themepath = '%s/%s' % (url_prefix_static, request.theme.name)
|
||||
smileypath = themepath + '/img'
|
||||
# auto-generating a list for SmileyImages does NOT work from here!
|
||||
editor_size = int(request.user.edit_rows) * 22 # 22 height_pixels/line
|
||||
word_rule = self.word_rule()
|
||||
|
||||
request.write("""
|
||||
<script type="text/javascript" src="%(fckbasepath)s/fckeditor.js"></script>
|
||||
<script type="text/javascript">
|
||||
<!--
|
||||
var oFCKeditor = new FCKeditor( 'savetext', '100%%', %(editor_size)s, 'MoinDefault' ) ;
|
||||
oFCKeditor.BasePath= '%(fckbasepath)s/' ;
|
||||
oFCKeditor.Config['WikiBasePath'] = '%(wikiurl)s' ;
|
||||
oFCKeditor.Config['WikiPage'] = '%(wikipage)s' ;
|
||||
oFCKeditor.Config['PluginsPath'] = '%(url_prefix_local)s/applets/moinFCKplugins/' ;
|
||||
oFCKeditor.Config['CustomConfigurationsPath'] = '%(url_prefix_local)s/applets/moinfckconfig.js' ;
|
||||
oFCKeditor.Config['WordRule'] = %(word_rule)s ;
|
||||
oFCKeditor.Config['SmileyPath'] = '%(smileypath)s/' ;
|
||||
oFCKeditor.Config['EditorAreaCSS'] = '%(themepath)s/css/common.css' ;
|
||||
oFCKeditor.Config['SkinPath'] = '%(fckbasepath)s/editor/skins/silver/' ;
|
||||
oFCKeditor.Config['AutoDetectLanguage'] = false ;
|
||||
oFCKeditor.Config['DefaultLanguage'] = '%(uilanguage)s' ;
|
||||
oFCKeditor.Config['ContentLangDirection'] = '%(contentlangdirection)s' ;
|
||||
oFCKeditor.Value= """ % locals())
|
||||
|
||||
from MoinMoin.formatter.text_gedit import Formatter
|
||||
self.formatter = Formatter(request)
|
||||
self.formatter.page = self
|
||||
output = request.redirectedOutput(self.send_page_content, request, raw_body, format=self.pi['format'], do_cache=False)
|
||||
output = repr(output)
|
||||
if output[0] == 'u':
|
||||
output = output[1:]
|
||||
request.write(output)
|
||||
request.write(""" ;
|
||||
oFCKeditor.Create() ;
|
||||
//-->
|
||||
</script>
|
||||
""")
|
||||
request.write("<p>")
|
||||
request.write(_("Comment:"),
|
||||
' <input id="editor-comment" type="text" name="comment" value="%s" size="80" maxlength="200">' % (
|
||||
wikiutil.escape(kw.get('comment', ''), 1), ))
|
||||
request.write("</p>")
|
||||
|
||||
# Category selection
|
||||
filterfn = self.cfg.cache.page_category_regexact.search
|
||||
cat_pages = request.rootpage.getPageList(filter=filterfn)
|
||||
cat_pages.sort()
|
||||
cat_pages = [wikiutil.pagelinkmarkup(p) for p in cat_pages]
|
||||
cat_pages.insert(0, ('', _('<No addition>')))
|
||||
request.write("<p>")
|
||||
request.write(_('Add to: %(category)s') % {
|
||||
'category': unicode(web.makeSelection('category', cat_pages)),
|
||||
})
|
||||
if self.cfg.mail_enabled:
|
||||
request.write('''
|
||||
|
||||
<input type="checkbox" name="trivial" id="chktrivial" value="1" %(checked)s onclick="toggle_trivial(this)">
|
||||
<label for="chktrivial">%(label)s</label> ''' % {
|
||||
'checked': ('', 'checked')[form.get('trivial', ['0'])[0] == '1'],
|
||||
'label': _("Trivial change"),
|
||||
})
|
||||
|
||||
request.write('''
|
||||
|
||||
<input type="checkbox" name="rstrip" id="chkrstrip" value="1" %(checked)s>
|
||||
<label for="chkrstrip">%(label)s</label>
|
||||
</p> ''' % {
|
||||
'checked': ('', 'checked')[form.get('rstrip', ['0'])[0] == '1'],
|
||||
'label': _('Remove trailing whitespace from each line')
|
||||
})
|
||||
|
||||
request.write("</p>")
|
||||
|
||||
badwords_re = None
|
||||
if preview is not None:
|
||||
if 'button_spellcheck' in form or 'button_newwords' in form:
|
||||
badwords, badwords_re, msg = SpellCheck.checkSpelling(self, request, own_form=0)
|
||||
request.write("<p>%s</p>" % msg)
|
||||
request.write('</fieldset>')
|
||||
request.write("</form>")
|
||||
|
||||
if preview is not None:
|
||||
if staytop:
|
||||
content_id = 'previewbelow'
|
||||
else:
|
||||
content_id = 'preview'
|
||||
self.send_page(content_id=content_id, content_only=1, hilite_re=badwords_re)
|
||||
|
||||
request.write(request.formatter.endContent()) # end content div
|
||||
request.theme.send_footer(self.page_name)
|
||||
request.theme.send_closing_html()
|
||||
|
428
wiki-lenny/share/PageGraphicalEditor.py
Normal file
428
wiki-lenny/share/PageGraphicalEditor.py
Normal file
|
@ -0,0 +1,428 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
MoinMoin - Call the GUI editor (FCKeditor)
|
||||
|
||||
Same as PageEditor, but we use the HTML based GUI editor here.
|
||||
|
||||
TODO:
|
||||
* see PageEditor.py
|
||||
|
||||
@copyright: 2006 Bastian Blank, Florian Festi,
|
||||
2006-2007 MoinMoin:ThomasWaldmann
|
||||
@license: GNU GPL, see COPYING for details.
|
||||
"""
|
||||
import re
|
||||
|
||||
from MoinMoin import PageEditor
|
||||
from MoinMoin import wikiutil
|
||||
from MoinMoin.Page import Page
|
||||
from MoinMoin.widget import html
|
||||
from MoinMoin.widget.dialog import Status
|
||||
from MoinMoin.util import web
|
||||
from MoinMoin.parser.text_moin_wiki import Parser as WikiParser
|
||||
|
||||
def execute(pagename, request):
|
||||
if not request.user.may.write(pagename):
|
||||
_ = request.getText
|
||||
request.theme.add_msg_('You are not allowed to edit this page.', "error")
|
||||
Page(request, pagename).send_page()
|
||||
return
|
||||
|
||||
PageGraphicalEditor(request, pagename).sendEditor()
|
||||
|
||||
|
||||
class PageGraphicalEditor(PageEditor.PageEditor):
|
||||
""" Same as PageEditor, but use the GUI editor (FCKeditor) """
|
||||
def word_rule(self):
|
||||
regex = re.compile(r"\(\?<![^)]*?\)")
|
||||
word_rule = regex.sub("", WikiParser.word_rule_js)
|
||||
return repr(word_rule)[1:]
|
||||
|
||||
def sendEditor(self, **kw):
|
||||
""" Send the editor form page.
|
||||
|
||||
@keyword preview: if given, show this text in preview mode
|
||||
@keyword staytop: don't go to #preview
|
||||
@keyword comment: comment field (when preview is true)
|
||||
"""
|
||||
from MoinMoin import i18n
|
||||
from MoinMoin.action import SpellCheck
|
||||
|
||||
request = self.request
|
||||
form = request.form
|
||||
_ = self._
|
||||
request.disableHttpCaching(level=2)
|
||||
page_categories = self.getCategories(request)
|
||||
|
||||
|
||||
raw_body = ''
|
||||
msg = None
|
||||
conflict_msg = None
|
||||
edit_lock_message = None
|
||||
preview = kw.get('preview', None)
|
||||
staytop = kw.get('staytop', 0)
|
||||
|
||||
# check edit permissions
|
||||
if not request.user.may.write(self.page_name):
|
||||
# L'effet de bord dans le test empêche-t-il la ligne suivante
|
||||
# d'être exécutée ?
|
||||
msg = _('You are not allowed to edit this page.')
|
||||
elif not self.isWritable():
|
||||
# même remarque.
|
||||
msg = _('Page is immutable!')
|
||||
elif self.rev:
|
||||
# Trying to edit an old version, this is not possible via
|
||||
# the web interface, but catch it just in case...
|
||||
msg = _('Cannot edit old revisions!')
|
||||
elif u"CatégorieEditeurGraphiqueInterdit" in page_categories:
|
||||
msg =_('Cannot edit this page with the graphical editor')
|
||||
request.theme.add_msg(msg, "error")
|
||||
from MoinMoin.PageEditor import PageTextEditor
|
||||
# Pour éviter à l'utilisateur de rester sur le cul, on le
|
||||
# redirige vers l'éditeur texte
|
||||
pg = PageTextEditor(request, self.page_name, **kw)
|
||||
pg.sendEditor()
|
||||
else:
|
||||
# try to acquire edit lock
|
||||
ok, edit_lock_message = self.lock.acquire()
|
||||
if not ok:
|
||||
# failed to get the lock
|
||||
if preview is not None:
|
||||
edit_lock_message = _('The lock you held timed out. Be prepared for editing conflicts!'
|
||||
) + "<br>" + edit_lock_message
|
||||
else:
|
||||
msg = edit_lock_message
|
||||
|
||||
# Did one of the prechecks fail?
|
||||
if msg:
|
||||
request.theme.add_msg(msg, "error")
|
||||
# Il est manifestement hors de question d'avoir envoyé les
|
||||
# headers http avant d'appeler cette fonction
|
||||
self.send_page()
|
||||
return
|
||||
|
||||
# par contre, il faut les envoyer dans le cas contraire
|
||||
request.emit_http_headers()
|
||||
|
||||
# check if we want to load a draft
|
||||
use_draft = None
|
||||
if 'button_load_draft' in form:
|
||||
wanted_draft_timestamp = int(form.get('draft_ts', ['0'])[0])
|
||||
if wanted_draft_timestamp:
|
||||
draft = self._load_draft()
|
||||
if draft is not None:
|
||||
draft_timestamp, draft_rev, draft_text = draft
|
||||
if draft_timestamp == wanted_draft_timestamp:
|
||||
use_draft = draft_text
|
||||
|
||||
# Check for draft / normal / preview submit
|
||||
if use_draft is not None:
|
||||
title = _('Draft of "%(pagename)s"')
|
||||
# Propagate original revision
|
||||
rev = int(form['draft_rev'][0])
|
||||
self.set_raw_body(use_draft, modified=1)
|
||||
preview = use_draft
|
||||
elif preview is None:
|
||||
title = _('Edit "%(pagename)s"')
|
||||
else:
|
||||
title = _('Preview of "%(pagename)s"')
|
||||
# Propagate original revision
|
||||
rev = request.rev
|
||||
self.set_raw_body(preview, modified=1)
|
||||
|
||||
# send header stuff
|
||||
lock_timeout = self.lock.timeout / 60
|
||||
lock_page = wikiutil.escape(self.page_name, quote=1)
|
||||
lock_expire = _("Your edit lock on %(lock_page)s has expired!") % {'lock_page': lock_page}
|
||||
lock_mins = _("Your edit lock on %(lock_page)s will expire in # minutes.") % {'lock_page': lock_page}
|
||||
lock_secs = _("Your edit lock on %(lock_page)s will expire in # seconds.") % {'lock_page': lock_page}
|
||||
|
||||
# get request parameters
|
||||
try:
|
||||
text_rows = int(form['rows'][0])
|
||||
except StandardError:
|
||||
text_rows = self.cfg.edit_rows
|
||||
if request.user.valid:
|
||||
text_rows = int(request.user.edit_rows)
|
||||
|
||||
if preview is not None:
|
||||
# Check for editing conflicts
|
||||
if not self.exists():
|
||||
# page does not exist, are we creating it?
|
||||
if rev:
|
||||
conflict_msg = _('Someone else deleted this page while you were editing!')
|
||||
elif rev != self.current_rev():
|
||||
conflict_msg = _('Someone else changed this page while you were editing!')
|
||||
if self.mergeEditConflict(rev):
|
||||
conflict_msg = _("""Someone else saved this page while you were editing!
|
||||
Please review the page and save then. Do not save this page as it is!""")
|
||||
rev = self.current_rev()
|
||||
if conflict_msg:
|
||||
# We don't show preview when in conflict
|
||||
preview = None
|
||||
|
||||
elif self.exists():
|
||||
# revision of existing page
|
||||
rev = self.current_rev()
|
||||
else:
|
||||
# page creation
|
||||
rev = 0
|
||||
|
||||
self.setConflict(bool(conflict_msg))
|
||||
|
||||
# Page editing is done using user language
|
||||
request.setContentLanguage(request.lang)
|
||||
|
||||
# Get the text body for the editor field.
|
||||
# TODO: what about deleted pages? show the text of the last revision or use the template?
|
||||
if preview is not None:
|
||||
raw_body = self.get_raw_body()
|
||||
if use_draft:
|
||||
request.write(_("[Content loaded from draft]"), '<br>')
|
||||
elif self.exists():
|
||||
# If the page exists, we get the text from the page.
|
||||
# TODO: maybe warn if template argument was ignored because the page exists?
|
||||
raw_body = self.get_raw_body()
|
||||
elif 'template' in form:
|
||||
# If the page does not exist, we try to get the content from the template parameter.
|
||||
template_page = wikiutil.unquoteWikiname(form['template'][0])
|
||||
if request.user.may.read(template_page):
|
||||
raw_body = Page(request, template_page).get_raw_body()
|
||||
if raw_body:
|
||||
request.write(_("[Content of new page loaded from %s]") % (template_page, ), '<br>')
|
||||
else:
|
||||
request.write(_("[Template %s not found]") % (template_page, ), '<br>')
|
||||
else:
|
||||
request.write(_("[You may not read %s]") % (template_page, ), '<br>')
|
||||
|
||||
# Make backup on previews - but not for new empty pages
|
||||
if not use_draft and preview and raw_body:
|
||||
self._save_draft(raw_body, rev)
|
||||
|
||||
draft_message = None
|
||||
loadable_draft = False
|
||||
if preview is None:
|
||||
draft = self._load_draft()
|
||||
if draft is not None:
|
||||
draft_timestamp, draft_rev, draft_text = draft
|
||||
if draft_text != raw_body:
|
||||
loadable_draft = True
|
||||
page_rev = rev
|
||||
draft_timestamp_str = request.user.getFormattedDateTime(draft_timestamp)
|
||||
draft_message = _(u"'''<<BR>>Your draft based on revision %(draft_rev)d (saved %(draft_timestamp_str)s) can be loaded instead of the current revision %(page_rev)d by using the load draft button - in case you lost your last edit somehow without saving it.''' A draft gets saved for you when you do a preview, cancel an edit or unsuccessfully save.", wiki=True, percent=True) % locals()
|
||||
|
||||
# Setup status message
|
||||
status = [kw.get('msg', ''), conflict_msg, edit_lock_message, draft_message]
|
||||
status = [msg for msg in status if msg]
|
||||
status = ' '.join(status)
|
||||
status = Status(request, content=status)
|
||||
|
||||
request.theme.add_msg(status, "error")
|
||||
request.theme.send_title(
|
||||
title % {'pagename': self.split_title(), },
|
||||
page=self,
|
||||
html_head=self.lock.locktype and (
|
||||
PageEditor._countdown_js % {
|
||||
'countdown_script': request.theme.externalScript('countdown'),
|
||||
'lock_timeout': lock_timeout,
|
||||
'lock_expire': lock_expire,
|
||||
'lock_mins': lock_mins,
|
||||
'lock_secs': lock_secs,
|
||||
}) or '',
|
||||
editor_mode=1,
|
||||
)
|
||||
|
||||
request.write(request.formatter.startContent("content"))
|
||||
|
||||
# Generate default content for new pages
|
||||
if not raw_body:
|
||||
raw_body = _('Describe %s here.') % (self.page_name, )
|
||||
|
||||
# send form
|
||||
request.write('<form id="editor" method="post" action="%s/%s#preview">' % (
|
||||
request.getScriptname(),
|
||||
wikiutil.quoteWikinameURL(self.page_name),
|
||||
))
|
||||
|
||||
# yet another weird workaround for broken IE6 (it expands the text
|
||||
# editor area to the right after you begin to type...). IE sucks...
|
||||
# http://fplanque.net/2003/Articles/iecsstextarea/
|
||||
request.write('<fieldset style="border:none;padding:0;">')
|
||||
|
||||
request.write(unicode(html.INPUT(type="hidden", name="action", value="edit")))
|
||||
|
||||
# Send revision of the page our edit is based on
|
||||
request.write('<input type="hidden" name="rev" value="%d">' % (rev, ))
|
||||
|
||||
# Add src format (e.g. 'wiki') into a hidden form field, so that
|
||||
# we can load the correct converter after POSTing.
|
||||
request.write('<input type="hidden" name="format" value="%s">' % self.pi['format'])
|
||||
|
||||
# Create and send a ticket, so we can check the POST
|
||||
request.write('<input type="hidden" name="ticket" value="%s">' % wikiutil.createTicket(request))
|
||||
|
||||
# Save backto in a hidden input
|
||||
backto = form.get('backto', [None])[0]
|
||||
if backto:
|
||||
request.write(unicode(html.INPUT(type="hidden", name="backto", value=backto)))
|
||||
|
||||
# button bar
|
||||
button_spellcheck = '<input class="button" type="submit" name="button_spellcheck" value="%s">' % _('Check Spelling')
|
||||
|
||||
save_button_text = _('Save Changes')
|
||||
cancel_button_text = _('Cancel')
|
||||
|
||||
if self.cfg.page_license_enabled:
|
||||
request.write('<p><em>', _(
|
||||
"""By hitting '''%(save_button_text)s''' you put your changes under the %(license_link)s.
|
||||
If you don't want that, hit '''%(cancel_button_text)s''' to cancel your changes.""", wiki=True) % {
|
||||
'save_button_text': save_button_text,
|
||||
'cancel_button_text': cancel_button_text,
|
||||
'license_link': wikiutil.getLocalizedPage(request, self.cfg.page_license_page).link_to(request),
|
||||
}, '</em></p>')
|
||||
|
||||
request.write('''
|
||||
<input class="button" type="submit" name="button_save" value="%s">
|
||||
<input class="button" type="submit" name="button_preview" value="%s">
|
||||
<input class="button" type="submit" name="button_switch" value="%s">
|
||||
''' % (save_button_text, _('Preview'), _('Text mode'), ))
|
||||
|
||||
if loadable_draft:
|
||||
request.write('''
|
||||
<input class="button" type="submit" name="button_load_draft" value="%s" onClick="flgChange = false;">
|
||||
<input type="hidden" name="draft_ts" value="%d">
|
||||
<input type="hidden" name="draft_rev" value="%d">
|
||||
''' % (_('Load Draft'), draft_timestamp, draft_rev))
|
||||
|
||||
request.write('''
|
||||
%s
|
||||
<input class="button" type="submit" name="button_cancel" value="%s">
|
||||
<input type="hidden" name="editor" value="gui">
|
||||
''' % (button_spellcheck, cancel_button_text, ))
|
||||
if self.cfg.mail_enabled:
|
||||
request.write('''
|
||||
<script type="text/javascript">
|
||||
function toggle_trivial(CheckedBox)
|
||||
{
|
||||
TrivialBoxes = document.getElementsByName("trivial");
|
||||
for (var i = 0; i < TrivialBoxes.length; i++)
|
||||
TrivialBoxes[i].checked = CheckedBox.checked;
|
||||
}
|
||||
</script>
|
||||
|
||||
<input type="checkbox" name="trivial" id="chktrivialtop" value="1" %(checked)s onclick="toggle_trivial(this)">
|
||||
<label for="chktrivialtop">%(label)s</label>
|
||||
''' % {
|
||||
'checked': ('', 'checked')[form.get('trivial', ['0'])[0] == '1'],
|
||||
'label': _("Trivial change"),
|
||||
})
|
||||
|
||||
from MoinMoin.security.textcha import TextCha
|
||||
request.write(TextCha(request).render())
|
||||
|
||||
self.sendconfirmleaving() # TODO update state of flgChange to make this work, see PageEditor
|
||||
|
||||
# Add textarea with page text
|
||||
lang = self.pi.get('language', request.cfg.language_default)
|
||||
contentlangdirection = i18n.getDirection(lang) # 'ltr' or 'rtl'
|
||||
uilanguage = request.lang
|
||||
url_prefix_static = request.cfg.url_prefix_static
|
||||
url_prefix_local = request.cfg.url_prefix_local
|
||||
wikipage = wikiutil.quoteWikinameURL(self.page_name)
|
||||
fckbasepath = url_prefix_local + '/applets/FCKeditor'
|
||||
wikiurl = request.getScriptname()
|
||||
if not wikiurl or wikiurl[-1] != '/':
|
||||
wikiurl += '/'
|
||||
themepath = '%s/%s' % (url_prefix_static, request.theme.name)
|
||||
smileypath = themepath + '/img'
|
||||
# auto-generating a list for SmileyImages does NOT work from here!
|
||||
editor_size = int(request.user.edit_rows) * 22 # 22 height_pixels/line
|
||||
word_rule = self.word_rule()
|
||||
|
||||
request.write("""
|
||||
<script type="text/javascript" src="%(fckbasepath)s/fckeditor.js"></script>
|
||||
<script type="text/javascript">
|
||||
<!--
|
||||
var oFCKeditor = new FCKeditor( 'savetext', '100%%', %(editor_size)s, 'MoinDefault' ) ;
|
||||
oFCKeditor.BasePath= '%(fckbasepath)s/' ;
|
||||
oFCKeditor.Config['WikiBasePath'] = '%(wikiurl)s' ;
|
||||
oFCKeditor.Config['WikiPage'] = '%(wikipage)s' ;
|
||||
oFCKeditor.Config['PluginsPath'] = '%(url_prefix_local)s/applets/moinFCKplugins/' ;
|
||||
oFCKeditor.Config['CustomConfigurationsPath'] = '%(url_prefix_local)s/applets/moinfckconfig.js' ;
|
||||
oFCKeditor.Config['WordRule'] = %(word_rule)s ;
|
||||
oFCKeditor.Config['SmileyPath'] = '%(smileypath)s/' ;
|
||||
oFCKeditor.Config['EditorAreaCSS'] = '%(themepath)s/css/common.css' ;
|
||||
oFCKeditor.Config['SkinPath'] = '%(fckbasepath)s/editor/skins/silver/' ;
|
||||
oFCKeditor.Config['AutoDetectLanguage'] = false ;
|
||||
oFCKeditor.Config['DefaultLanguage'] = '%(uilanguage)s' ;
|
||||
oFCKeditor.Config['ContentLangDirection'] = '%(contentlangdirection)s' ;
|
||||
oFCKeditor.Value= """ % locals())
|
||||
|
||||
from MoinMoin.formatter.text_gedit import Formatter
|
||||
self.formatter = Formatter(request)
|
||||
self.formatter.page = self
|
||||
output = request.redirectedOutput(self.send_page_content, request, raw_body, format=self.pi['format'], do_cache=False)
|
||||
output = repr(output)
|
||||
if output[0] == 'u':
|
||||
output = output[1:]
|
||||
request.write(output)
|
||||
request.write(""" ;
|
||||
oFCKeditor.Create() ;
|
||||
//-->
|
||||
</script>
|
||||
""")
|
||||
request.write("<p>")
|
||||
request.write(_("Comment:"),
|
||||
' <input id="editor-comment" type="text" name="comment" value="%s" size="80" maxlength="200">' % (
|
||||
wikiutil.escape(kw.get('comment', ''), 1), ))
|
||||
request.write("</p>")
|
||||
|
||||
# Category selection
|
||||
filterfn = self.cfg.cache.page_category_regexact.search
|
||||
cat_pages = request.rootpage.getPageList(filter=filterfn)
|
||||
cat_pages.sort()
|
||||
cat_pages = [wikiutil.pagelinkmarkup(p) for p in cat_pages]
|
||||
cat_pages.insert(0, ('', _('<No addition>')))
|
||||
request.write("<p>")
|
||||
request.write(_('Add to: %(category)s') % {
|
||||
'category': unicode(web.makeSelection('category', cat_pages)),
|
||||
})
|
||||
if self.cfg.mail_enabled:
|
||||
request.write('''
|
||||
|
||||
<input type="checkbox" name="trivial" id="chktrivial" value="1" %(checked)s onclick="toggle_trivial(this)">
|
||||
<label for="chktrivial">%(label)s</label> ''' % {
|
||||
'checked': ('', 'checked')[form.get('trivial', ['0'])[0] == '1'],
|
||||
'label': _("Trivial change"),
|
||||
})
|
||||
|
||||
request.write('''
|
||||
|
||||
<input type="checkbox" name="rstrip" id="chkrstrip" value="1" %(checked)s>
|
||||
<label for="chkrstrip">%(label)s</label>
|
||||
</p> ''' % {
|
||||
'checked': ('', 'checked')[form.get('rstrip', ['0'])[0] == '1'],
|
||||
'label': _('Remove trailing whitespace from each line')
|
||||
})
|
||||
|
||||
request.write("</p>")
|
||||
|
||||
badwords_re = None
|
||||
if preview is not None:
|
||||
if 'button_spellcheck' in form or 'button_newwords' in form:
|
||||
badwords, badwords_re, msg = SpellCheck.checkSpelling(self, request, own_form=0)
|
||||
request.write("<p>%s</p>" % msg)
|
||||
request.write('</fieldset>')
|
||||
request.write("</form>")
|
||||
|
||||
if preview is not None:
|
||||
if staytop:
|
||||
content_id = 'previewbelow'
|
||||
else:
|
||||
content_id = 'preview'
|
||||
self.send_page(content_id=content_id, content_only=1, hilite_re=badwords_re)
|
||||
|
||||
request.write(request.formatter.endContent()) # end content div
|
||||
request.theme.send_footer(self.page_name)
|
||||
request.theme.send_closing_html()
|
||||
|
187
wiki-lenny/share/action.edit.orig.py
Normal file
187
wiki-lenny/share/action.edit.orig.py
Normal file
|
@ -0,0 +1,187 @@
|
|||
# -*- coding: iso-8859-1 -*-
|
||||
"""
|
||||
MoinMoin - edit a page
|
||||
|
||||
This either calls the text or the GUI page editor.
|
||||
|
||||
@copyright: 2000-2004 Juergen Hermann <jh@web.de>,
|
||||
2006 MoinMoin:ThomasWaldmann
|
||||
@license: GNU GPL, see COPYING for details.
|
||||
"""
|
||||
from MoinMoin import wikiutil
|
||||
from MoinMoin.Page import Page
|
||||
|
||||
def execute(pagename, request):
|
||||
""" edit a page """
|
||||
_ = request.getText
|
||||
|
||||
if 'button_preview' in request.form and 'button_spellcheck' in request.form:
|
||||
# multiple buttons pressed at once? must be some spammer/bot
|
||||
request.makeForbidden403()
|
||||
request.surge_protect(kick_him=True) # get rid of him
|
||||
return
|
||||
|
||||
if not request.user.may.write(pagename):
|
||||
request.theme.add_msg(_('You are not allowed to edit this page.'), "error")
|
||||
Page(request, pagename).send_page()
|
||||
return
|
||||
|
||||
valideditors = ['text', 'gui', ]
|
||||
editor = ''
|
||||
if request.user.valid:
|
||||
editor = request.user.editor_default
|
||||
if editor not in valideditors:
|
||||
editor = request.cfg.editor_default
|
||||
|
||||
editorparam = request.form.get('editor', [editor])[0]
|
||||
if editorparam == "guipossible":
|
||||
lasteditor = editor
|
||||
elif editorparam == "textonly":
|
||||
editor = lasteditor = 'text'
|
||||
else:
|
||||
editor = lasteditor = editorparam
|
||||
|
||||
if request.cfg.editor_force:
|
||||
editor = request.cfg.editor_default
|
||||
|
||||
# if it is still nothing valid, we just use the text editor
|
||||
if editor not in valideditors:
|
||||
editor = 'text'
|
||||
|
||||
rev = request.rev or 0
|
||||
savetext = request.form.get('savetext', [None])[0]
|
||||
comment = request.form.get('comment', [u''])[0]
|
||||
category = request.form.get('category', [None])[0]
|
||||
rstrip = int(request.form.get('rstrip', ['0'])[0])
|
||||
trivial = int(request.form.get('trivial', ['0'])[0])
|
||||
|
||||
if 'button_switch' in request.form:
|
||||
if editor == 'text':
|
||||
editor = 'gui'
|
||||
else: # 'gui'
|
||||
editor = 'text'
|
||||
|
||||
# load right editor class
|
||||
if editor == 'gui':
|
||||
from MoinMoin.PageGraphicalEditor import PageGraphicalEditor
|
||||
pg = PageGraphicalEditor(request, pagename)
|
||||
else: # 'text'
|
||||
from MoinMoin.PageEditor import PageEditor
|
||||
pg = PageEditor(request, pagename)
|
||||
|
||||
# is invoked without savetext start editing
|
||||
if savetext is None or 'button_load_draft' in request.form:
|
||||
pg.sendEditor()
|
||||
return
|
||||
|
||||
# did user hit cancel button?
|
||||
cancelled = 'button_cancel' in request.form
|
||||
|
||||
if request.cfg.edit_ticketing:
|
||||
ticket = request.form.get('ticket', [''])[0]
|
||||
if not wikiutil.checkTicket(request, ticket):
|
||||
request.theme.add_msg(_('Please use the interactive user interface to use action %(actionname)s!') % {'actionname': 'edit' }, "error")
|
||||
pg.send_page()
|
||||
return
|
||||
|
||||
from MoinMoin.error import ConvertError
|
||||
try:
|
||||
if lasteditor == 'gui':
|
||||
# convert input from Graphical editor
|
||||
format = request.form.get('format', ['wiki'])[0]
|
||||
if format == 'wiki':
|
||||
converter_name = 'text_html_text_moin_wiki'
|
||||
else:
|
||||
converter_name = 'undefined' # XXX we don't have other converters yet
|
||||
convert = wikiutil.importPlugin(request.cfg, "converter", converter_name, 'convert')
|
||||
savetext = convert(request, pagename, savetext)
|
||||
|
||||
# IMPORTANT: normalize text from the form. This should be done in
|
||||
# one place before we manipulate the text.
|
||||
savetext = pg.normalizeText(savetext, stripspaces=rstrip)
|
||||
except ConvertError:
|
||||
# we don't want to throw an exception if user cancelled anyway
|
||||
if not cancelled:
|
||||
raise
|
||||
|
||||
if cancelled:
|
||||
pg.sendCancel(savetext or "", rev)
|
||||
pagedir = pg.getPagePath(check_create=0)
|
||||
import os
|
||||
if not os.listdir(pagedir):
|
||||
os.removedirs(pagedir)
|
||||
return
|
||||
|
||||
comment = wikiutil.clean_input(comment)
|
||||
|
||||
# Add category
|
||||
|
||||
# TODO: this code does not work with extended links, and is doing
|
||||
# things behind your back, and in general not needed. Either we have
|
||||
# a full interface for categories (add, delete) or just add them by
|
||||
# markup.
|
||||
|
||||
if category and category != _('<No addition>'): # opera 8.5 needs this
|
||||
# strip trailing whitespace
|
||||
savetext = savetext.rstrip()
|
||||
|
||||
# Add category separator if last non-empty line contains
|
||||
# non-categories.
|
||||
lines = [line for line in savetext.splitlines() if line]
|
||||
if lines:
|
||||
|
||||
#TODO: this code is broken, will not work for extended links
|
||||
#categories, e.g ["category hebrew"]
|
||||
categories = lines[-1].split()
|
||||
|
||||
if categories:
|
||||
confirmed = wikiutil.filterCategoryPages(request, categories)
|
||||
if len(confirmed) < len(categories):
|
||||
# This was not a categories line, add separator
|
||||
savetext += u'\n----\n'
|
||||
|
||||
# Add new category
|
||||
if savetext and savetext[-1] != u'\n':
|
||||
savetext += ' '
|
||||
savetext += category + u'\n' # Should end with newline!
|
||||
|
||||
# Preview, spellcheck or spellcheck add new words
|
||||
if ('button_preview' in request.form or
|
||||
'button_spellcheck' in request.form or
|
||||
'button_newwords' in request.form):
|
||||
pg.sendEditor(preview=savetext, comment=comment)
|
||||
|
||||
# Preview with mode switch
|
||||
elif 'button_switch' in request.form:
|
||||
pg.sendEditor(preview=savetext, comment=comment, staytop=1)
|
||||
|
||||
# Save new text
|
||||
else:
|
||||
try:
|
||||
from MoinMoin.security.textcha import TextCha
|
||||
if not TextCha(request).check_answer_from_form():
|
||||
raise pg.SaveError(_('TextCha: Wrong answer! Go back and try again...'))
|
||||
savemsg = pg.saveText(savetext, rev, trivial=trivial, comment=comment)
|
||||
except pg.EditConflict, e:
|
||||
msg = e.message
|
||||
|
||||
# Handle conflict and send editor
|
||||
pg.set_raw_body(savetext, modified=1)
|
||||
|
||||
pg.mergeEditConflict(rev)
|
||||
# We don't send preview when we do merge conflict
|
||||
pg.sendEditor(msg=msg, comment=comment)
|
||||
return
|
||||
|
||||
except pg.SaveError, msg:
|
||||
# msg contains a unicode string
|
||||
savemsg = unicode(msg)
|
||||
|
||||
# Send new page after save or after unsuccessful conflict merge.
|
||||
request.reset()
|
||||
pg = Page(request, pagename)
|
||||
|
||||
# sets revision number to default for further actions
|
||||
request.rev = 0
|
||||
request.theme.add_msg(savemsg, "info")
|
||||
pg.send_page()
|
187
wiki-lenny/share/action.edit.py
Normal file
187
wiki-lenny/share/action.edit.py
Normal file
|
@ -0,0 +1,187 @@
|
|||
# -*- coding: iso-8859-1 -*-
|
||||
"""
|
||||
MoinMoin - edit a page
|
||||
|
||||
This either calls the text or the GUI page editor.
|
||||
|
||||
@copyright: 2000-2004 Juergen Hermann <jh@web.de>,
|
||||
2006 MoinMoin:ThomasWaldmann
|
||||
@license: GNU GPL, see COPYING for details.
|
||||
"""
|
||||
from MoinMoin import wikiutil
|
||||
from MoinMoin.Page import Page
|
||||
|
||||
def execute(pagename, request):
|
||||
""" edit a page """
|
||||
_ = request.getText
|
||||
|
||||
if 'button_preview' in request.form and 'button_spellcheck' in request.form:
|
||||
# multiple buttons pressed at once? must be some spammer/bot
|
||||
request.makeForbidden403()
|
||||
request.surge_protect(kick_him=True) # get rid of him
|
||||
return
|
||||
|
||||
if not request.user.may.write(pagename):
|
||||
request.theme.add_msg(_('You are not allowed to edit this page.'), "error")
|
||||
Page(request, pagename).send_page()
|
||||
return
|
||||
|
||||
valideditors = ['text', 'gui', ]
|
||||
editor = ''
|
||||
if request.user.valid:
|
||||
editor = request.user.editor_default
|
||||
if editor not in valideditors:
|
||||
editor = request.cfg.editor_default
|
||||
|
||||
editorparam = request.form.get('editor', [editor])[0]
|
||||
if editorparam == "guipossible":
|
||||
lasteditor = editor
|
||||
elif editorparam == "textonly":
|
||||
editor = lasteditor = 'text'
|
||||
else:
|
||||
editor = lasteditor = editorparam
|
||||
|
||||
if request.cfg.editor_force:
|
||||
editor = request.cfg.editor_default
|
||||
|
||||
# if it is still nothing valid, we just use the text editor
|
||||
if editor not in valideditors:
|
||||
editor = 'text'
|
||||
|
||||
rev = request.rev or 0
|
||||
savetext = request.form.get('savetext', [None])[0]
|
||||
comment = request.form.get('comment', [u''])[0]
|
||||
category = request.form.get('category', [None])[0]
|
||||
rstrip = int(request.form.get('rstrip', ['0'])[0])
|
||||
trivial = int(request.form.get('trivial', ['0'])[0])
|
||||
|
||||
if 'button_switch' in request.form:
|
||||
if editor == 'text':
|
||||
editor = 'gui'
|
||||
else: # 'gui'
|
||||
editor = 'text'
|
||||
|
||||
# load right editor class
|
||||
if editor == 'gui':
|
||||
from MoinMoin.PageGraphicalEditor import PageGraphicalEditor
|
||||
pg = PageGraphicalEditor(request, pagename)
|
||||
else: # 'text'
|
||||
from MoinMoin.PageEditor import PageEditor
|
||||
pg = PageEditor(request, pagename)
|
||||
|
||||
# is invoked without savetext start editing
|
||||
if savetext is None or 'button_load_draft' in request.form:
|
||||
pg.sendEditor()
|
||||
return
|
||||
|
||||
# did user hit cancel button?
|
||||
cancelled = 'button_cancel' in request.form
|
||||
|
||||
if request.cfg.edit_ticketing:
|
||||
ticket = request.form.get('ticket', [''])[0]
|
||||
if not wikiutil.checkTicket(request, ticket):
|
||||
request.theme.add_msg(_('Please use the interactive user interface to use action %(actionname)s!') % {'actionname': 'edit' }, "error")
|
||||
pg.send_page()
|
||||
return
|
||||
|
||||
from MoinMoin.error import ConvertError
|
||||
try:
|
||||
if lasteditor == 'gui':
|
||||
# convert input from Graphical editor
|
||||
format = request.form.get('format', ['wiki'])[0]
|
||||
if format == 'wiki':
|
||||
converter_name = 'text_html_text_moin_wiki'
|
||||
else:
|
||||
converter_name = 'undefined' # XXX we don't have other converters yet
|
||||
convert = wikiutil.importPlugin(request.cfg, "converter", converter_name, 'convert')
|
||||
savetext = convert(request, pagename, savetext)
|
||||
|
||||
# IMPORTANT: normalize text from the form. This should be done in
|
||||
# one place before we manipulate the text.
|
||||
savetext = pg.normalizeText(savetext, stripspaces=rstrip)
|
||||
except ConvertError:
|
||||
# we don't want to throw an exception if user cancelled anyway
|
||||
if not cancelled:
|
||||
raise
|
||||
|
||||
if cancelled:
|
||||
pg.sendCancel(savetext or "", rev)
|
||||
pagedir = pg.getPagePath(check_create=0)
|
||||
import os
|
||||
if not os.listdir(pagedir):
|
||||
os.removedirs(pagedir)
|
||||
return
|
||||
|
||||
comment = wikiutil.clean_input(comment)
|
||||
|
||||
# Add category
|
||||
|
||||
# TODO: this code does not work with extended links, and is doing
|
||||
# things behind your back, and in general not needed. Either we have
|
||||
# a full interface for categories (add, delete) or just add them by
|
||||
# markup.
|
||||
|
||||
if category and category != _('<No addition>'): # opera 8.5 needs this
|
||||
# strip trailing whitespace
|
||||
savetext = savetext.rstrip()
|
||||
|
||||
# Add category separator if last non-empty line contains
|
||||
# non-categories.
|
||||
lines = [line for line in savetext.splitlines() if line]
|
||||
if lines:
|
||||
|
||||
#TODO: this code is broken, will not work for extended links
|
||||
#categories, e.g ["category hebrew"]
|
||||
categories = lines[-1].split()
|
||||
|
||||
if categories:
|
||||
confirmed = wikiutil.filterCategoryPages(request, categories)
|
||||
if len(confirmed) < len(categories):
|
||||
# This was not a categories line, add separator
|
||||
savetext += u'\n----\n'
|
||||
|
||||
# Add new category
|
||||
if savetext and savetext[-1] != u'\n':
|
||||
savetext += ' '
|
||||
savetext += category + u'\n' # Should end with newline!
|
||||
|
||||
# Preview, spellcheck or spellcheck add new words
|
||||
if ('button_preview' in request.form or
|
||||
'button_spellcheck' in request.form or
|
||||
'button_newwords' in request.form):
|
||||
pg.sendEditor(preview=savetext, comment=comment)
|
||||
|
||||
# Preview with mode switch
|
||||
elif 'button_switch' in request.form:
|
||||
pg.sendEditor(preview=savetext, comment=comment, staytop=1)
|
||||
|
||||
# Save new text
|
||||
else:
|
||||
try:
|
||||
from MoinMoin.security.textcha import TextCha
|
||||
if not TextCha(request).check_answer_from_form():
|
||||
raise pg.SaveError(_('TextCha: Wrong answer! Go back and try again...'))
|
||||
savemsg = pg.saveText(savetext, rev, trivial=trivial, comment=comment)
|
||||
except pg.EditConflict, e:
|
||||
msg = e.message
|
||||
|
||||
# Handle conflict and send editor
|
||||
pg.set_raw_body(savetext, modified=1)
|
||||
|
||||
pg.mergeEditConflict(rev)
|
||||
# We don't send preview when we do merge conflict
|
||||
pg.sendEditor(msg=msg, comment=comment)
|
||||
return
|
||||
|
||||
except pg.SaveError, msg:
|
||||
# msg contains a unicode string
|
||||
savemsg = unicode(msg)
|
||||
|
||||
# Send new page after save or after unsuccessful conflict merge.
|
||||
request.reset()
|
||||
pg = Page(request, pagename)
|
||||
|
||||
# sets revision number to default for further actions
|
||||
request.rev = 0
|
||||
request.theme.add_msg(savemsg, "info")
|
||||
pg.send_page()
|
195
wiki-lenny/share/action.newaccount.orig.py
Normal file
195
wiki-lenny/share/action.newaccount.orig.py
Normal file
|
@ -0,0 +1,195 @@
|
|||
# -*- coding: iso-8859-1 -*-
|
||||
"""
|
||||
MoinMoin - create account action
|
||||
|
||||
@copyright: 2007 MoinMoin:JohannesBerg
|
||||
@license: GNU GPL, see COPYING for details.
|
||||
"""
|
||||
|
||||
from MoinMoin import user, wikiutil, util
|
||||
from MoinMoin.Page import Page
|
||||
from MoinMoin.widget import html
|
||||
from MoinMoin.security.textcha import TextCha
|
||||
from MoinMoin.auth import MoinAuth
|
||||
|
||||
|
||||
_debug = False
|
||||
|
||||
def _create_user(request):
|
||||
_ = request.getText
|
||||
form = request.form
|
||||
|
||||
if request.request_method != 'POST':
|
||||
return
|
||||
|
||||
if not TextCha(request).check_answer_from_form():
|
||||
return _('TextCha: Wrong answer! Go back and try again...')
|
||||
|
||||
# Create user profile
|
||||
theuser = user.User(request, auth_method="new-user")
|
||||
|
||||
# Require non-empty name
|
||||
try:
|
||||
theuser.name = form['name'][0]
|
||||
except KeyError:
|
||||
return _("Empty user name. Please enter a user name.")
|
||||
|
||||
# Don't allow creating users with invalid names
|
||||
if not user.isValidName(request, theuser.name):
|
||||
return _("""Invalid user name {{{'%s'}}}.
|
||||
Name may contain any Unicode alpha numeric character, with optional one
|
||||
space between words. Group page name is not allowed.""", wiki=True) % wikiutil.escape(theuser.name)
|
||||
|
||||
# Name required to be unique. Check if name belong to another user.
|
||||
if user.getUserId(request, theuser.name):
|
||||
return _("This user name already belongs to somebody else.")
|
||||
|
||||
# try to get the password and pw repeat
|
||||
password = form.get('password1', [''])[0]
|
||||
password2 = form.get('password2', [''])[0]
|
||||
|
||||
# Check if password is given and matches with password repeat
|
||||
if password != password2:
|
||||
return _("Passwords don't match!")
|
||||
if not password:
|
||||
return _("Please specify a password!")
|
||||
|
||||
pw_checker = request.cfg.password_checker
|
||||
if pw_checker:
|
||||
pw_error = pw_checker(theuser.name, password)
|
||||
if pw_error:
|
||||
return _("Password not acceptable: %s") % pw_error
|
||||
|
||||
# Encode password
|
||||
if password and not password.startswith('{SHA}'):
|
||||
try:
|
||||
theuser.enc_password = user.encodePassword(password)
|
||||
except UnicodeError, err:
|
||||
# Should never happen
|
||||
return "Can't encode password: %s" % str(err)
|
||||
|
||||
# try to get the email, for new users it is required
|
||||
email = wikiutil.clean_input(form.get('email', [''])[0])
|
||||
theuser.email = email.strip()
|
||||
if not theuser.email and 'email' not in request.cfg.user_form_remove:
|
||||
return _("Please provide your email address. If you lose your"
|
||||
" login information, you can get it by email.")
|
||||
|
||||
# Email should be unique - see also MoinMoin/script/accounts/moin_usercheck.py
|
||||
if theuser.email and request.cfg.user_email_unique:
|
||||
if user.get_by_email_address(request, theuser.email):
|
||||
return _("This email already belongs to somebody else.")
|
||||
|
||||
# save data
|
||||
theuser.save()
|
||||
|
||||
if form.has_key('create_and_mail'):
|
||||
theuser.mailAccountData()
|
||||
|
||||
result = _("User account created! You can use this account to login now...")
|
||||
if _debug:
|
||||
result = result + util.dumpFormData(form)
|
||||
return result
|
||||
|
||||
|
||||
def _create_form(request):
|
||||
_ = request.getText
|
||||
url = request.page.url(request)
|
||||
ret = html.FORM(action=url)
|
||||
ret.append(html.INPUT(type='hidden', name='action', value='newaccount'))
|
||||
lang_attr = request.theme.ui_lang_attr()
|
||||
ret.append(html.Raw('<div class="userpref"%s>' % lang_attr))
|
||||
tbl = html.TABLE(border="0")
|
||||
ret.append(tbl)
|
||||
ret.append(html.Raw('</div>'))
|
||||
|
||||
row = html.TR()
|
||||
tbl.append(row)
|
||||
row.append(html.TD().append(html.STRONG().append(
|
||||
html.Text(_("Name")))))
|
||||
cell = html.TD()
|
||||
row.append(cell)
|
||||
cell.append(html.INPUT(type="text", size="36", name="name"))
|
||||
cell.append(html.Text(' ' + _("(Use FirstnameLastname)")))
|
||||
|
||||
row = html.TR()
|
||||
tbl.append(row)
|
||||
row.append(html.TD().append(html.STRONG().append(
|
||||
html.Text(_("Password")))))
|
||||
row.append(html.TD().append(html.INPUT(type="password", size="36",
|
||||
name="password1")))
|
||||
|
||||
row = html.TR()
|
||||
tbl.append(row)
|
||||
row.append(html.TD().append(html.STRONG().append(
|
||||
html.Text(_("Password repeat")))))
|
||||
row.append(html.TD().append(html.INPUT(type="password", size="36",
|
||||
name="password2")))
|
||||
|
||||
row = html.TR()
|
||||
tbl.append(row)
|
||||
row.append(html.TD().append(html.STRONG().append(html.Text(_("Email")))))
|
||||
row.append(html.TD().append(html.INPUT(type="text", size="36",
|
||||
name="email")))
|
||||
|
||||
textcha = TextCha(request)
|
||||
if textcha.is_enabled():
|
||||
row = html.TR()
|
||||
tbl.append(row)
|
||||
row.append(html.TD().append(html.STRONG().append(
|
||||
html.Text(_('TextCha (required)')))))
|
||||
td = html.TD()
|
||||
if textcha:
|
||||
td.append(textcha.render())
|
||||
row.append(td)
|
||||
|
||||
row = html.TR()
|
||||
tbl.append(row)
|
||||
row.append(html.TD())
|
||||
td = html.TD()
|
||||
row.append(td)
|
||||
td.append(html.INPUT(type="submit", name="create_only",
|
||||
value=_('Create Profile')))
|
||||
if request.cfg.mail_enabled:
|
||||
td.append(html.Text(' '))
|
||||
td.append(html.INPUT(type="submit", name="create_and_mail",
|
||||
value="%s + %s" % (_('Create Profile'),
|
||||
_('Email'))))
|
||||
|
||||
return unicode(ret)
|
||||
|
||||
def execute(pagename, request):
|
||||
found = False
|
||||
for auth in request.cfg.auth:
|
||||
if isinstance(auth, MoinAuth):
|
||||
found = True
|
||||
break
|
||||
|
||||
if not found:
|
||||
# we will not have linked, so forbid access
|
||||
request.makeForbidden403()
|
||||
return
|
||||
|
||||
page = Page(request, pagename)
|
||||
_ = request.getText
|
||||
form = request.form
|
||||
|
||||
submitted = form.has_key('create_only') or form.has_key('create_and_mail')
|
||||
|
||||
if submitted: # user pressed create button
|
||||
request.theme.add_msg(_create_user(request), "dialog")
|
||||
return page.send_page()
|
||||
else: # show create form
|
||||
request.emit_http_headers()
|
||||
request.theme.send_title(_("Create Account"), pagename=pagename)
|
||||
|
||||
request.write(request.formatter.startContent("content"))
|
||||
|
||||
# THIS IS A BIG HACK. IT NEEDS TO BE CLEANED UP
|
||||
request.write(_create_form(request))
|
||||
|
||||
request.write(request.formatter.endContent())
|
||||
|
||||
request.theme.send_footer(pagename)
|
||||
request.theme.send_closing_html()
|
||||
|
207
wiki-lenny/share/action.newaccount.py
Normal file
207
wiki-lenny/share/action.newaccount.py
Normal file
|
@ -0,0 +1,207 @@
|
|||
# -*- coding: iso-8859-1 -*-
|
||||
"""
|
||||
MoinMoin - create account action
|
||||
|
||||
@copyright: 2007 MoinMoin:JohannesBerg
|
||||
@license: GNU GPL, see COPYING for details.
|
||||
"""
|
||||
|
||||
from MoinMoin import user, wikiutil, util
|
||||
from MoinMoin.Page import Page
|
||||
from MoinMoin.widget import html
|
||||
from MoinMoin.security.textcha import TextCha
|
||||
from MoinMoin.auth import MoinAuth
|
||||
|
||||
|
||||
_debug = False
|
||||
|
||||
def _create_user(request):
|
||||
_ = request.getText
|
||||
form = request.form
|
||||
|
||||
if request.request_method != 'POST':
|
||||
return
|
||||
|
||||
if not TextCha(request).check_answer_from_form():
|
||||
return _('TextCha: Wrong answer! Go back and try again...')
|
||||
|
||||
# Create user profile
|
||||
theuser = user.User(request, auth_method="new-user")
|
||||
|
||||
# Require non-empty name
|
||||
try:
|
||||
theuser.name = form['name'][0]
|
||||
except KeyError:
|
||||
return _("Empty user name. Please enter a user name.")
|
||||
|
||||
# Don't allow creating users with invalid names
|
||||
if not user.isValidName(request, theuser.name):
|
||||
return _("""Invalid user name {{{'%s'}}}.
|
||||
Name may contain any Unicode alpha numeric character, with optional one
|
||||
space between words. Group page name is not allowed.""", wiki=True) % wikiutil.escape(theuser.name)
|
||||
|
||||
# Name required to be unique. Check if name belong to another user.
|
||||
if user.getUserId(request, theuser.name):
|
||||
return _("This user name already belongs to somebody else.")
|
||||
|
||||
# HACK SAUVAGE 1/1
|
||||
# On interdit la création de compte aux gens qui ne sont pas en zone Cr@ns
|
||||
import sys
|
||||
sys.path.append('/usr/scripts/gestion/')
|
||||
from iptools import is_crans
|
||||
if not is_crans(self.request.remote_addr):
|
||||
return _(u"""Création de compte impossible.
|
||||
Pour des raisons de sécurité, la fonction de création d'un compte n'est
|
||||
possible que depuis la zone CRANS. Si vous possédez un compte sur zamok,
|
||||
vous pouvez y exécuter creer_compte_wiki.""")
|
||||
# FIN HACK
|
||||
|
||||
# try to get the password and pw repeat
|
||||
password = form.get('password1', [''])[0]
|
||||
password2 = form.get('password2', [''])[0]
|
||||
|
||||
# Check if password is given and matches with password repeat
|
||||
if password != password2:
|
||||
return _("Passwords don't match!")
|
||||
if not password:
|
||||
return _("Please specify a password!")
|
||||
|
||||
pw_checker = request.cfg.password_checker
|
||||
if pw_checker:
|
||||
pw_error = pw_checker(theuser.name, password)
|
||||
if pw_error:
|
||||
return _("Password not acceptable: %s") % pw_error
|
||||
|
||||
# Encode password
|
||||
if password and not password.startswith('{SHA}'):
|
||||
try:
|
||||
theuser.enc_password = user.encodePassword(password)
|
||||
except UnicodeError, err:
|
||||
# Should never happen
|
||||
return "Can't encode password: %s" % str(err)
|
||||
|
||||
# try to get the email, for new users it is required
|
||||
email = wikiutil.clean_input(form.get('email', [''])[0])
|
||||
theuser.email = email.strip()
|
||||
if not theuser.email and 'email' not in request.cfg.user_form_remove:
|
||||
return _("Please provide your email address. If you lose your"
|
||||
" login information, you can get it by email.")
|
||||
|
||||
# Email should be unique - see also MoinMoin/script/accounts/moin_usercheck.py
|
||||
if theuser.email and request.cfg.user_email_unique:
|
||||
if user.get_by_email_address(request, theuser.email):
|
||||
return _("This email already belongs to somebody else.")
|
||||
|
||||
# save data
|
||||
theuser.save()
|
||||
|
||||
if form.has_key('create_and_mail'):
|
||||
theuser.mailAccountData()
|
||||
|
||||
result = _("User account created! You can use this account to login now...")
|
||||
if _debug:
|
||||
result = result + util.dumpFormData(form)
|
||||
return result
|
||||
|
||||
|
||||
def _create_form(request):
|
||||
_ = request.getText
|
||||
url = request.page.url(request)
|
||||
ret = html.FORM(action=url)
|
||||
ret.append(html.INPUT(type='hidden', name='action', value='newaccount'))
|
||||
lang_attr = request.theme.ui_lang_attr()
|
||||
ret.append(html.Raw('<div class="userpref"%s>' % lang_attr))
|
||||
tbl = html.TABLE(border="0")
|
||||
ret.append(tbl)
|
||||
ret.append(html.Raw('</div>'))
|
||||
|
||||
row = html.TR()
|
||||
tbl.append(row)
|
||||
row.append(html.TD().append(html.STRONG().append(
|
||||
html.Text(_("Name")))))
|
||||
cell = html.TD()
|
||||
row.append(cell)
|
||||
cell.append(html.INPUT(type="text", size="36", name="name"))
|
||||
cell.append(html.Text(' ' + _("(Use FirstnameLastname)")))
|
||||
|
||||
row = html.TR()
|
||||
tbl.append(row)
|
||||
row.append(html.TD().append(html.STRONG().append(
|
||||
html.Text(_("Password")))))
|
||||
row.append(html.TD().append(html.INPUT(type="password", size="36",
|
||||
name="password1")))
|
||||
|
||||
row = html.TR()
|
||||
tbl.append(row)
|
||||
row.append(html.TD().append(html.STRONG().append(
|
||||
html.Text(_("Password repeat")))))
|
||||
row.append(html.TD().append(html.INPUT(type="password", size="36",
|
||||
name="password2")))
|
||||
|
||||
row = html.TR()
|
||||
tbl.append(row)
|
||||
row.append(html.TD().append(html.STRONG().append(html.Text(_("Email")))))
|
||||
row.append(html.TD().append(html.INPUT(type="text", size="36",
|
||||
name="email")))
|
||||
|
||||
textcha = TextCha(request)
|
||||
if textcha.is_enabled():
|
||||
row = html.TR()
|
||||
tbl.append(row)
|
||||
row.append(html.TD().append(html.STRONG().append(
|
||||
html.Text(_('TextCha (required)')))))
|
||||
td = html.TD()
|
||||
if textcha:
|
||||
td.append(textcha.render())
|
||||
row.append(td)
|
||||
|
||||
row = html.TR()
|
||||
tbl.append(row)
|
||||
row.append(html.TD())
|
||||
td = html.TD()
|
||||
row.append(td)
|
||||
td.append(html.INPUT(type="submit", name="create_only",
|
||||
value=_('Create Profile')))
|
||||
if request.cfg.mail_enabled:
|
||||
td.append(html.Text(' '))
|
||||
td.append(html.INPUT(type="submit", name="create_and_mail",
|
||||
value="%s + %s" % (_('Create Profile'),
|
||||
_('Email'))))
|
||||
|
||||
return unicode(ret)
|
||||
|
||||
def execute(pagename, request):
|
||||
found = False
|
||||
for auth in request.cfg.auth:
|
||||
if isinstance(auth, MoinAuth):
|
||||
found = True
|
||||
break
|
||||
|
||||
if not found:
|
||||
# we will not have linked, so forbid access
|
||||
request.makeForbidden403()
|
||||
return
|
||||
|
||||
page = Page(request, pagename)
|
||||
_ = request.getText
|
||||
form = request.form
|
||||
|
||||
submitted = form.has_key('create_only') or form.has_key('create_and_mail')
|
||||
|
||||
if submitted: # user pressed create button
|
||||
request.theme.add_msg(_create_user(request), "dialog")
|
||||
return page.send_page()
|
||||
else: # show create form
|
||||
request.emit_http_headers()
|
||||
request.theme.send_title(_("Create Account"), pagename=pagename)
|
||||
|
||||
request.write(request.formatter.startContent("content"))
|
||||
|
||||
# THIS IS A BIG HACK. IT NEEDS TO BE CLEANED UP
|
||||
request.write(_create_form(request))
|
||||
|
||||
request.write(request.formatter.endContent())
|
||||
|
||||
request.theme.send_footer(pagename)
|
||||
request.theme.send_closing_html()
|
||||
|
435
wiki-lenny/share/formatter.__init__.py
Normal file
435
wiki-lenny/share/formatter.__init__.py
Normal file
|
@ -0,0 +1,435 @@
|
|||
# -*- coding: iso-8859-1 -*-
|
||||
"""
|
||||
MoinMoin - Formatter Package and FormatterBase
|
||||
|
||||
See "base.py" for the formatter interface.
|
||||
|
||||
@copyright: 2000-2004 by Juergen Hermann <jh@web.de>
|
||||
@license: GNU GPL, see COPYING for details.
|
||||
"""
|
||||
import re
|
||||
|
||||
from MoinMoin import log
|
||||
logging = log.getLogger(__name__)
|
||||
|
||||
from MoinMoin.util import pysupport
|
||||
from MoinMoin import wikiutil
|
||||
from MoinMoin.support.python_compatibility import rsplit
|
||||
|
||||
modules = pysupport.getPackageModules(__file__)
|
||||
|
||||
|
||||
class FormatterBase:
|
||||
""" This defines the output interface used all over the rest of the code.
|
||||
|
||||
Note that no other means should be used to generate _content_ output,
|
||||
while navigational elements (HTML page header/footer) and the like
|
||||
can be printed directly without violating output abstraction.
|
||||
"""
|
||||
|
||||
hardspace = ' '
|
||||
|
||||
def __init__(self, request, **kw):
|
||||
self.request = request
|
||||
self._ = request.getText
|
||||
|
||||
self._store_pagelinks = kw.get('store_pagelinks', 0)
|
||||
self._terse = kw.get('terse', 0)
|
||||
self.pagelinks = []
|
||||
self.in_p = 0
|
||||
self.in_pre = 0
|
||||
self._highlight_re = None
|
||||
self._base_depth = 0
|
||||
|
||||
def set_highlight_re(self, hi_re=None):
|
||||
""" set the highlighting regular expression (e.g. for search terms)
|
||||
|
||||
@param hi_re: either a valid re as str/unicode (you may want to use
|
||||
re.escape before passing generic strings!) or a compiled
|
||||
re object. raises re.error for invalid re.
|
||||
"""
|
||||
if isinstance(hi_re, (str, unicode)):
|
||||
hi_re = re.compile(hi_re, re.U + re.IGNORECASE)
|
||||
self._highlight_re = hi_re
|
||||
|
||||
def lang(self, on, lang_name):
|
||||
return ""
|
||||
|
||||
def setPage(self, page):
|
||||
self.page = page
|
||||
|
||||
def sysmsg(self, on, **kw):
|
||||
""" Emit a system message (embed it into the page).
|
||||
|
||||
Normally used to indicate disabled options, or invalid markup.
|
||||
"""
|
||||
return ""
|
||||
|
||||
# Document Level #####################################################
|
||||
|
||||
def startDocument(self, pagename):
|
||||
return ""
|
||||
|
||||
def endDocument(self):
|
||||
return ""
|
||||
|
||||
def startContent(self, content_id="content", **kw):
|
||||
if self.page:
|
||||
self.request.begin_include(self.page.page_name)
|
||||
return ""
|
||||
|
||||
def endContent(self):
|
||||
if self.page:
|
||||
self.request.end_include()
|
||||
return ""
|
||||
|
||||
# Links ##############################################################
|
||||
|
||||
def pagelink(self, on, pagename='', page=None, **kw):
|
||||
""" make a link to page <pagename>. Instead of supplying a pagename,
|
||||
it is also possible to give a live Page object, then page.page_name
|
||||
will be used.
|
||||
"""
|
||||
if not self._store_pagelinks or not on or kw.get('generated'):
|
||||
return ''
|
||||
if not pagename and page:
|
||||
pagename = page.page_name
|
||||
pagename = self.request.normalizePagename(pagename)
|
||||
if pagename and pagename not in self.pagelinks:
|
||||
self.pagelinks.append(pagename)
|
||||
|
||||
def interwikilink(self, on, interwiki='', pagename='', **kw):
|
||||
""" calls pagelink() for internal interwikilinks
|
||||
to make sure they get counted for self.pagelinks.
|
||||
IMPORTANT: on and off must be called with same parameters, see
|
||||
also the text_html formatter.
|
||||
"""
|
||||
wikitag, wikiurl, wikitail, wikitag_bad = wikiutil.resolve_interwiki(self.request, interwiki, pagename)
|
||||
if wikitag == 'Self' or wikitag == self.request.cfg.interwikiname:
|
||||
if '#' in wikitail:
|
||||
wikitail, kw['anchor'] = rsplit(wikitail, '#', 1)
|
||||
wikitail = wikiutil.url_unquote(wikitail)
|
||||
return self.pagelink(on, wikitail, **kw)
|
||||
return ''
|
||||
|
||||
def url(self, on, url=None, css=None, **kw):
|
||||
raise NotImplementedError
|
||||
|
||||
# Attachments ######################################################
|
||||
|
||||
def attachment_link(self, on, url=None, **kw):
|
||||
raise NotImplementedError
|
||||
def attachment_image(self, url, **kw):
|
||||
raise NotImplementedError
|
||||
def attachment_drawing(self, url, text, **kw):
|
||||
raise NotImplementedError
|
||||
|
||||
def attachment_inlined(self, url, text, **kw):
|
||||
from MoinMoin.action import AttachFile
|
||||
import os
|
||||
_ = self.request.getText
|
||||
pagename, filename = AttachFile.absoluteName(url, self.page.page_name)
|
||||
fname = wikiutil.taintfilename(filename)
|
||||
fpath = AttachFile.getFilename(self.request, pagename, fname)
|
||||
ext = os.path.splitext(filename)[1]
|
||||
Parser = wikiutil.getParserForExtension(self.request.cfg, ext)
|
||||
if Parser is not None:
|
||||
try:
|
||||
content = file(fpath, 'r').read()
|
||||
# Try to decode text. It might return junk, but we don't
|
||||
# have enough information with attachments.
|
||||
content = wikiutil.decodeUnknownInput(content)
|
||||
colorizer = Parser(content, self.request, filename=filename)
|
||||
colorizer.format(self)
|
||||
except IOError:
|
||||
pass
|
||||
|
||||
return (self.attachment_link(1, url) +
|
||||
self.text(text) +
|
||||
self.attachment_link(0))
|
||||
|
||||
def anchordef(self, name):
|
||||
return ""
|
||||
|
||||
def line_anchordef(self, lineno):
|
||||
return ""
|
||||
|
||||
def anchorlink(self, on, name='', **kw):
|
||||
return ""
|
||||
|
||||
def line_anchorlink(self, on, lineno=0):
|
||||
return ""
|
||||
|
||||
def image(self, src=None, **kw):
|
||||
"""An inline image.
|
||||
|
||||
Extra keyword arguments are according to the HTML <img> tag attributes.
|
||||
In particular an 'alt' or 'title' argument should give a description
|
||||
of the image.
|
||||
"""
|
||||
title = src
|
||||
for titleattr in ('title', 'html__title', 'alt', 'html__alt'):
|
||||
if titleattr in kw:
|
||||
title = kw[titleattr]
|
||||
break
|
||||
if title:
|
||||
return '[Image:%s]' % title
|
||||
return '[Image]'
|
||||
|
||||
# generic transclude/include:
|
||||
def transclusion(self, on, **kw):
|
||||
raise NotImplementedError
|
||||
def transclusion_param(self, **kw):
|
||||
raise NotImplementedError
|
||||
|
||||
def smiley(self, text):
|
||||
return text
|
||||
|
||||
def nowikiword(self, text):
|
||||
return self.text(text)
|
||||
|
||||
# Text and Text Attributes ###########################################
|
||||
|
||||
def text(self, text, **kw):
|
||||
if not self._highlight_re:
|
||||
return self._text(text)
|
||||
|
||||
result = []
|
||||
lastpos = 0
|
||||
match = self._highlight_re.search(text)
|
||||
while match and lastpos < len(text):
|
||||
# add the match we found
|
||||
result.append(self._text(text[lastpos:match.start()]))
|
||||
result.append(self.highlight(1))
|
||||
result.append(self._text(match.group(0)))
|
||||
result.append(self.highlight(0))
|
||||
|
||||
# search for the next one
|
||||
lastpos = match.end() + (match.end() == lastpos)
|
||||
match = self._highlight_re.search(text, lastpos)
|
||||
|
||||
result.append(self._text(text[lastpos:]))
|
||||
return ''.join(result)
|
||||
|
||||
def _text(self, text):
|
||||
raise NotImplementedError
|
||||
|
||||
def strong(self, on, **kw):
|
||||
raise NotImplementedError
|
||||
|
||||
def emphasis(self, on, **kw):
|
||||
raise NotImplementedError
|
||||
|
||||
def underline(self, on, **kw):
|
||||
raise NotImplementedError
|
||||
|
||||
def highlight(self, on, **kw):
|
||||
raise NotImplementedError
|
||||
|
||||
def sup(self, on, **kw):
|
||||
raise NotImplementedError
|
||||
|
||||
def sub(self, on, **kw):
|
||||
raise NotImplementedError
|
||||
|
||||
def strike(self, on, **kw):
|
||||
raise NotImplementedError
|
||||
|
||||
def code(self, on, **kw):
|
||||
raise NotImplementedError
|
||||
|
||||
def preformatted(self, on, **kw):
|
||||
self.in_pre = on != 0
|
||||
|
||||
def small(self, on, **kw):
|
||||
raise NotImplementedError
|
||||
|
||||
def big(self, on, **kw):
|
||||
raise NotImplementedError
|
||||
|
||||
# special markup for syntax highlighting #############################
|
||||
|
||||
def code_area(self, on, code_id, **kw):
|
||||
raise NotImplementedError
|
||||
|
||||
def code_line(self, on):
|
||||
raise NotImplementedError
|
||||
|
||||
def code_token(self, tok_text, tok_type):
|
||||
raise NotImplementedError
|
||||
|
||||
def crans_box(self, title, content, color=None):
|
||||
raise NotImplementedError
|
||||
|
||||
# Paragraphs, Lines, Rules ###########################################
|
||||
|
||||
def linebreak(self, preformatted=1):
|
||||
raise NotImplementedError
|
||||
|
||||
def paragraph(self, on, **kw):
|
||||
self.in_p = on != 0
|
||||
|
||||
def rule(self, size=0, **kw):
|
||||
raise NotImplementedError
|
||||
|
||||
def icon(self, type):
|
||||
return type
|
||||
|
||||
# Lists ##############################################################
|
||||
|
||||
def number_list(self, on, type=None, start=None, **kw):
|
||||
raise NotImplementedError
|
||||
|
||||
def bullet_list(self, on, **kw):
|
||||
raise NotImplementedError
|
||||
|
||||
def listitem(self, on, **kw):
|
||||
raise NotImplementedError
|
||||
|
||||
def definition_list(self, on, **kw):
|
||||
raise NotImplementedError
|
||||
|
||||
def definition_term(self, on, compact=0, **kw):
|
||||
raise NotImplementedError
|
||||
|
||||
def definition_desc(self, on, **kw):
|
||||
raise NotImplementedError
|
||||
|
||||
def heading(self, on, depth, **kw):
|
||||
raise NotImplementedError
|
||||
|
||||
# Tables #############################################################
|
||||
|
||||
def table(self, on, attrs={}, **kw):
|
||||
raise NotImplementedError
|
||||
|
||||
def table_row(self, on, attrs={}, **kw):
|
||||
raise NotImplementedError
|
||||
|
||||
def table_cell(self, on, attrs={}, **kw):
|
||||
raise NotImplementedError
|
||||
|
||||
# Dynamic stuff / Plugins ############################################
|
||||
|
||||
def macro(self, macro_obj, name, args, markup=None):
|
||||
# call the macro
|
||||
try:
|
||||
return macro_obj.execute(name, args)
|
||||
except ImportError, err:
|
||||
errmsg = unicode(err)
|
||||
if not name in errmsg:
|
||||
raise
|
||||
if markup:
|
||||
return (self.span(1, title=errmsg) +
|
||||
self.text(markup) +
|
||||
self.span(0))
|
||||
else:
|
||||
return self.text(errmsg)
|
||||
def _get_bang_args(self, line):
|
||||
if line.startswith('#!'):
|
||||
try:
|
||||
name, args = line[2:].split(None, 1)
|
||||
except ValueError:
|
||||
return ''
|
||||
else:
|
||||
return args
|
||||
return None
|
||||
|
||||
def parser(self, parser_name, lines):
|
||||
""" parser_name MUST be valid!
|
||||
writes out the result instead of returning it!
|
||||
"""
|
||||
# attention: this is copied into text_python!
|
||||
parser = wikiutil.searchAndImportPlugin(self.request.cfg, "parser", parser_name)
|
||||
args = None
|
||||
if lines:
|
||||
args = self._get_bang_args(lines[0])
|
||||
logging.debug("formatter.parser: parser args %r" % args)
|
||||
if args is not None:
|
||||
lines = lines[1:]
|
||||
if lines and not lines[0]:
|
||||
lines = lines[1:]
|
||||
if lines and not lines[-1].strip():
|
||||
lines = lines[:-1]
|
||||
p = parser('\n'.join(lines), self.request, format_args=args)
|
||||
p.format(self)
|
||||
del p
|
||||
return ''
|
||||
|
||||
# Other ##############################################################
|
||||
|
||||
def div(self, on, **kw):
|
||||
""" open/close a blocklevel division """
|
||||
return ""
|
||||
|
||||
def span(self, on, **kw):
|
||||
""" open/close a inline span """
|
||||
return ""
|
||||
|
||||
def rawHTML(self, markup):
|
||||
""" This allows emitting pre-formatted HTML markup, and should be
|
||||
used wisely (i.e. very seldom).
|
||||
|
||||
Using this event while generating content results in unwanted
|
||||
effects, like loss of markup or insertion of CDATA sections
|
||||
when output goes to XML formats.
|
||||
"""
|
||||
|
||||
import formatter, htmllib
|
||||
from MoinMoin.util import simpleIO
|
||||
|
||||
# Regenerate plain text
|
||||
f = simpleIO()
|
||||
h = htmllib.HTMLParser(formatter.AbstractFormatter(formatter.DumbWriter(f)))
|
||||
h.feed(markup)
|
||||
h.close()
|
||||
|
||||
return self.text(f.getvalue())
|
||||
|
||||
def escapedText(self, on, **kw):
|
||||
""" This allows emitting text as-is, anything special will
|
||||
be escaped (at least in HTML, some text output format
|
||||
would possibly do nothing here)
|
||||
"""
|
||||
return ""
|
||||
|
||||
def comment(self, text, **kw):
|
||||
return ""
|
||||
|
||||
# ID handling #################################################
|
||||
|
||||
def sanitize_to_id(self, text):
|
||||
'''
|
||||
Take 'text' and return something that is a valid ID
|
||||
for this formatter.
|
||||
The default returns the first non-space character of the string.
|
||||
|
||||
Because of the way this is used, it must be idempotent,
|
||||
i.e. calling it on an already sanitized id must yield the
|
||||
original id.
|
||||
'''
|
||||
return text.strip()[:1]
|
||||
|
||||
def make_id_unique(self, id):
|
||||
'''
|
||||
Take an ID and make it unique in the current namespace.
|
||||
'''
|
||||
ns = self.request.include_id
|
||||
if not ns is None:
|
||||
ns = self.sanitize_to_id(ns)
|
||||
id = self.sanitize_to_id(id)
|
||||
id = self.request.make_unique_id(id, ns)
|
||||
return id
|
||||
|
||||
def qualify_id(self, id):
|
||||
'''
|
||||
Take an ID and return a string that is qualified by
|
||||
the current namespace; this default implementation
|
||||
is suitable if the dot ('.') is valid in IDs for your
|
||||
formatter.
|
||||
'''
|
||||
ns = self.request.include_id
|
||||
if not ns is None:
|
||||
ns = self.sanitize_to_id(ns)
|
||||
return '%s.%s' % (ns, id)
|
||||
return id
|
1405
wiki-lenny/share/formatter.text_html.py
Normal file
1405
wiki-lenny/share/formatter.text_html.py
Normal file
File diff suppressed because it is too large
Load diff
454
wiki-lenny/share/security.__init__.orig.py
Normal file
454
wiki-lenny/share/security.__init__.orig.py
Normal file
|
@ -0,0 +1,454 @@
|
|||
# -*- coding: iso-8859-1 -*-
|
||||
"""
|
||||
MoinMoin - Wiki Security Interface and Access Control Lists
|
||||
|
||||
|
||||
This implements the basic interface for user permissions and
|
||||
system policy. If you want to define your own policy, inherit
|
||||
from the base class 'Permissions', so that when new permissions
|
||||
are defined, you get the defaults.
|
||||
|
||||
Then assign your new class to "SecurityPolicy" in wikiconfig;
|
||||
and I mean the class, not an instance of it!
|
||||
|
||||
@copyright: 2000-2004 Juergen Hermann <jh@web.de>,
|
||||
2003-2008 MoinMoin:ThomasWaldmann,
|
||||
2003 Gustavo Niemeyer,
|
||||
2005 Oliver Graf,
|
||||
2007 Alexander Schremmer
|
||||
@license: GNU GPL, see COPYING for details.
|
||||
"""
|
||||
|
||||
import re
|
||||
|
||||
from MoinMoin import wikiutil, user
|
||||
from MoinMoin.Page import Page
|
||||
|
||||
#############################################################################
|
||||
### Basic Permissions Interface -- most features enabled by default
|
||||
#############################################################################
|
||||
|
||||
def _check(request, pagename, username, right):
|
||||
""" Check <right> access permission for user <username> on page <pagename>
|
||||
|
||||
For cfg.acl_hierarchic=False we just check the page in question.
|
||||
|
||||
For cfg.acl_hierarchic=True we, we check each page in the hierarchy. We
|
||||
start with the deepest page and recurse to the top of the tree.
|
||||
If one of those permits, True is returned.
|
||||
|
||||
For both configurations, we check acl_rights_before before the page/default
|
||||
acl and acl_rights_after after the page/default acl, of course.
|
||||
|
||||
This method should not be called by users, use __getattr__ instead.
|
||||
|
||||
@param request: the current request object
|
||||
@param pagename: pagename to get permissions from
|
||||
@param username: the user name
|
||||
@param right: the right to check
|
||||
|
||||
@rtype: bool
|
||||
@return: True if you have permission or False
|
||||
"""
|
||||
cache = request.cfg.cache
|
||||
allowed = cache.acl_rights_before.may(request, username, right)
|
||||
if allowed is not None:
|
||||
return allowed
|
||||
|
||||
if request.cfg.acl_hierarchic:
|
||||
pages = pagename.split('/') # create page hierarchy list
|
||||
some_acl = False
|
||||
for i in range(len(pages), 0, -1):
|
||||
# Create the next pagename in the hierarchy
|
||||
# starting at the leaf, going to the root
|
||||
name = '/'.join(pages[:i])
|
||||
# Get page acl and ask for permission
|
||||
acl = Page(request, name).getACL(request)
|
||||
if acl.acl:
|
||||
some_acl = True
|
||||
allowed = acl.may(request, username, right)
|
||||
if allowed is not None:
|
||||
return allowed
|
||||
if not some_acl:
|
||||
allowed = cache.acl_rights_default.may(request, username, right)
|
||||
if allowed is not None:
|
||||
return allowed
|
||||
else:
|
||||
if request.page is not None and pagename == request.page.page_name:
|
||||
p = request.page # reuse is good
|
||||
else:
|
||||
p = Page(request, pagename)
|
||||
acl = p.getACL(request) # this will be fast in a reused page obj
|
||||
allowed = acl.may(request, username, right)
|
||||
if allowed is not None:
|
||||
return allowed
|
||||
|
||||
allowed = cache.acl_rights_after.may(request, username, right)
|
||||
if allowed is not None:
|
||||
return allowed
|
||||
|
||||
return False
|
||||
|
||||
|
||||
class Permissions:
|
||||
""" Basic interface for user permissions and system policy.
|
||||
|
||||
Note that you still need to allow some of the related actions, this
|
||||
just controls their behavior, not their activation.
|
||||
|
||||
When sub classing this class, you must extend the class methods, not
|
||||
replace them, or you might break the acl in the wiki. Correct sub
|
||||
classing looks like this:
|
||||
|
||||
def read(self, pagename):
|
||||
# Your special security rule
|
||||
if something:
|
||||
return false
|
||||
|
||||
# Do not return True or you break acl!
|
||||
# This call will use the default acl rules
|
||||
return Permissions.read(pagename)
|
||||
"""
|
||||
|
||||
def __init__(self, user):
|
||||
self.name = user.name
|
||||
self.request = user._request
|
||||
|
||||
def save(self, editor, newtext, rev, **kw):
|
||||
""" Check whether user may save a page.
|
||||
|
||||
`editor` is the PageEditor instance, the other arguments are
|
||||
those of the `PageEditor.saveText` method.
|
||||
|
||||
@param editor: PageEditor instance.
|
||||
@param newtext: new page text, you can enable of disable saving according
|
||||
to the content of the text, e.g. prevent link spam.
|
||||
@param rev: new revision number? XXX
|
||||
@param kw: XXX
|
||||
@rtype: bool
|
||||
@return: True if you can save or False
|
||||
"""
|
||||
return self.write(editor.page_name)
|
||||
|
||||
def __getattr__(self, attr):
|
||||
""" Shortcut to export getPermission function for all known ACL rights
|
||||
|
||||
if attr is one of the rights in acl_rights_valid, then return a
|
||||
checking function for it. Else raise an AttributeError.
|
||||
|
||||
@param attr: one of ACL rights as defined in acl_rights_valid
|
||||
@rtype: function
|
||||
@return: checking function for that right, accepting a pagename
|
||||
"""
|
||||
request = self.request
|
||||
if attr not in request.cfg.acl_rights_valid:
|
||||
raise AttributeError, attr
|
||||
return lambda pagename: _check(self.request, pagename, self.name, attr)
|
||||
|
||||
|
||||
# make an alias for the default policy
|
||||
Default = Permissions
|
||||
|
||||
|
||||
class AccessControlList:
|
||||
''' Access Control List
|
||||
|
||||
Control who may do what on or with a wiki page.
|
||||
|
||||
Syntax of an ACL string:
|
||||
|
||||
[+|-]User[,User,...]:[right[,right,...]] [[+|-]SomeGroup:...] ...
|
||||
... [[+|-]Known:...] [[+|-]All:...]
|
||||
|
||||
"User" is a user name and triggers only if the user matches. Up
|
||||
to version 1.2 only WikiNames were supported, as of version 1.3,
|
||||
any name can be used in acl lines, including name with spaces
|
||||
using esoteric languages.
|
||||
|
||||
"SomeGroup" is a page name matching cfg.page_group_regex with
|
||||
some lines in the form " * Member", defining the group members.
|
||||
|
||||
"Known" is a group containing all valid / known users.
|
||||
|
||||
"All" is a group containing all users (Known and Anonymous users).
|
||||
|
||||
"right" may be an arbitrary word like read, write, delete, admin.
|
||||
Only words in cfg.acl_validrights are accepted, others are
|
||||
ignored. It is allowed to specify no rights, which means that no
|
||||
rights are given.
|
||||
|
||||
How ACL is processed
|
||||
|
||||
When some user is trying to access some ACL-protected resource,
|
||||
the ACLs will be processed in the order they are found. The first
|
||||
matching ACL will tell if the user has access to that resource
|
||||
or not.
|
||||
|
||||
For example, the following ACL tells that SomeUser is able to
|
||||
read and write the resources protected by that ACL, while any
|
||||
member of SomeGroup (besides SomeUser, if part of that group)
|
||||
may also admin that, and every other user is able to read it.
|
||||
|
||||
SomeUser:read,write SomeGroup:read,write,admin All:read
|
||||
|
||||
In this example, SomeUser can read and write but can not admin,
|
||||
revert or delete pages. Rights that are NOT specified on the
|
||||
right list are automatically set to NO.
|
||||
|
||||
Using Prefixes
|
||||
|
||||
To make the system more flexible, there are also two modifiers:
|
||||
the prefixes "+" and "-".
|
||||
|
||||
+SomeUser:read -OtherUser:write
|
||||
|
||||
The acl line above will grant SomeUser read right, and OtherUser
|
||||
write right, but will NOT block automatically all other rights
|
||||
for these users. For example, if SomeUser ask to write, the
|
||||
above acl line does not define if he can or can not write. He
|
||||
will be able to write if acl_rights_before or acl_rights_after
|
||||
allow this (see configuration options).
|
||||
|
||||
Using prefixes, this acl line:
|
||||
|
||||
SomeUser:read,write SomeGroup:read,write,admin All:read
|
||||
|
||||
Can be written as:
|
||||
|
||||
-SomeUser:admin SomeGroup:read,write,admin All:read
|
||||
|
||||
Or even:
|
||||
|
||||
+All:read -SomeUser:admin SomeGroup:read,write,admin
|
||||
|
||||
Notice that you probably will not want to use the second and
|
||||
third examples in ACL entries of some page. They are very
|
||||
useful on the moin configuration entries though.
|
||||
|
||||
Configuration options
|
||||
|
||||
cfg.acl_rights_default
|
||||
It is is ONLY used when no other ACLs are given.
|
||||
Default: "Known:read,write,delete All:read,write",
|
||||
|
||||
cfg.acl_rights_before
|
||||
When the page has ACL entries, this will be inserted BEFORE
|
||||
any page entries.
|
||||
Default: ""
|
||||
|
||||
cfg.acl_rights_after
|
||||
When the page has ACL entries, this will be inserted AFTER
|
||||
any page entries.
|
||||
Default: ""
|
||||
|
||||
cfg.acl_rights_valid
|
||||
These are the acceptable (known) rights (and the place to
|
||||
extend, if necessary).
|
||||
Default: ["read", "write", "delete", "admin"]
|
||||
'''
|
||||
|
||||
special_users = ["All", "Known", "Trusted"] # order is important
|
||||
|
||||
def __init__(self, cfg, lines=[]):
|
||||
"""Initialize an ACL, starting from <nothing>.
|
||||
"""
|
||||
if lines:
|
||||
self.acl = [] # [ ('User', {"read": 0, ...}), ... ]
|
||||
self.acl_lines = []
|
||||
for line in lines:
|
||||
self._addLine(cfg, line)
|
||||
else:
|
||||
self.acl = None
|
||||
self.acl_lines = None
|
||||
|
||||
def _addLine(self, cfg, aclstring, remember=1):
|
||||
""" Add another ACL line
|
||||
|
||||
This can be used in multiple subsequent calls to process longer lists.
|
||||
|
||||
@param cfg: current config
|
||||
@param aclstring: acl string from page or cfg
|
||||
@param remember: should add the line to self.acl_lines
|
||||
"""
|
||||
|
||||
# Remember lines
|
||||
if remember:
|
||||
self.acl_lines.append(aclstring)
|
||||
|
||||
# Iterate over entries and rights, parsed by acl string iterator
|
||||
acliter = ACLStringIterator(cfg.acl_rights_valid, aclstring)
|
||||
for modifier, entries, rights in acliter:
|
||||
if entries == ['Default']:
|
||||
self._addLine(cfg, cfg.acl_rights_default, remember=0)
|
||||
else:
|
||||
for entry in entries:
|
||||
rightsdict = {}
|
||||
if modifier:
|
||||
# Only user rights are added to the right dict.
|
||||
# + add rights with value of 1
|
||||
# - add right with value of 0
|
||||
for right in rights:
|
||||
rightsdict[right] = (modifier == '+')
|
||||
else:
|
||||
# All rights from acl_rights_valid are added to the
|
||||
# dict, user rights with value of 1, and other with
|
||||
# value of 0
|
||||
for right in cfg.acl_rights_valid:
|
||||
rightsdict[right] = (right in rights)
|
||||
self.acl.append((entry, rightsdict))
|
||||
|
||||
def may(self, request, name, dowhat):
|
||||
""" May <name> <dowhat>? Returns boolean answer.
|
||||
|
||||
Note: this check does NOT include the acl_rights_before / _after ACL,
|
||||
but it WILL use acl_rights_default if there is no (page) ACL.
|
||||
"""
|
||||
if self.acl is None: # no #acl used on Page
|
||||
acl = request.cfg.cache.acl_rights_default.acl
|
||||
else: # we have a #acl on the page (self.acl can be [] if #acl is empty!)
|
||||
acl = self.acl
|
||||
is_group_member = request.dicts.has_member
|
||||
group_re = request.cfg.cache.page_group_regexact
|
||||
allowed = None
|
||||
for entry, rightsdict in acl:
|
||||
if entry in self.special_users:
|
||||
handler = getattr(self, "_special_"+entry, None)
|
||||
allowed = handler(request, name, dowhat, rightsdict)
|
||||
elif group_re.search(entry):
|
||||
if is_group_member(entry, name):
|
||||
allowed = rightsdict.get(dowhat)
|
||||
else:
|
||||
for special in self.special_users:
|
||||
if is_group_member(entry, special):
|
||||
handler = getattr(self, "_special_" + special, None)
|
||||
allowed = handler(request, name, dowhat, rightsdict)
|
||||
break # order of self.special_users is important
|
||||
elif entry == name:
|
||||
allowed = rightsdict.get(dowhat)
|
||||
if allowed is not None:
|
||||
return allowed
|
||||
return allowed # should be None
|
||||
|
||||
def getString(self, b='#acl ', e='\n'):
|
||||
"""print the acl strings we were fed with"""
|
||||
if self.acl_lines:
|
||||
acl_lines = ''.join(["%s%s%s" % (b, l, e) for l in self.acl_lines])
|
||||
else:
|
||||
acl_lines = ''
|
||||
return acl_lines
|
||||
|
||||
def _special_All(self, request, name, dowhat, rightsdict):
|
||||
return rightsdict.get(dowhat)
|
||||
|
||||
def _special_Known(self, request, name, dowhat, rightsdict):
|
||||
""" check if user <name> is known to us,
|
||||
that means that there is a valid user account present.
|
||||
works for subscription emails.
|
||||
"""
|
||||
if user.getUserId(request, name): # is a user with this name known?
|
||||
return rightsdict.get(dowhat)
|
||||
return None
|
||||
|
||||
def _special_Trusted(self, request, name, dowhat, rightsdict):
|
||||
""" check if user <name> is known AND has logged in using a trusted
|
||||
authentication method.
|
||||
Does not work for subsription emails that should be sent to <user>,
|
||||
as he is not logged in in that case.
|
||||
"""
|
||||
if (request.user.name == name and
|
||||
request.user.auth_method in request.cfg.auth_methods_trusted):
|
||||
return rightsdict.get(dowhat)
|
||||
return None
|
||||
|
||||
def __eq__(self, other):
|
||||
return self.acl_lines == other.acl_lines
|
||||
|
||||
def __ne__(self, other):
|
||||
return self.acl_lines != other.acl_lines
|
||||
|
||||
|
||||
class ACLStringIterator:
|
||||
""" Iterator for acl string
|
||||
|
||||
Parse acl string and return the next entry on each call to
|
||||
next. Implement the Iterator protocol.
|
||||
|
||||
Usage:
|
||||
iter = ACLStringIterator(cfg.acl_rights_valid, 'user name:right')
|
||||
for modifier, entries, rights in iter:
|
||||
# process data
|
||||
"""
|
||||
|
||||
def __init__(self, rights, aclstring):
|
||||
""" Initialize acl iterator
|
||||
|
||||
@param rights: the acl rights to consider when parsing
|
||||
@param aclstring: string to parse
|
||||
"""
|
||||
self.rights = rights
|
||||
self.rest = aclstring.strip()
|
||||
self.finished = 0
|
||||
|
||||
def __iter__(self):
|
||||
""" Required by the Iterator protocol """
|
||||
return self
|
||||
|
||||
def next(self):
|
||||
""" Return the next values from the acl string
|
||||
|
||||
When the iterator is finished and you try to call next, it
|
||||
raises a StopIteration. The iterator finish as soon as the
|
||||
string is fully parsed or can not be parsed any more.
|
||||
|
||||
@rtype: 3 tuple - (modifier, [entry, ...], [right, ...])
|
||||
@return: values for one item in an acl string
|
||||
"""
|
||||
# Handle finished state, required by iterator protocol
|
||||
if self.rest == '':
|
||||
self.finished = 1
|
||||
if self.finished:
|
||||
raise StopIteration
|
||||
|
||||
# Get optional modifier [+|-]entries:rights
|
||||
modifier = ''
|
||||
if self.rest[0] in ('+', '-'):
|
||||
modifier, self.rest = self.rest[0], self.rest[1:]
|
||||
|
||||
# Handle the Default meta acl
|
||||
if self.rest.startswith('Default ') or self.rest == 'Default':
|
||||
self.rest = self.rest[8:]
|
||||
entries, rights = ['Default'], []
|
||||
|
||||
# Handle entries:rights pairs
|
||||
else:
|
||||
# Get entries
|
||||
try:
|
||||
entries, self.rest = self.rest.split(':', 1)
|
||||
except ValueError:
|
||||
self.finished = 1
|
||||
raise StopIteration("Can't parse rest of string")
|
||||
if entries == '':
|
||||
entries = []
|
||||
else:
|
||||
# TODO strip each entry from blanks?
|
||||
entries = entries.split(',')
|
||||
|
||||
# Get rights
|
||||
try:
|
||||
rights, self.rest = self.rest.split(' ', 1)
|
||||
# Remove extra white space after rights fragment,
|
||||
# allowing using multiple spaces between items.
|
||||
self.rest = self.rest.lstrip()
|
||||
except ValueError:
|
||||
rights, self.rest = self.rest, ''
|
||||
rights = [r for r in rights.split(',') if r in self.rights]
|
||||
|
||||
return modifier, entries, rights
|
||||
|
||||
|
||||
def parseACL(request, text):
|
||||
""" Parse acl lines from text and return ACL object """
|
||||
pi, dummy = wikiutil.get_processing_instructions(text)
|
||||
acl_lines = [args for verb, args in pi if verb == 'acl']
|
||||
return AccessControlList(request.cfg, acl_lines)
|
||||
|
501
wiki-lenny/share/security.__init__.py
Normal file
501
wiki-lenny/share/security.__init__.py
Normal file
|
@ -0,0 +1,501 @@
|
|||
# -*- coding: iso-8859-1 -*-
|
||||
"""
|
||||
MoinMoin - Wiki Security Interface and Access Control Lists
|
||||
|
||||
|
||||
This implements the basic interface for user permissions and
|
||||
system policy. If you want to define your own policy, inherit
|
||||
from the base class 'Permissions', so that when new permissions
|
||||
are defined, you get the defaults.
|
||||
|
||||
Then assign your new class to "SecurityPolicy" in wikiconfig;
|
||||
and I mean the class, not an instance of it!
|
||||
|
||||
@copyright: 2000-2004 Juergen Hermann <jh@web.de>,
|
||||
2003-2008 MoinMoin:ThomasWaldmann,
|
||||
2003 Gustavo Niemeyer,
|
||||
2005 Oliver Graf,
|
||||
2007 Alexander Schremmer
|
||||
@license: GNU GPL, see COPYING for details.
|
||||
"""
|
||||
|
||||
import re
|
||||
|
||||
from MoinMoin import wikiutil, user
|
||||
from MoinMoin.Page import Page
|
||||
|
||||
#### HACK SAUVAGE 1/5
|
||||
import sys
|
||||
sys.path.append('/usr/scripts/gestion/')
|
||||
from iptools import is_crans
|
||||
#### FIN DU HACK 1/5
|
||||
|
||||
#############################################################################
|
||||
### Basic Permissions Interface -- most features enabled by default
|
||||
#############################################################################
|
||||
|
||||
def _check(request, pagename, username, right):
|
||||
""" Check <right> access permission for user <username> on page <pagename>
|
||||
|
||||
For cfg.acl_hierarchic=False we just check the page in question.
|
||||
|
||||
For cfg.acl_hierarchic=True we, we check each page in the hierarchy. We
|
||||
start with the deepest page and recurse to the top of the tree.
|
||||
If one of those permits, True is returned.
|
||||
|
||||
For both configurations, we check acl_rights_before before the page/default
|
||||
acl and acl_rights_after after the page/default acl, of course.
|
||||
|
||||
This method should not be called by users, use __getattr__ instead.
|
||||
|
||||
@param request: the current request object
|
||||
@param pagename: pagename to get permissions from
|
||||
@param username: the user name
|
||||
@param right: the right to check
|
||||
|
||||
@rtype: bool
|
||||
@return: True if you have permission or False
|
||||
"""
|
||||
cache = request.cfg.cache
|
||||
allowed = cache.acl_rights_before.may(request, username, right)
|
||||
if allowed is not None:
|
||||
return allowed
|
||||
|
||||
if request.cfg.acl_hierarchic:
|
||||
pages = pagename.split('/') # create page hierarchy list
|
||||
some_acl = False
|
||||
for i in range(len(pages), 0, -1):
|
||||
# Create the next pagename in the hierarchy
|
||||
# starting at the leaf, going to the root
|
||||
name = '/'.join(pages[:i])
|
||||
# Get page acl and ask for permission
|
||||
acl = Page(request, name).getACL(request)
|
||||
if acl.acl:
|
||||
some_acl = True
|
||||
allowed = acl.may(request, username, right)
|
||||
if allowed is not None:
|
||||
return allowed
|
||||
if not some_acl:
|
||||
allowed = cache.acl_rights_default.may(request, username, right)
|
||||
if allowed is not None:
|
||||
return allowed
|
||||
else:
|
||||
if request.page is not None and pagename == request.page.page_name:
|
||||
p = request.page # reuse is good
|
||||
else:
|
||||
p = Page(request, pagename)
|
||||
acl = p.getACL(request) # this will be fast in a reused page obj
|
||||
allowed = acl.may(request, username, right)
|
||||
if allowed is not None:
|
||||
return allowed
|
||||
|
||||
allowed = cache.acl_rights_after.may(request, username, right)
|
||||
if allowed is not None:
|
||||
return allowed
|
||||
|
||||
return False
|
||||
|
||||
|
||||
class Permissions:
|
||||
""" Basic interface for user permissions and system policy.
|
||||
|
||||
Note that you still need to allow some of the related actions, this
|
||||
just controls their behavior, not their activation.
|
||||
|
||||
When sub classing this class, you must extend the class methods, not
|
||||
replace them, or you might break the acl in the wiki. Correct sub
|
||||
classing looks like this:
|
||||
|
||||
def read(self, pagename):
|
||||
# Your special security rule
|
||||
if something:
|
||||
return false
|
||||
|
||||
# Do not return True or you break acl!
|
||||
# This call will use the default acl rules
|
||||
return Permissions.read(pagename)
|
||||
"""
|
||||
|
||||
def __init__(self, user):
|
||||
self.name = user.name
|
||||
self.request = user._request
|
||||
|
||||
def save(self, editor, newtext, rev, **kw):
|
||||
""" Check whether user may save a page.
|
||||
|
||||
`editor` is the PageEditor instance, the other arguments are
|
||||
those of the `PageEditor.saveText` method.
|
||||
|
||||
@param editor: PageEditor instance.
|
||||
@param newtext: new page text, you can enable of disable saving according
|
||||
to the content of the text, e.g. prevent link spam.
|
||||
@param rev: new revision number? XXX
|
||||
@param kw: XXX
|
||||
@rtype: bool
|
||||
@return: True if you can save or False
|
||||
"""
|
||||
return self.write(editor.page_name)
|
||||
|
||||
def __getattr__(self, attr):
|
||||
""" Shortcut to export getPermission function for all known ACL rights
|
||||
|
||||
if attr is one of the rights in acl_rights_valid, then return a
|
||||
checking function for it. Else raise an AttributeError.
|
||||
|
||||
@param attr: one of ACL rights as defined in acl_rights_valid
|
||||
@rtype: function
|
||||
@return: checking function for that right, accepting a pagename
|
||||
"""
|
||||
request = self.request
|
||||
if attr not in request.cfg.acl_rights_valid:
|
||||
raise AttributeError, attr
|
||||
return lambda pagename: _check(self.request, pagename, self.name, attr)
|
||||
|
||||
|
||||
# make an alias for the default policy
|
||||
Default = Permissions
|
||||
|
||||
|
||||
class AccessControlList:
|
||||
''' Access Control List
|
||||
|
||||
Control who may do what on or with a wiki page.
|
||||
|
||||
Syntax of an ACL string:
|
||||
|
||||
[+|-]User[,User,...]:[right[,right,...]] [[+|-]SomeGroup:...] ...
|
||||
... [[+|-]Known:...] [[+|-]All:...]
|
||||
|
||||
"User" is a user name and triggers only if the user matches. Up
|
||||
to version 1.2 only WikiNames were supported, as of version 1.3,
|
||||
any name can be used in acl lines, including name with spaces
|
||||
using esoteric languages.
|
||||
|
||||
"SomeGroup" is a page name matching cfg.page_group_regex with
|
||||
some lines in the form " * Member", defining the group members.
|
||||
|
||||
"Known" is a group containing all valid / known users.
|
||||
|
||||
"All" is a group containing all users (Known and Anonymous users).
|
||||
|
||||
"right" may be an arbitrary word like read, write, delete, admin.
|
||||
Only words in cfg.acl_validrights are accepted, others are
|
||||
ignored. It is allowed to specify no rights, which means that no
|
||||
rights are given.
|
||||
|
||||
How ACL is processed
|
||||
|
||||
When some user is trying to access some ACL-protected resource,
|
||||
the ACLs will be processed in the order they are found. The first
|
||||
matching ACL will tell if the user has access to that resource
|
||||
or not.
|
||||
|
||||
For example, the following ACL tells that SomeUser is able to
|
||||
read and write the resources protected by that ACL, while any
|
||||
member of SomeGroup (besides SomeUser, if part of that group)
|
||||
may also admin that, and every other user is able to read it.
|
||||
|
||||
SomeUser:read,write SomeGroup:read,write,admin All:read
|
||||
|
||||
In this example, SomeUser can read and write but can not admin,
|
||||
revert or delete pages. Rights that are NOT specified on the
|
||||
right list are automatically set to NO.
|
||||
|
||||
Using Prefixes
|
||||
|
||||
To make the system more flexible, there are also two modifiers:
|
||||
the prefixes "+" and "-".
|
||||
|
||||
+SomeUser:read -OtherUser:write
|
||||
|
||||
The acl line above will grant SomeUser read right, and OtherUser
|
||||
write right, but will NOT block automatically all other rights
|
||||
for these users. For example, if SomeUser ask to write, the
|
||||
above acl line does not define if he can or can not write. He
|
||||
will be able to write if acl_rights_before or acl_rights_after
|
||||
allow this (see configuration options).
|
||||
|
||||
Using prefixes, this acl line:
|
||||
|
||||
SomeUser:read,write SomeGroup:read,write,admin All:read
|
||||
|
||||
Can be written as:
|
||||
|
||||
-SomeUser:admin SomeGroup:read,write,admin All:read
|
||||
|
||||
Or even:
|
||||
|
||||
+All:read -SomeUser:admin SomeGroup:read,write,admin
|
||||
|
||||
Notice that you probably will not want to use the second and
|
||||
third examples in ACL entries of some page. They are very
|
||||
useful on the moin configuration entries though.
|
||||
|
||||
Configuration options
|
||||
|
||||
cfg.acl_rights_default
|
||||
It is is ONLY used when no other ACLs are given.
|
||||
Default: "Known:read,write,delete All:read,write",
|
||||
|
||||
cfg.acl_rights_before
|
||||
When the page has ACL entries, this will be inserted BEFORE
|
||||
any page entries.
|
||||
Default: ""
|
||||
|
||||
cfg.acl_rights_after
|
||||
When the page has ACL entries, this will be inserted AFTER
|
||||
any page entries.
|
||||
Default: ""
|
||||
|
||||
cfg.acl_rights_valid
|
||||
These are the acceptable (known) rights (and the place to
|
||||
extend, if necessary).
|
||||
Default: ["read", "write", "delete", "admin"]
|
||||
'''
|
||||
|
||||
#special_users = ["All", "Known", "Trusted"] # order is important
|
||||
## HACK SAUVAGE 2/5
|
||||
special_users = ["All", "Known", "Trusted", "Crans", "NoCrans"] # order is important
|
||||
## FIN HACK 2/5
|
||||
|
||||
def __init__(self, cfg, lines=[]):
|
||||
"""Initialize an ACL, starting from <nothing>.
|
||||
"""
|
||||
if lines:
|
||||
self.acl = [] # [ ('User', {"read": 0, ...}), ... ]
|
||||
self.acl_lines = []
|
||||
for line in lines:
|
||||
self._addLine(cfg, line)
|
||||
else:
|
||||
self.acl = None
|
||||
self.acl_lines = None
|
||||
|
||||
def _addLine(self, cfg, aclstring, remember=1):
|
||||
""" Add another ACL line
|
||||
|
||||
This can be used in multiple subsequent calls to process longer lists.
|
||||
|
||||
@param cfg: current config
|
||||
@param aclstring: acl string from page or cfg
|
||||
@param remember: should add the line to self.acl_lines
|
||||
"""
|
||||
|
||||
# Remember lines
|
||||
if remember:
|
||||
self.acl_lines.append(aclstring)
|
||||
|
||||
# Iterate over entries and rights, parsed by acl string iterator
|
||||
acliter = ACLStringIterator(cfg.acl_rights_valid, aclstring)
|
||||
for modifier, entries, rights in acliter:
|
||||
if entries == ['Default']:
|
||||
self._addLine(cfg, cfg.acl_rights_default, remember=0)
|
||||
else:
|
||||
for entry in entries:
|
||||
rightsdict = {}
|
||||
if modifier:
|
||||
# Only user rights are added to the right dict.
|
||||
# + add rights with value of 1
|
||||
# - add right with value of 0
|
||||
for right in rights:
|
||||
rightsdict[right] = (modifier == '+')
|
||||
else:
|
||||
# All rights from acl_rights_valid are added to the
|
||||
# dict, user rights with value of 1, and other with
|
||||
# value of 0
|
||||
for right in cfg.acl_rights_valid:
|
||||
rightsdict[right] = (right in rights)
|
||||
self.acl.append((entry, rightsdict))
|
||||
|
||||
def may(self, request, name, dowhat):
|
||||
""" May <name> <dowhat>? Returns boolean answer.
|
||||
|
||||
Note: this check does NOT include the acl_rights_before / _after ACL,
|
||||
but it WILL use acl_rights_default if there is no (page) ACL.
|
||||
"""
|
||||
if self.acl is None: # no #acl used on Page
|
||||
acl = request.cfg.cache.acl_rights_default.acl
|
||||
else: # we have a #acl on the page (self.acl can be [] if #acl is empty!)
|
||||
acl = self.acl
|
||||
is_group_member = request.dicts.has_member
|
||||
group_re = request.cfg.cache.page_group_regexact
|
||||
allowed = None
|
||||
for entry, rightsdict in acl:
|
||||
if entry in self.special_users:
|
||||
handler = getattr(self, "_special_"+entry, None)
|
||||
allowed = handler(request, name, dowhat, rightsdict)
|
||||
elif group_re.search(entry):
|
||||
if is_group_member(entry, name):
|
||||
allowed = rightsdict.get(dowhat)
|
||||
else:
|
||||
for special in self.special_users:
|
||||
if is_group_member(entry, special):
|
||||
handler = getattr(self, "_special_" + special, None)
|
||||
allowed = handler(request, name, dowhat, rightsdict)
|
||||
break # order of self.special_users is important
|
||||
elif entry == name:
|
||||
allowed = rightsdict.get(dowhat)
|
||||
if allowed is not None:
|
||||
return allowed
|
||||
return allowed # should be None
|
||||
|
||||
def getString(self, b='#acl ', e='\n'):
|
||||
"""print the acl strings we were fed with"""
|
||||
if self.acl_lines:
|
||||
acl_lines = ''.join(["%s%s%s" % (b, l, e) for l in self.acl_lines])
|
||||
else:
|
||||
acl_lines = ''
|
||||
return acl_lines
|
||||
|
||||
def _special_All(self, request, name, dowhat, rightsdict):
|
||||
## HACK SAUVAGE 3/5
|
||||
if dowhat == "read" and is_page_public(request):
|
||||
return True
|
||||
## FIN HACK 3/5
|
||||
return rightsdict.get(dowhat)
|
||||
|
||||
def _special_Known(self, request, name, dowhat, rightsdict):
|
||||
""" check if user <name> is known to us,
|
||||
that means that there is a valid user account present.
|
||||
works for subscription emails.
|
||||
"""
|
||||
if user.getUserId(request, name): # is a user with this name known?
|
||||
return rightsdict.get(dowhat)
|
||||
return None
|
||||
|
||||
def _special_Trusted(self, request, name, dowhat, rightsdict):
|
||||
""" check if user <name> is known AND has logged in using a trusted
|
||||
authentication method.
|
||||
Does not work for subsription emails that should be sent to <user>,
|
||||
as he is not logged in in that case.
|
||||
"""
|
||||
if (request.user.name == name and
|
||||
request.user.auth_method in request.cfg.auth_methods_trusted):
|
||||
return rightsdict.get(dowhat)
|
||||
return None
|
||||
|
||||
#### HACK SAUVAGE 4/5
|
||||
def _requete_interne(self, request):
|
||||
try:
|
||||
if is_crans(request.remote_addr) and (request.remote_addr != u'138.231.136.3' or is_crans(request.mpyreq.headers_in['X-Forwarded-For'].split(",")[-1].strip())):
|
||||
return True
|
||||
except:
|
||||
pass
|
||||
|
||||
return False
|
||||
|
||||
def _special_Crans(self, request, name, dowhat, rightsdict):
|
||||
if self._requete_interne(request):
|
||||
return rightsdict.get(dowhat)
|
||||
return None
|
||||
|
||||
def _special_NoCrans(self, request, name, dowhat, rightsdict):
|
||||
if dowhat == "read" and is_page_public(request):
|
||||
return True
|
||||
if not self._requete_interne(request):
|
||||
return rightsdict.get(dowhat)
|
||||
return None
|
||||
#### FIN Du HACK 4/5
|
||||
|
||||
def __eq__(self, other):
|
||||
return self.acl_lines == other.acl_lines
|
||||
|
||||
def __ne__(self, other):
|
||||
return self.acl_lines != other.acl_lines
|
||||
|
||||
|
||||
class ACLStringIterator:
|
||||
""" Iterator for acl string
|
||||
|
||||
Parse acl string and return the next entry on each call to
|
||||
next. Implement the Iterator protocol.
|
||||
|
||||
Usage:
|
||||
iter = ACLStringIterator(cfg.acl_rights_valid, 'user name:right')
|
||||
for modifier, entries, rights in iter:
|
||||
# process data
|
||||
"""
|
||||
|
||||
def __init__(self, rights, aclstring):
|
||||
""" Initialize acl iterator
|
||||
|
||||
@param rights: the acl rights to consider when parsing
|
||||
@param aclstring: string to parse
|
||||
"""
|
||||
self.rights = rights
|
||||
self.rest = aclstring.strip()
|
||||
self.finished = 0
|
||||
|
||||
def __iter__(self):
|
||||
""" Required by the Iterator protocol """
|
||||
return self
|
||||
|
||||
def next(self):
|
||||
""" Return the next values from the acl string
|
||||
|
||||
When the iterator is finished and you try to call next, it
|
||||
raises a StopIteration. The iterator finish as soon as the
|
||||
string is fully parsed or can not be parsed any more.
|
||||
|
||||
@rtype: 3 tuple - (modifier, [entry, ...], [right, ...])
|
||||
@return: values for one item in an acl string
|
||||
"""
|
||||
# Handle finished state, required by iterator protocol
|
||||
if self.rest == '':
|
||||
self.finished = 1
|
||||
if self.finished:
|
||||
raise StopIteration
|
||||
|
||||
# Get optional modifier [+|-]entries:rights
|
||||
modifier = ''
|
||||
if self.rest[0] in ('+', '-'):
|
||||
modifier, self.rest = self.rest[0], self.rest[1:]
|
||||
|
||||
# Handle the Default meta acl
|
||||
if self.rest.startswith('Default ') or self.rest == 'Default':
|
||||
self.rest = self.rest[8:]
|
||||
entries, rights = ['Default'], []
|
||||
|
||||
# Handle entries:rights pairs
|
||||
else:
|
||||
# Get entries
|
||||
try:
|
||||
entries, self.rest = self.rest.split(':', 1)
|
||||
except ValueError:
|
||||
self.finished = 1
|
||||
raise StopIteration("Can't parse rest of string")
|
||||
if entries == '':
|
||||
entries = []
|
||||
else:
|
||||
# TODO strip each entry from blanks?
|
||||
entries = entries.split(',')
|
||||
|
||||
# Get rights
|
||||
try:
|
||||
rights, self.rest = self.rest.split(' ', 1)
|
||||
# Remove extra white space after rights fragment,
|
||||
# allowing using multiple spaces between items.
|
||||
self.rest = self.rest.lstrip()
|
||||
except ValueError:
|
||||
rights, self.rest = self.rest, ''
|
||||
rights = [r for r in rights.split(',') if r in self.rights]
|
||||
|
||||
return modifier, entries, rights
|
||||
|
||||
|
||||
def parseACL(request, text):
|
||||
""" Parse acl lines from text and return ACL object """
|
||||
pi, dummy = wikiutil.get_processing_instructions(text)
|
||||
acl_lines = [args for verb, args in pi if verb == 'acl']
|
||||
return AccessControlList(request.cfg, acl_lines)
|
||||
|
||||
#### HACK SAUVAGE 5/5
|
||||
def is_page_public(request):
|
||||
#return True
|
||||
## On recherche si la page est publique
|
||||
this_page = request.page.page_name
|
||||
categories = request.page.getCategories(request)
|
||||
if u'CatégoriePagePublique' in categories:
|
||||
return True
|
||||
else:
|
||||
return None
|
||||
#### FIn DU HACK 5/5
|
Loading…
Add table
Add a link
Reference in a new issue