diff --git a/wiki/PageGraphicalEditor.py b/wiki/PageGraphicalEditor.py deleted file mode 100644 index e60205cf..00000000 --- a/wiki/PageGraphicalEditor.py +++ /dev/null @@ -1,365 +0,0 @@ -# -*- coding: iso-8859-1 -*- -""" - MoinMoin - Call the GUI editor (FCKeditor) - - @copyright: (c) Bastian Blank, Florian Festi, Thomas Waldmann - @license: GNU GPL, see COPYING for details. -""" - -from MoinMoin import PageEditor -import os, time, codecs, re - -#### HACK SAUVAGE 1/2 -from MoinMoin import caching, config, user, util, wikiutil, error, search -#### FIN DU HACK 1/2 -from MoinMoin.Page import Page -from MoinMoin.widget import html -from MoinMoin.widget.dialog import Status -from MoinMoin.logfile import editlog, eventlog -from MoinMoin.util import filesys -import MoinMoin.util.web -import MoinMoin.util.mail -from MoinMoin.parser.wiki import Parser - -from StringIO import StringIO - -def execute(pagename, request): - if not request.user.may.write(pagename): - _ = request.getText - Page(request, pagename).send_page(request, - msg = _('You are not allowed to edit this page.')) - return - - PageGraphicalEditor(request, pagename).sendEditor() - - -class PageGraphicalEditor(PageEditor.PageEditor): - - def word_rule(self): - regex = re.compile(r"\(\?" + edit_lock_message - else: - msg = edit_lock_message - - #### HACK SAUVAGE 2/2 - query = search.QueryParser().parse_query(u'CatégorieEditeurGraphiqueInterdit') - page = search.Page(request, self.page_name) - if query.search(page): - msg = _('You cannot use the graphical editor on this page.') - #### FIN HACK 2/2 - - # Did one of the prechecks fail? - if msg: - self.send_page(self.request, msg=msg) - return - - # Check for preview submit - if preview is None: - title = _('Edit "%(pagename)s"') - else: - title = _('Preview of "%(pagename)s"') - 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 self.request.user.valid: - text_rows = int(self.request.user.edit_rows) - - if preview is not None: - # Propagate original revision - rev = int(form['rev'][0]) - - # 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! -Have a look at the diff of %(difflink)s to see what has been changed.""") % { - 'difflink': self.link_to(self.request, - querystr='action=diff&rev=%d' % rev) - } - 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 - - # Page editing is done using user language - self.request.setContentLanguage(self.request.lang) - - # Setup status message - status = [kw.get('msg', ''), conflict_msg, edit_lock_message] - status = [msg for msg in status if msg] - status = ' '.join(status) - status = Status(self.request, content=status) - - wikiutil.send_title(self.request, - title % {'pagename': self.split_title(self.request),}, - page=self, - pagename=self.page_name, msg=status, - html_head=self.lock.locktype and ( - PageEditor._countdown_js % { - 'countdown_script': self.request.theme.externalScript('countdown'), - 'lock_timeout': lock_timeout, - 'lock_expire': lock_expire, - 'lock_mins': lock_mins, - 'lock_secs': lock_secs, - }) or '', - editor_mode=1, - ) - - self.request.write(self.request.formatter.startContent("content")) - - # 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() - 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 form.has_key('template'): - # If the page does not exists, we try to get the content from the template parameter. - template_page = wikiutil.unquoteWikiname(form['template'][0]) - if self.request.user.may.read(template_page): - raw_body = Page(self.request, template_page).get_raw_body() - if raw_body: - self.request.write(_("[Content of new page loaded from %s]") % (template_page,), '
') - else: - self.request.write(_("[Template %s not found]") % (template_page,), '
') - else: - self.request.write(_("[You may not read %s]") % (template_page,), '
') - - # Make backup on previews - but not for new empty pages - if preview and raw_body: - self._make_backup(raw_body) - - # Generate default content for new pages - if not raw_body: - raw_body = _('Describe %s here.') % (self.page_name,) - - # send form - self.request.write('
' % ( - self.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/ - self.request.write('
') - - self.request.write(unicode(html.INPUT(type="hidden", name="action", value="edit"))) - - # Send revision of the page our edit is based on - self.request.write('' % (rev,)) - - # Save backto in a hidden input - backto = form.get('backto', [None])[0] - if backto: - self.request.write(unicode(html.INPUT(type="hidden", name="backto", value=backto))) - - # button bar - button_spellcheck = (SpellCheck and - '' - % _('Check Spelling')) or '' - - save_button_text = _('Save Changes') - cancel_button_text = _('Cancel') - - if self.cfg.page_license_enabled: - self.request.write('

', _( -"""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.""") % { - 'save_button_text': save_button_text, - 'cancel_button_text': cancel_button_text, - 'license_link': wikiutil.getSysPage(self.request, self.cfg.page_license_page).link_to(self.request), - }, '

') - - self.request.write(''' - - - -%s - - -''' % (save_button_text, _('Preview'), _('Text mode'), button_spellcheck, cancel_button_text,)) - - self.sendconfirmleaving() # TODO update state of flgChange to make this work, see PageEditor - - # Add textarea with page text - - # TODO: currently self.language is None at this point. We have - # to do processing instructions parsing earlier, or move page - # language into meta file. - lang = self.language or self.request.cfg.language_default - contentlangdirection = i18n.getDirection(lang) # 'ltr' or 'rtl' - uilanguage = self.request.lang - url_prefix = self.request.cfg.url_prefix - wikipage = wikiutil.quoteWikinameURL(self.page_name) - fckbasepath = url_prefix + '/applets/FCKeditor' - wikiurl = request.getScriptname() - if not wikiurl or wikiurl[-1] != '/': - wikiurl += '/' - themepath = '%s/%s' % (url_prefix, self.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() - - self.request.write(""" - - -""") - self.request.write("

") - self.request.write(_("Comment:"), - ' ' % ( - wikiutil.escape(kw.get('comment', ''), 1), )) - self.request.write("

") - - # Category selection - filter = re.compile(self.cfg.page_category_regex, re.UNICODE).search - cat_pages = self.request.rootpage.getPageList(filter=filter) - cat_pages.sort() - cat_pages = [wikiutil.pagelinkmarkup(p) for p in cat_pages] - cat_pages.insert(0, ('', _('', formatted=False))) - self.request.write("

") - self.request.write(_('Add to: %(category)s') % { - 'category': unicode(util.web.makeSelection('category', cat_pages)), - }) - if self.cfg.mail_enabled: - self.request.write(''' -  - - ''' % { - 'checked': ('', 'checked')[form.get('trivial',['0'])[0] == '1'], - 'label': _("Trivial change"), - }) - - self.request.write(''' -  - - -

''' % { - 'checked': ('', 'checked')[form.get('rstrip',['0'])[0] == '1'], - 'label': _('Remove trailing whitespace from each line') - }) - - self.request.write("

") - - badwords_re = None - if preview is not None: - if SpellCheck and ( - form.has_key('button_spellcheck') or - form.has_key('button_newwords')): - badwords, badwords_re, msg = SpellCheck.checkSpelling(self, self.request, own_form=0) - self.request.write("

%s

" % msg) - self.request.write('
') - self.request.write("
") - - - if preview is not None: - if staytop: - content_id = 'previewbelow' - else: - content_id = 'preview' - self.send_page(self.request, content_id=content_id, content_only=1, - hilite_re=badwords_re) - - self.request.write(self.request.formatter.endContent()) # end content div - wikiutil.send_footer(self.request, self.page_name) - diff --git a/wiki/action/gallery2image.py b/wiki/action/gallery2image.py deleted file mode 100644 index 44710dad..00000000 --- a/wiki/action/gallery2image.py +++ /dev/null @@ -1,398 +0,0 @@ -# -*- coding: iso-8859-1 -*- -""" - MoinMoin - gallery2Image Actionmacro - - PURPOSE:: - This action macro is used to rotate, move to bak or to slide through the images from Gallery2 - - CALLING SEQUENCE:: - called by Gallery2 POST Method - - PROCEDURE:: - see Gallery2 - - Please remove the version number from this file - - RESTRICTIONS:: - spaces in file names are not supported. I don't know how to escape them right. Probaly this does work in 1.3.5 - - MODIFICATION HISTORY:: - Version 1.3.3.-1 - @copyright: 2005 by Reimar Bauer (R.Bauer@fz-juelich.de) - @license: GNU GPL, see COPYING for details. - 2005-06-24: 1.3.3.-2 feature reqeust of CraigJohnson added - os.path.join used to join platform independent pathes - os.unlink removed to get it more platform independend - 2005-08-06: 1.3.5-3 RB VS mode added - by one step back or forward could be toggled through the selected slides - and the first and last one could be selected too - 2005-08-07 1.3.5-4 RB bug fixed for cgi-bin call. formatting of tables adjusted - 2005-08-13 1.3.5-5 RB code change from GET to POST - forms instead of link - toggle between webnail and image by click on image - alias (description) and exif_date added - this version needs Gallery2-1.3.5-7.py - 2005-08-31 1.3.5-6 RB html code changed into a function :-) - some html bugs fixed too - instead of button text now images used (disabled buttons are grey color coded) - back link to callers page - whole page inserted into the common wiki page - code clean up. - - - - -""" -Dependencies = [] -import os,string,Image,StringIO -from MoinMoin import config, wikiutil -from MoinMoin.PageEditor import PageEditor -from MoinMoin import user, util -from MoinMoin.Page import Page -from MoinMoin.action import AttachFile -from MoinMoin.formatter.text_html import Formatter -from MoinMoin.parser import wiki - -def html_show_image(request,pagename,url_wiki_page,full,alias,exif_date,target,idx): - - n = len(target) - last_disabled = '' - last_status = '' - first_disabled = '' - first_status = '' - previous = idx - 1 - next = idx + 1 - - if idx == n-1 : - last_disabled = 'disabled' - last_status = '_disabled' - - if idx == 0 : - first_disabled = 'disabled' - first_status = '_disabled' - - - if previous < 0 : - previous = 0 - - if next > n - 1 : - next = n - 1 - - if n == 1 : - next = 0 - # previous = 0 - # first_disabled = 'disabled' - # first_status = '_disabled' - # last_disabled = 'disabled' - # last_status = '_disabled' - - html = ''' - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - -
- - - - - - - -
- - - - - - - -
- - - - - - - -
- - - - - - - -
- - - - - - - -
-
- - - - - - - -
-

- %(this_alias_text)s -

-
-

- %(this_exif_date_text)s -

-
''' % { - -"base_url" : request.getScriptname(), -"first_status" : first_status, -"last_status" : last_status, -"first_full_list" : full[0] + "," + string.join(full,','), -"first_alias_list" : alias[0] + '!,!' + string.join(alias,'!,!'), -"first_exif_date_list" : exif_date[0] + ',' + string.join(exif_date,','), -"first_target_list" : target[0] + "," + string.join(target,','), - -"previous_full_list" : full[previous] + "," + string.join(full,','), -"previous_alias_list" : alias[previous] + '!,!' + string.join(alias,'!,!'), -"previous_exif_date_list" : exif_date[previous] + ',' + string.join(exif_date,','), -"previous_target_list" : target[previous] + "," + string.join(target,','), - -"next_full_list" : full[next] + "," + string.join(full,','), -"next_alias_list" : alias[next] + '!,!' + string.join(alias,'!,!'), -"next_exif_date_list" : exif_date[next] + ',' + string.join(exif_date,','), -"next_target_list" : target[next] + "," + string.join(target,','), - -"last_full_list" : full[n-1] + "," + string.join(full,','), -"last_alias_list" : alias[n-1] + '!,!' + string.join(alias,'!,!'), -"last_exif_date_list" : exif_date[n-1] + ',' + string.join(exif_date,','), -"last_target_list" : target[n-1] + "," + string.join(target,','), - -"this_full_list" : full[idx] + "," + string.join(full,','), -"this_alias_list" : alias[idx] + '!,!' + string.join(alias,'!,!'), -"this_exif_date_list" : exif_date[idx] + ',' + string.join(exif_date,','), -"this_target_list" : target[idx] + "," + string.join(target,','), - -"first_disabled" : first_disabled, -"last_disabled" : last_disabled, -"this_alias_text" : alias[idx], -"this_exif_date_text" : exif_date[idx], -"this_image" : AttachFile.getAttachUrl(pagename,target[idx],request), -"url_wiki_page" : url_wiki_page, -"pagename" : pagename -} - - - return html - -def to_wikiname(request,text): - - #taken from test_parser_wiki - page = Page(request, 'ThisPageDoesNotExistsAndWillNeverBeReally') - page.formatter = Formatter(request) - request.formatter = page.formatter - page.formatter.setPage(page) - page.hilite_re = None - - out=StringIO.StringIO() - request.redirect(out) - wikiizer = wiki.Parser(text.strip(),request) - wikiizer.format(page.formatter) - result = out.getvalue() - request.redirect() - del out - - return result.strip() - - -action_name = __name__.split('.')[-1] - -def execute(pagename, request): - """ Main dispatcher for the 'Gallery' action. - """ - _ = request.getText - - request.formatter = Formatter(request) - attachment_path = AttachFile.getAttachDir(request,pagename) - if request.form['do'][0] == 'VS' : - web = {} - images = string.split(request.form['target'][0],',') - target = images[0] - images = (images[1:]) - - full_image = string.split(request.form['full'][0],',') - full_target = full_image[0] - full_image = (full_image[1:]) - - all_description = string.split(request.form['alias'][0],'!,!') - this_description = all_description[0] - all_description = (all_description[1:]) - - all_exif_date = string.split(request.form['exif_date'][0],',') - this_exif_date = all_exif_date[0] - all_exif_date = (all_exif_date[1:]) - - z = 0 - for img in images : - if target == img : - idx = z - - z += 1 - n = len(images) - - ######## url_wiki_page ############################################################# - text = pagename - url = pagename - url_wiki_page = wikiutil.link_tag(request, url, text = text, - formatter = request.formatter) - ############################################################################ - - attachment_path = AttachFile.getAttachDir(request,pagename) - - web['src'] = AttachFile.getAttachUrl(pagename,target,request) - web['title'] = target - #web['width']="1024" - - - image_link=request.formatter.image(**web) - - - request.http_headers() - request.setContentLanguage(request.lang) - wikiutil.send_title(request, pagename, - pagename=pagename) - request.write(request.formatter.startContent("content")) - - - html = html_show_image(request,pagename,url_wiki_page,full_image,all_description,all_exif_date,images,idx) - request.write(html) - request.write(request.formatter.endContent()) - wikiutil.send_footer(request, pagename) - msg = None - #return - - elif request.form['do'][0] == 'PS' : - images=string.split(request.form['target'][0],',') - attachment_path = AttachFile.getAttachDir(request,pagename) - target=request.form['target'][0] - - msg= _('not finished by now') #+ target - - elif request.form['do'][0] == 'BS' : - - msg = "gone back" #None - - elif request.user.may.delete(pagename): - # only users which are allowed to delete should use this tool - - target=request.form['target'][0] - file, ext = os.path.splitext(target) - - if ext == '.gif' or ext == '.png' : - img_type = 'PNG' - thumbfile = "thumbnail_%(file)s.png" % {"file" : file} - webnail = "webnail_%(file)s.png" % {"file" : file} - else: - img_type="JPEG" - thumbfile="thumbnail_%(file)s.jpg" % {"file" : file} - webnail="webnail_%(file)s.jpg" % {"file" : file} - - thumb = os.path.join(attachment_path,thumbfile) - webf = os.path.join(attachment_path,webnail) - infile = os.path.join(attachment_path,target) - - msg = None - if action_name in request.cfg.excluded_actions: - msg = _('File attachments are not allowed in this wiki!') - - elif request.form['do'][0] == 'RM' : - if os.path.exists(infile + '.bak') : - os.unlink("%(file)s.bak" % {"file" : infile}) - os.link(infile,"%(file)s.bak" % {"file" : infile}) - os.unlink(infile) - os.unlink(webf) - os.unlink(thumb) - - msg = _('%(target)s deleted, backup in place' % { - 'target':target}) - - elif request.form['do'][0] == 'RL' : - im = Image.open(infile) - #os.unlink(infile) - im.rotate(90).save(infile,img_type) - nim = Image.open(infile) - nim.thumbnail((640,640), Image.ANTIALIAS) - #os.unlink(webf) - nim.save(webf, img_type) - nim.thumbnail((128, 128), Image.ANTIALIAS) - #os.unlink(thumb) - nim.save(thumb, img_type) - msg= _('%(target)s rotated to left 90 degrees' % { - 'target':target}) - - elif request.form['do'][0] == 'RR' : - im = Image.open(infile) - #os.unlink(infile) - im.rotate(270).save(infile,img_type) - - - nim = Image.open(infile) - - nim.thumbnail((640,640), Image.ANTIALIAS) - #os.unlink(webf) - nim.save(webf, img_type) - nim.thumbnail((128, 128), Image.ANTIALIAS) - #os.unlink(thumb) - nim.save(thumb, img_type) - msg= _('%(target)s rotated to right 90 degrees' % { - 'target':target}) - - - - - else: - msg = _('action not implemented: %s') % (request.form['do'][0],) - else: - msg = _('Your are not allowed to change images on this page: %s') % (pagename,) - - if msg: - AttachFile.error_msg(pagename, request, msg) - - return() diff --git a/wiki/action/opensearch.py b/wiki/action/opensearch.py deleted file mode 100644 index 723fb67e..00000000 --- a/wiki/action/opensearch.py +++ /dev/null @@ -1,83 +0,0 @@ -# -*- coding: iso-8859-1 -*- -""" - MoinMoin - "opensearch" action - - Generate an opensearch xml description. - - @copyright: 2006 by Grégoire Détrez - @license: GNU GPL, see COPYING for details. -""" - -from MoinMoin import config, wikiutil -from MoinMoin.util import MoinMoinNoFooter -from MoinMoin.wikixml.util import XMLGenerator -import StringIO -from xml.sax import saxutils - -def execute(pagename, request): - _ = request.getText - form = request.form - - if form.has_key('searchtype'): - searchtype = form['searchtype'][0] - else: - searchtype = "Titres" - - request.http_headers(["Content-Type: text/xml; charset=%s" % config.charset ]) - - name = request.cfg.sitename + " (%s)" % searchtype - if searchtype == "Titres": - Desc = "%s, recherche dans les titres" % request.cfg.sitename - else: - Desc = "%s, recherche dans le texte" % request.cfg.sitename - - if searchtype == "Titres": - searchtype_arg = "titlesearch=Titres" - else: - searchtype_arg = "fullsearch=Texte" - server_search_addr = "http://%s%s?action=fullsearch&context=180&value={searchTerms}&%s" % (request.http_host, request.script_name, searchtype_arg) - - # prepare output - out = StringIO.StringIO() - handler = OpenSearchGenerator(out) - - - handler.startDocument() - - handler.node('ShortName', name) - handler.node('Description', Desc) - - handler.node('Image', 'http://%s/favicon.ico' % request.http_host, { - 'height': "16", - 'width': "16", - 'type': "image/x-icon", - }) - handler.node('Url', None, { - 'template': server_search_addr, - 'method': "get", - 'type': "text/html", - }) - handler.endDocument() - request.write(out.getvalue()) - - raise MoinMoinNoFooter - -class OpenSearchGenerator(saxutils.XMLGenerator): - default_xmlns = { - 'opensearch':"http://a9.com/-/spec/opensearch/1.1/", - } - def __init__(self, out): - saxutils.XMLGenerator.__init__(self, out=out, encoding=config.charset) - #self.xmlns = self.default_xmlns - def startDocument(self): - saxutils.XMLGenerator.startDocument(self) - self.startElement('OpenSearchDescription', {'xmlns': "http://a9.com/-/spec/opensearch/1.1/"}) - def endDocument(self): - self.endElement('OpenSearchDescription') - saxutils.XMLGenerator.endDocument(self) - def node(self, tag, value, attr={}): - self.startElement(tag, attr) - if value: self.characters(value) - self.endElement(tag) - - diff --git a/wiki/dump-wiki.py b/wiki/dump-wiki.py deleted file mode 100755 index 6be70cc4..00000000 --- a/wiki/dump-wiki.py +++ /dev/null @@ -1,200 +0,0 @@ -#! /usr/bin/env python -# -*- coding: iso-8859-15 -*- -# -# Dumpe une partie du Wiki dans le répertoire donné pour créer -# une copie "statique". -# -# Exemple : python dump-wiki.py --regex WiFi/AvoirLeWifi".*" ~/macopie -# Les pages correspondant à la regex donnée seront placées dans -# le répertoire ~/macopie/wiki. Les attachements seront dans -# ~/macopie/attach. -# -# Actuellement, j'utilise : -# sudo python /usr/scripts/dump-wiki.py --regex 'WiFi(/PositionnementDesBornes|/AvoirLeWifi.*)?' ~/mointest - -#!/usr/bin/python2.3 - -# -*- coding: iso-8859-1 -*- -""" - MoinMoin - Dump a MoinMoin wiki to static pages - - @copyright: 2002-2004 by Jürgen Hermann - @license: GNU GPL, see COPYING for details. -""" - -__version__ = "20040329" - -# use this if your moin installation is not in sys.path: -import sys -sys.path.insert(0, '../..') # path to MoinMoin -sys.path.insert(0, '/etc/moin') - -url_prefix = "." -HTML_SUFFIX = ".html" - -page_template = u''' - - - - -%(pagename)s - - - -

-Ce site est une copie statique et partielle de ce que l'on peut trouver sur le -wiki de l'association. Si vous êtes ici, alors -que vous avez demandé un autre site, c'est sans doute que vous êtes connecté -au réseau wifi de l'association mais que vous n'avez pas encore complété toutes -les étapes nécessaires pour avoir une connexion pleinement fonctionnelle. Ce site -contient donc les infos pour configurer correctement votre connexion. -

- -

%(pagenamewithlinks)s

- -%(pagehtml)s - -

-Cette page a été extraite du wiki le %(timestamp)s. Vous pouvez l'éditer ou voir la page originale. -

- - -''' -#' - -import os, time, StringIO, codecs, shutil, re -from MoinMoin import config, wikiutil, Page -from MoinMoin.script import _util -from MoinMoin.request import RequestCLI -from MoinMoin.action import AttachFile - -class MoinDump(_util.Script): - def __init__(self): - _util.Script.__init__(self, __name__, "[options] ") - - # --regex=REGEX - self.parser.add_option( - "--regex", metavar="REGEX", dest="regex", - help="Ne copie que les pages correspondant à cette regex" - ) - - def mainloop(self): - """ moin-dump's main code. """ - - if len(sys.argv) == 1: - self.parser.print_help() - sys.exit(1) - - # Prepare output directory - outputdir = self.args[0] - outputdir = os.path.abspath(outputdir) - if not os.path.isdir(outputdir): - try: - os.mkdir(outputdir) - _util.log("Created output directory '%s'!" % outputdir) - except OSError: - _util.fatal("Cannot create output directory '%s'!" % outputdir) - - AttachFile.getAttachUrl = lambda pagename, filename, request, addts=0, escaped=0: (get_attachment(request, pagename, filename, outputdir)) - - - # Dump the wiki - request = RequestCLI(u"wiki.crans.org/") - request.form = request.args = request.setup_args() - - # fix url_prefix so we get relative paths in output html - request.cfg.url_prefix = url_prefix - - # Get all existing pages in the wiki - pages = list(request.rootpage.getPageList(user='')) - if self.options.regex: - pages = list(filter(lambda x: re.match(self.options.regex, x), pages)) - - pages.sort() - - quoteWikinameOriUrl = wikiutil.quoteWikinameURL - wikiutil.quoteWikinameURL = lambda pagename, qfn=wikiutil.quoteWikinameFS: (qfn(pagename) + HTML_SUFFIX) - - errfile = os.path.join(outputdir, 'error.log') - errlog = open(errfile, 'w') - errcnt = 0 - - for pagename in pages: - file = wikiutil.quoteWikinameURL(pagename) # we have the same name in URL and FS - # On construit le nom de la page avec les liens (peut sans doute mieux faire) - originalpagename = pagename - pagename = pagename.replace("/PagesStatiques", "") - pagenamewithlinks = [u''] - for composant in pagename.split("/"): - pagenamewithlinks.append(pagenamewithlinks[-1]+'/'+composant) - pagenamewithlinks = u" / ".join(map(lambda x: u'%s' % ( - wikiutil.quoteWikinameURL(x[1:]), x[1:].split("/")[-1]), pagenamewithlinks[1:])) - _util.log('Writing "%s"...' % file) - try: - pagehtml = '' - page = Page.Page(request, originalpagename) - try: - request.reset() - out = StringIO.StringIO() - request.redirect(out) - request.page = page - request.remote_addr = '138.231.136.7' - page.send_page(request, count_hit=0, content_only=1) - pagehtml = out.getvalue() - request.redirect() - except: - errcnt = errcnt + 1 - print >>sys.stderr, "*** Caught exception while writing page!" - print >>errlog, "~" * 78 - print >>errlog, file # page filename - import traceback - traceback.print_exc(None, errlog) - finally: - timestamp = time.strftime("%Y-%m-%d %H:%M") - filepath = os.path.join(outputdir, 'wiki', file) - fileout = codecs.open(filepath, 'w', config.charset) - fileout.write((page_template % { - 'charset': config.charset, - 'pagename': pagename, - 'pagenamewithlinks': pagenamewithlinks, - 'pagehtml': pagehtml, - 'timestamp': timestamp, - 'wikilink': u"http://wiki.crans.org/%s" % quoteWikinameOriUrl(originalpagename).encode("UTF-8"), - 'theme': request.cfg.theme_default, - }).replace("./monobook", "..")) - fileout.close() - - - errlog.close() - if errcnt: - print >>sys.stderr, "*** %d error(s) occurred, see '%s'!" % (errcnt, errfile) - -def run(): - print '''dump-wiki.py est obsolète. Essayez donc: -sudo -u www-data moin \ - --config-dir=/etc/moin --wiki-url=http://wiki.crans.org/ \ - export dump \ - --page "WiFi(/PositionnementDesBornes|/AvoirLeWifi.*)?" \ - --target-dir=/home/myname/outputdir - -Si vous voulez quand même utiliser ce script obsolète, passez-lui --ignore-deprecation-warning en premier argument -''' - if sys.argv[1] == "--ignore-deprecation-warning": - sys.argv = sys.argv[0]+sys.argv[2:] - MoinDump().run() - -def get_attachment(request, pagename, filename, outputdir): - """Traitement des attachements""" - source_dir = AttachFile.getAttachDir(request, pagename) - source_file = os.path.join(source_dir, filename) - if not os.path.isfile(source_file): - print "%s n'existe pas !" % source_file - return - dest_file = os.path.join(outputdir, "attach", - "%s_%s" % (wikiutil.quoteWikinameFS(pagename), filename)) - shutil.copyfile(source_file, dest_file) - return os.path.join("..", "attach", - "%s_%s" % (wikiutil.quoteWikinameFS(pagename), filename)) - -if __name__ == "__main__": - run() diff --git a/wiki/formatter/text_latex.py b/wiki/formatter/text_latex.py deleted file mode 100644 index 2229f09b..00000000 --- a/wiki/formatter/text_latex.py +++ /dev/null @@ -1,340 +0,0 @@ -# -*- coding: utf-8 -*- -""" -MoinMoin - "text/latex" Formatter - -Copyright 2005 Johannes Berg -Copyright (c) 2003 by João Neves -Copyright (c) 2000, 2001, 2002 by Jürgen Hermann - -All rights reserved, see COPYING for details. -""" - -# Imports - -import sys, re, time -from MoinMoin.formatter.base import FormatterBase -from MoinMoin.Page import Page - -############################################################################# -### LaTeX Formatter -############################################################################# - -class Formatter(FormatterBase): - """ - Send text data. - """ - - hardspace = ' ' - - def __init__(self, request, **kw): - apply(FormatterBase.__init__, (self, request), kw) - self.verbatim = False - self.itemized = False - - def text2latex(self, text): - "Escape special characters if not in verbatim mode" - if self.verbatim: return text - text = text.replace('\\', '$\\backslash$ '); - text = text.replace('$', r'\$'); - text = text.replace(r'\$\backslash\$', r'$\backslash$') - text = text.replace('#', '\#'); - text = text.replace('%', '\%'); - text = text.replace('^', '\^{}'); - text = text.replace('&', '\&'); - text = text.replace('_', '\_'); - text = text.replace('{', '\{'); - text = text.replace('}', '\}'); - text = text.replace('~', '\~{}'); - text = text.replace('"', '\"'); - return text - - def write_text(self, text): - if self.item is None: - return text - else: - self.item = (self.item[0], self.item[1]+text) - return '' - - def startDocument(self, pagename): - extra_preamble = '' - preamble_page = self.request.pragma.get('latex_preamble', None) - if preamble_page is not None: - extra_preamble = Page(self.request, preamble_page).get_raw_body() - extra_preamble = re.sub(re.compile('^#'), '%', extra_preamble) - import locale - locale.setlocale(locale.LC_ALL,('fr_FR')) - date = time.strftime("%A %d %B %Y", time.localtime()).capitalize() - return """\\documentclass[a4paper,10pt]{article} - -\\usepackage[english,french]{babel} -\\usepackage[utf8]{inputenc} -\\usepackage{times} -\\usepackage[T1]{fontenc} -\\usepackage{helvet} -\\usepackage{graphicx} -\\usepackage{multicol} -\\usepackage{fullpage} -\\usepackage{fancyhdr} -\\usepackage{hyperref} -\\usepackage{multirow} -\\makeatletter -\\DeclareRobustCommand*\\textsubscript[1]{%% -\\@textsubscript{\\selectfont#1}} -\\def\\@textsubscript#1{%% -{\\m@th\\ensuremath{_{\\mbox{\\fontsize\\sf@size\\z@#1}}}}} -\\makeatother - -%% begin extra preamble inclusion %% -%s - -%% end extra preamble inclusion %% - -\\title{%s} - -\\author{ } - -\\date{%s} - -\\renewcommand{\\theenumi}{\\arabic{enumi}} -\\renewcommand{\\theenumii}{\\arabic{enumi}.\\arabic{enumii}} -\\renewcommand{\\theenumiii}{\\arabic{enumi}.\\arabic{enumii}.\\arabic{enumiii}} -\\renewcommand{\\theenumiv}{\\arabic{enumi}.\\arabic{enumii}.\\arabic{enumiii}.\\arabic{enumiv}} - -\\begin{document} -\\maketitle -\\tableofcontents -\\newpage -""" % (extra_preamble, pagename, date) - - def endDocument(self): - return '\\end{document}\n' - - def sysmsg(self, text, **kw): - return self.write_text('') - - def pagelink(self, on, pagename, text=None, **kw): - return self.write_text('') - - def url(self, on, url=None, css=None, **kw): - if not on: - return self.write_text('}') - url = url.replace('&', '\\&') - return self.write_text('\\href{%s}{' % url) - - def text(self, text): - return self.write_text(self.text2latex(text)) - - def rule(self, size=0): - size = min(size, 10) - ch = "---~=*+#####"[size] - return self.write_text('\\vrule \n') - - def strong(self, on): - return self.write_text(['{\\bf ', '}'][not on]) - - def emphasis(self, on): - return self.write_text(['{\\em ', '}'][not on]) - - def highlight(self, on): - return self.write_text(['{\\tt ', '}'][not on]) - - def number_list(self, on, type=None, start=None): - self.itemized = on - if on: - text = "\\begin{enumerate}" - else: - text = '\\end{enumerate}\n' - return self.write_text(text) - - def bullet_list(self, on): - self.itemized = on - return self.write_text(['\\begin{itemize}\n', '\n\\end{itemize}\n'][not on]) - - def listitem(self, on, **kw): - if not self.itemized: return '' - self._in_li = on != 0 - if on: - return self.write_text('\\item ') - else: - return '' - - def sup(self, on): - return self.write_text(['\\textsuperscript{', '}'][not on]) - - def sub(self, on): - return self.write_text(['\\textsubscript{', '}'][not on]) - - def code(self, on): - return self.write_text(['{\\tt ', '}'][not on]) - - def code_area(self, on, code_id, code_type='code', show=0, start=-1, step=-1): - res = self.preformatted(on) - self.verbatim = False - return self.write_text(res) - - def code_token(self, on, tok_type): - return self.write_text('') - - def code_line(self, on): - return self.write_text('\n') - - def preformatted(self, on): - FormatterBase.preformatted(self, on) - self.verbatim = on - return self.write_text(['\\begin{verbatim}\n', '\\end{verbatim}\n'][not on]) - - def smiley(self, text): - return self.write_text(self.text2latex(text)) - - def paragraph(self, on): - FormatterBase.paragraph(self, on) - return self.write_text(['', '\n\n'][not on]) - - def linebreak(self, preformatted=1): - if preformatted==1: - return self.write_text('\n') - else: - return self.write_text('\\newline') - - def heading(self, on, depth, **kw): - if depth == 1: - rv = (r'\section{','}') - elif depth == 2: - rv = ('\\subsection{','}') - elif depth == 3: - rv = ('\\subsubsection{','}') - else: - rv = (r'\paragraph{','}',) - return self.write_text(rv[not on]) - - rows = [] - row = [] - item = None - - def table(self, on, attrs={}): - def count_cols(row): - cols = 0 - for cell in row: - if cell[0].has_key('colspan'): - cols += int(cell[0]['colspan'][1:-1]) - else: - cols += 1 - return cols - - if on: - self.rows = [] - self.item = None - self.row = [] - return '' - # not on: - if self.rows == []: return '' - cols = count_cols(self.rows[0]) - rows = len(self.rows) - _table = [[0 for i in xrange(0,cols)] for j in xrange(0,rows)] - _rownum = -1 - for _row in self.rows: - _rownum += 1 - _cellnum = -1 - for _cell in _row: - _cellnum += 1 - - while _table[_rownum][_cellnum] is None or type(_table[_rownum][_cellnum]) == type(()): - _cellnum += 1 - - if _cell[0].get('rowspan') == '"1"': - del _cell[0]['rowspan'] - if _cell[0].get('colspan') == '"1"': - del _cell[0]['colspan'] - - _rowspan = int(_cell[0].get('rowspan', '"1"')[1:-1]) - _colspan = int(_cell[0].get('colspan', '"1"')[1:-1]) - - for j in xrange(0,_rowspan): - for i in xrange(0,_colspan): - _table[_rownum+j][_cellnum+i] = None - _table[_rownum+j][_cellnum] = ({'colspan':'"%d"'%_colspan},None) - _table[_rownum][_cellnum] = _cell - - - table = '\\begin{tabular}{|%s}\n' % (cols * 'l|') - for _row in _table: - row = '' - cellnum = 0 - _lines = [] - _do_line = True - for _cell in _row: - cellnum+=1 - if _cell == 0: - return 'INVALID TABLE' - if _cell is None: - if _do_line: - _lines += [cellnum] - continue - _rowspan = int(_cell[0].get('rowspan', '"1"')[1:-1]) - _colspan = int(_cell[0].get('colspan', '"1"')[1:-1]) - format = '%s' - if not (_cell[1] is None): - _do_line = True - _lines += [cellnum] - else: - _do_line = False - _cell = (_cell[0], u'') - if _rowspan > 1: - format = r'\multirow{%d}*{%%s}' % _rowspan - if _colspan > 1: - format = r'\multicolumn{%d}{|l|}{ %s }' % (_colspan, format) - row += (format+' & ') % _cell[1].replace('\n',' ') - for l in _lines: - table += r'\cline{%d-%d}' % (l,l) - table += row[0:-3] + '\\\\ \n' - table += '\\hline\\end{tabular}\n\n' - return table - - - def table_row(self, on, attrs={}): - if not on: - self.rows += [self.row] - self.row = [] - return '' - - def table_cell(self, on, attrs={}): - if not on: - self.row += [self.item] - self.item = None - else: - self.item = (attrs,'') - return '' - - def underline(self, on): - return self.write_text(['\\underline{', '}'][not on]) - - def definition_list(self, on): - return self.write_text(['\\begin{description}\n', '\\end{description}\n'][not on]) - - def definition_term(self, on, compact=0): - return self.write_text(['\\item[', '] '][not on]) - - def definition_desc(self, on): - return self.write_text('') - - def image(self, **kw): - # I am using alt for caption, but how to integrate the image? - text = '' - #if kw.has_key('alt'): - # text += '\\begin{picture}\n' - # text += '\\caption{%s}\n' % kw[alt] - # text += '\\end{picture}\n' - return self.write_text(text) - - def johill_sidecall_emit_latex(self, code): - # nothing else for now - return code - - def open(self, on, **kw): - return "" - def close(self, on, **kw): - return "" - - # suckers who call this. we can't do raw HTML, so we ignore it - def rawHTML(self, markup): - return '' diff --git a/wiki/formatter/text_latex_test.py b/wiki/formatter/text_latex_test.py deleted file mode 100644 index 7afbfc4f..00000000 --- a/wiki/formatter/text_latex_test.py +++ /dev/null @@ -1,348 +0,0 @@ -# -*- coding: utf-8 -*- -""" -MoinMoin - "text/latex" Formatter - -Copyright 2005 Johannes Berg -Copyright (c) 2003 by João Neves -Copyright (c) 2000, 2001, 2002 by Jürgen Hermann - -All rights reserved, see COPYING for details. -""" - -# Imports - -import sys, re, time -from MoinMoin.formatter.base import FormatterBase -from MoinMoin.Page import Page - -############################################################################# -### LaTeX Formatter -############################################################################# - -class Formatter(FormatterBase): - """ - Send text data. - """ - - hardspace = ' ' - - def __init__(self, request, **kw): - apply(FormatterBase.__init__, (self, request), kw) - self.verbatim = False - self.itemized = False - - def text2latex(self, text): - "Escape special characters if not in verbatim mode" - if self.verbatim: return text - text = text.replace('\\', '$\\backslash$ '); - text = text.replace('$', r'\$'); - text = text.replace(r'\$\backslash\$', r'$\backslash$') - text = text.replace('#', '\#'); - text = text.replace('%', '\%'); - text = text.replace('^', '\^{}'); - text = text.replace('&', '\&'); - text = text.replace('_', '\_'); - text = text.replace('{', '\{'); - text = text.replace('}', '\}'); - text = text.replace('~', '\~{}'); - text = text.replace('"', '\"'); - return text - - def write_text(self, text): - if self.item is None: - return text - else: - self.item = (self.item[0], self.item[1]+text) - return '' - - def startDocument(self, pagename): - extra_preamble = '' - preamble_page = self.request.pragma.get('latex_preamble', None) - if preamble_page is not None: - extra_preamble = Page(self.request, preamble_page).get_raw_body() - extra_preamble = re.sub(re.compile('^#'), '%', extra_preamble) - import locale - locale.setlocale(locale.LC_ALL,('fr_FR')) - date = time.strftime("%A %d %B %Y", time.localtime()).capitalize() - return """\\documentclass[a4paper,10pt]{article} - -\\usepackage[english,french]{babel} -\\usepackage[utf8]{inputenc} -\\usepackage{times} -\\usepackage[T1]{fontenc} -\\usepackage{helvet} -\\usepackage{graphicx} -\\usepackage{multicol} -\\usepackage{fullpage} -\\usepackage{fancyhdr} -\\usepackage{hyperref} -\\usepackage{multirow} -\\makeatletter -\\DeclareRobustCommand*\\textsubscript[1]{%% -\\@textsubscript{\\selectfont#1}} -\\def\\@textsubscript#1{%% -{\\m@th\\ensuremath{_{\\mbox{\\fontsize\\sf@size\\z@#1}}}}} -\\makeatother - -%% begin extra preamble inclusion %% -%s - -%% end extra preamble inclusion %% - -\\title{%s} - -\\author{ } - -\\date{%s} - -\\renewcommand{\\theenumi}{\\arabic{enumi}} -\\renewcommand{\\theenumii}{\\arabic{enumi}.\\arabic{enumii}} -\\renewcommand{\\theenumiii}{\\arabic{enumi}.\\arabic{enumii}.\\arabic{enumiii}} -\\renewcommand{\\theenumiv}{\\arabic{enumi}.\\arabic{enumii}.\\arabic{enumiii}.\\arabic{enumiv}} - -\\begin{document} -\\maketitle -\\tableofcontents -\\newpage -""" % (extra_preamble, pagename, date) - - def endDocument(self): - return '\\end{document}\n' - - def sysmsg(self, text, **kw): - return self.write_text('') - - def pagelink(self, on, pagename, page=None, **kw): - if not on: - apply(FormatterBase.pagelink, (self, on, pagename, page), kw) - if page is None: - page = Page(self.request, pagename, formatter=self); - if page.exists(): - return self.write_text('\\footnote{http://crans.org%s}' % self.text2latex(page.url(request=self.request))) - #return self.write_text('toto:%s[%s]' % (self.request.getScriptname(),page.url(request=self.request))) - - return '' - - def url(self, on, url=None, css=None, **kw): - if on: - self.save_url=url.replace('&', '\\&') - return '' - return self.write_text('\\footnote{%s}' % self.save_url) - - def text(self, text): - return self.write_text(self.text2latex(text)) - - def rule(self, size=0): - size = min(size, 10) - ch = "---~=*+#####"[size] - return self.write_text('\\vrule \n') - - def strong(self, on): - return self.write_text(['{\\bf ', '}'][not on]) - - def emphasis(self, on): - return self.write_text(['{\\em ', '}'][not on]) - - def highlight(self, on): - return self.write_text(['{\\tt ', '}'][not on]) - - def number_list(self, on, type=None, start=None): - self.itemized = on - if on: - text = "\\begin{enumerate}" - else: - text = '\\end{enumerate}\n' - return self.write_text(text) - - def bullet_list(self, on): - self.itemized = on - return self.write_text(['\\begin{itemize}\n', '\n\\end{itemize}\n'][not on]) - - def listitem(self, on, **kw): - if not self.itemized: return '' - self._in_li = on != 0 - if on: - return self.write_text('\\item ') - else: - return '' - - def sup(self, on): - return self.write_text(['\\textsuperscript{', '}'][not on]) - - def sub(self, on): - return self.write_text(['\\textsubscript{', '}'][not on]) - - def code(self, on): - return self.write_text(['{\\tt ', '}'][not on]) - - def code_area(self, on, code_id, code_type='code', show=0, start=-1, step=-1): - res = self.preformatted(on) - self.verbatim = False - return self.write_text(res) - - def code_token(self, on, tok_type): - return self.write_text('') - - def code_line(self, on): - return self.write_text('\n') - - def preformatted(self, on): - FormatterBase.preformatted(self, on) - self.verbatim = on - return self.write_text(['\\begin{verbatim}\n', '\\end{verbatim}\n'][not on]) - - def smiley(self, text): - return self.write_text(self.text2latex(text)) - - def paragraph(self, on): - FormatterBase.paragraph(self, on) - return self.write_text(['', '\n\n'][not on]) - - def linebreak(self, preformatted=1): - if preformatted==1: - return self.write_text('\n') - else: - return self.write_text('\\newline') - - def heading(self, on, depth, **kw): - if depth == 1: - rv = (r'\section{','}') - elif depth == 2: - rv = ('\\subsection{','}') - elif depth == 3: - rv = ('\\subsubsection{','}') - else: - rv = (r'\paragraph{','}',) - return self.write_text(rv[not on]) - - rows = [] - row = [] - item = None - - def table(self, on, attrs={}): - def count_cols(row): - cols = 0 - for cell in row: - if cell[0].has_key('colspan'): - cols += int(cell[0]['colspan'][1:-1]) - else: - cols += 1 - return cols - - if on: - self.rows = [] - self.item = None - self.row = [] - return '' - # not on: - if self.rows == []: return '' - cols = count_cols(self.rows[0]) - rows = len(self.rows) - _table = [[0 for i in xrange(0,cols)] for j in xrange(0,rows)] - _rownum = -1 - for _row in self.rows: - _rownum += 1 - _cellnum = -1 - for _cell in _row: - _cellnum += 1 - - while _table[_rownum][_cellnum] is None or type(_table[_rownum][_cellnum]) == type(()): - _cellnum += 1 - - if _cell[0].get('rowspan') == '"1"': - del _cell[0]['rowspan'] - if _cell[0].get('colspan') == '"1"': - del _cell[0]['colspan'] - - _rowspan = int(_cell[0].get('rowspan', '"1"')[1:-1]) - _colspan = int(_cell[0].get('colspan', '"1"')[1:-1]) - - for j in xrange(0,_rowspan): - for i in xrange(0,_colspan): - _table[_rownum+j][_cellnum+i] = None - _table[_rownum+j][_cellnum] = ({'colspan':'"%d"'%_colspan},None) - _table[_rownum][_cellnum] = _cell - - - table = '\\begin{tabular}{|%s}\n' % (cols * 'l|') - for _row in _table: - row = '' - cellnum = 0 - _lines = [] - _do_line = True - for _cell in _row: - cellnum+=1 - if _cell == 0: - return 'INVALID TABLE' - if _cell is None: - if _do_line: - _lines += [cellnum] - continue - _rowspan = int(_cell[0].get('rowspan', '"1"')[1:-1]) - _colspan = int(_cell[0].get('colspan', '"1"')[1:-1]) - format = '%s' - if not (_cell[1] is None): - _do_line = True - _lines += [cellnum] - else: - _do_line = False - _cell = (_cell[0], u'') - if _rowspan > 1: - format = r'\multirow{%d}*{%%s}' % _rowspan - if _colspan > 1: - format = r'\multicolumn{%d}{|l|}{ %s }' % (_colspan, format) - row += (format+' & ') % _cell[1].replace('\n',' ') - for l in _lines: - table += r'\cline{%d-%d}' % (l,l) - table += row[0:-3] + '\\\\ \n' - table += '\\hline\\end{tabular}\n\n' - return table - - - def table_row(self, on, attrs={}): - if not on: - self.rows += [self.row] - self.row = [] - return '' - - def table_cell(self, on, attrs={}): - if not on: - self.row += [self.item] - self.item = None - else: - self.item = (attrs,'') - return '' - - def underline(self, on): - return self.write_text(['\\underline{', '}'][not on]) - - def definition_list(self, on): - return self.write_text(['\\begin{description}\n', '\\end{description}\n'][not on]) - - def definition_term(self, on, compact=0): - return self.write_text(['\\item[', '] '][not on]) - - def definition_desc(self, on): - return self.write_text('') - - def image(self, **kw): - # I am using alt for caption, but how to integrate the image? - text = '' - #if kw.has_key('alt'): - # text += '\\begin{picture}\n' - # text += '\\caption{%s}\n' % kw[alt] - # text += '\\end{picture}\n' - return self.write_text(text) - - def johill_sidecall_emit_latex(self, code): - # nothing else for now - return code - - def open(self, on, **kw): - return "" - def close(self, on, **kw): - return "" - - # suckers who call this. we can't do raw HTML, so we ignore it - def rawHTML(self, markup): - return '' diff --git a/wiki/formatter/text_plain.py b/wiki/formatter/text_plain.py deleted file mode 100644 index 15553d03..00000000 --- a/wiki/formatter/text_plain.py +++ /dev/null @@ -1,254 +0,0 @@ -# -*- coding: iso-8859-1 -*- -""" - MoinMoin - "text/plain" Formatter - - @copyright: 2000, 2001, 2002 by Jürgen Hermann - @copyright: 2006 by Stéphane Glondu - @license: GNU GPL, see COPYING for details. -""" - -from MoinMoin.formatter.base import FormatterBase - -class Formatter(FormatterBase): - """ - Send plain text data. - """ - - hardspace = u' ' - - def __init__(self, request, **kw): - apply(FormatterBase.__init__, (self, request), kw) - self._in_code_area = 0 - self._in_code_line = 0 - self._code_area_state = [0, -1, -1, 0] - self._nested_lists = [] - self._did_para = False - self._url = None - self._text = None # XXX does not work with links in headings!!!!! - - def startDocument(self, pagename): - line = u"*" * (len(pagename)+2) + u'\n' - self._did_para = True - return u"%s %s \n%s\n" % (line, pagename, line) - - def endDocument(self): - return u'\n' - - def sysmsg(self, on, **kw): - return (u'\n\n*** ', u' ***\n\n')[not on] - - def pagelink(self, on, pagename='', page=None, **kw): - apply(FormatterBase.pagelink, (self, on, pagename, page), kw) - return (u">>", u"<<") [not on] - - def interwikilink(self, on, interwiki='', pagename='', **kw): - if on: - self._url = u"%s:%s" % (interwiki, pagename) - self._text = [] - return u'' - else: - if "".join(self._text) == self._url: - res = u'' - else: - res = u' [lien wiki]' - self._url = None - self._text = None - return res - - def url(self, on, url='', css=None, **kw): - if on: - self._url = url - self._text = [] - return u'' - else: - if "".join(self._text) == self._url: - res = u'' - else: - res = u' [cf wiki]' - self._url = None - self._text = None - return res - - def text(self, text): - self._did_para = False - if self._text is not None: - self._text.append(text) - return text - - def rule(self, size=0): - size = min(size, 10) - ch = u"---~=*+#####"[size] - return (ch * 79) + u'\n' - - def strong(self, on): - return u'*' - - def emphasis(self, on): - return u'/' - - def highlight(self, on): - return u'' - - def _list(self, on, bullet): - if on: - self._nested_lists.append(bullet) - if self._did_para: - self._did_para = False - return u'' - else: - return u'\n' - else: - self._nested_lists.pop() - if self._did_para: - return u'' - else: - self._did_para = True - return u'\n' - - def number_list(self, on, type=None, start=None): - return self._list(on, 1) - - def bullet_list(self, on): - return self._list(on, 0) - - def listitem(self, on, **kw): - if on: - self._did_para = False - if self._nested_lists: - number = self._nested_lists[-1] - if number: - bullet = u'%d. ' % number - self._nested_lists[-1] = number + 1 - else: - bullet = u'-' - return u' %s%s' % (u' ' * (len(self._nested_lists)-1), bullet) - else: - return u' - ' - else: - if self._did_para: - return u'' - else: - self._did_para = True - return u'\n' - - def sup(self, on): - return u'^' - - def sub(self, on): - return u'_' - - def code(self, on): - #return [unichr(0x60), unichr(0xb4)][not on] - return u"'" # avoid high-ascii - - def preformatted(self, on): - FormatterBase.preformatted(self, on) - snip = u'---%<' - snip = snip + (u'-' * (78 - len(snip))) - if on: - return u'\n' + snip + u'\n' - else: - return snip + u'\n' - - def small(self, on): - return u'' - - def big(self, on): - return u'' - - def code_area(self, on, code_id, code_type='code', show=0, start=-1, step=-1): - snip = u'---CodeArea' - snip = snip + (u'-' * (78 - len(snip))) - if on: - self._in_code_area = 1 - self._in_code_line = 0 - self._code_area_state = [show, start, step, start] - return u'\n' + snip + u'\n' - else: - if self._in_code_line: - return self.code_line(0) + snip + u'\n' - return snip + u'\n' - - def code_line(self, on): - res = u'' - if not on or (on and self._in_code_line): - res += u'\n' - if on: - if self._code_area_state[0]>0: - res += u' %4d ' % ( self._code_area_state[3] ) - self._code_area_state[3] += self._code_area_state[2] - self._in_code_line = on != 0 - return res - - def code_token(self, on, tok_type): - return "" - - def paragraph(self, on): - FormatterBase.paragraph(self, on) - if on: - self._did_para = False - return u'' - else: - if self._did_para or self._nested_lists: - self._did_para = True - return u'\n' - else: - self._did_para = True - return u'\n\n' - - def linebreak(self, preformatted=1): - self._did_para = True - return u'\n' - - def smiley(self, text): - return text - - def heading(self, on, depth, **kw): - if on: - self._text = [] - return '\n\n' - else: - result = u'\n%s\n\n' % (u'=' * len("".join(self._text))) - self._text = None - return result - - def table(self, on, attrs={}): - return u'' - - def table_row(self, on, attrs={}): - return u'' - - def table_cell(self, on, attrs={}): - return u'' - - def underline(self, on): - return u'_' - - def definition_list(self, on): - return u'' - - def definition_term(self, on, compact=0): - result = u'' - if not compact: result = result + u'\n' - if not on: result = result + u':\n' - return result - - def definition_desc(self, on): - return [u' ', u'\n'][not on] - - def image(self, **kw): - if kw.has_key(u'alt'): - return kw[u'alt'] - return u'' - - def lang(self, on, lang_name): - return '' - - def langAttr(self, lang=None): - return {} - - def open(self, tag, newline=False, attr=None): - return u'' - - def close(self, tag, newline=False): - return u'' diff --git a/wiki/macro/EtatCommutationSecours.py b/wiki/macro/EtatCommutationSecours.py deleted file mode 100644 index 1e897447..00000000 --- a/wiki/macro/EtatCommutationSecours.py +++ /dev/null @@ -1,26 +0,0 @@ -# -*- coding: iso-8859-1 -*- - -def Cellule(texte, couleur, f) : - """ - Retourne le code HTML d'une cellule formattée aver le formatter f - """ - code = f.table(1) - code += f.table_row(1) - code += f.table_cell(1,{'style':'background-color:%s' % couleur }) - code += f.text(texte) - code += f.table_cell(0) - code += f.table_row(0) - code += f.table(0) - return code - -def execute(macro, text) : - - try : - f = open('/usr/scripts/secours/etat_maitre') - f.readline() - if f.readline().strip() == 'auto' : - return "" #Cellule('La commutation automatique de l\'état est activée.','lime',macro.formatter) - else : - return Cellule('La commutation automatique de l\'état a été désactivée.','red',macro.formatter) - except : - return Cellule('Impossible de déterminer le type de commutation.','yellow',macro.formatter) diff --git a/wiki/macro/EtatSecours.py b/wiki/macro/EtatSecours.py deleted file mode 100644 index 075e8060..00000000 --- a/wiki/macro/EtatSecours.py +++ /dev/null @@ -1,25 +0,0 @@ -# -*- coding: iso-8859-1 -*- - -def Cellule(texte, couleur, f) : - """ - Retourne le code HTML d'une cellule formattée aver le formatter f - """ - code = f.table(1) - code += f.table_row(1) - code += f.table_cell(1,{'style':'background-color:%s' % couleur }) - code += f.text(texte) - code += f.table_cell(0) - code += f.table_row(0) - code += f.table(0) - return code - -def execute(macro, text) : - - try : - f = open('/usr/scripts/secours/etat_maitre') - if f.readline().strip() == 'normal' : - return Cellule('Nous sommes actuellement en connexion normale.','lime',macro.formatter) - else : - return Cellule('Nous sommes actuellement en connexion de secours.','red',macro.formatter) - except : - return Cellule('Impossible de déterminer l\'état de la connexion.','yellow',macro.formatter) diff --git a/wiki/macro/Gallery.py b/wiki/macro/Gallery.py deleted file mode 100644 index a686afec..00000000 --- a/wiki/macro/Gallery.py +++ /dev/null @@ -1,746 +0,0 @@ -# -*- coding: iso-8859-1 -*- -""" - Gallery.py Version 0.87 - This macro creates dynamic tabulated displays based on attachment contents - - @copyright: 2004,2005 by Simon Ryan smartblackbox.com> http://smartblackbox.com/simon - @license: GPL - - Special thanks go to: - My beautiful wife Jenny: For keeping the kids at bay long enough for me to code it :-) - Adam Shand: For his GallerySoftware feature wish list, support, ideas and suggestions. - - Usage: [[Gallery(key1=value1,key2=value2....)]] - - where the following keys are valid: - thumbnailwidth = no of pixels wide to make the thumbnails - webnailwidth = width in pixels of the web sized images - numberofcolumns = no of columns used in the thumbnail table - - Bugs: - - Continued rotation will degrade the tmp images (but they can be forced to regen) - - Features: - - Simple usage, just put [[Gallery]] on any page and upload some pictures as attachments - Rotate buttons - Annotation - Should work with MoinMoin versions 1.2.x and 1.3.x - Support for Python Imaging Library - Works with FastCGI mode - - - Not yet implemented: - Handling of video formats - - Speed up: - # When you get really sick of how slow the moinmoin image system is, - # you can either reconfigure your setup for FastCGI (highly recommended) - # or: set the following variables in your wikiconfig.py - gallerytempdir (the path to a writable directory) - gallerytempurl (the path in your webservers url space where this directory can be read from) - eg: - gallerytempdir='/var/www/html/nails' - gallerytempurl='/nails' - or maybe: - gallerytempurl=url_prefix+'/nails' - # There are other ways of getting speedups for attachments, but these methods are the safest (IMHO) - -""" - -__author__ = "Simon D. Ryan" -__version__ = "0.87" - -from MoinMoin import config, wikiutil -import string, cStringIO, os -import commands, shutil -from random import randint -try: - import Image -except: - pass - -class Globs: - # A quick place to plonk those shared variables - thumbnailwidth='200' - webnailwidth='600' - numberofcolumns=4 - adminmsg='' - debuglevel=0 - originals={} - convertbin='' - annotated={} - attachmentdir='' - gallerytempdirroot='' - gallerytempdir='' - gallerytempurl='' - galleryrotchar='' - pagename='' - admin='' - bcomp='' - baseurl='' - timeout=40 - allowedextensions=['jpg','jpeg','png','bmp','tiff','gif'] - -def message(astring,level=1): - if level<=Globs.debuglevel: - Globs.adminmsg=Globs.adminmsg+'Gallery:  '+astring+'
\n' - -def version(): - return(' version '+Globs.version+' by Simon D. Ryan.'+\ - '
Copyright 2004,2005 Simon D. Ryan
Gallery is a MoinMoin macro and is released under the '+\ - 'GPL\n'+\ - '

Upload some images as attachments to '+Globs.pagename+' and I will generate a gallery for you.') - -# Thanks to dennyece.arizona.edu -# This can be replaced with a static translation table to speed things up (later) -def mktrans(): - # Allow only letters and digits and a few other valid file characters - alphanumeric=string.letters+string.digits+'.,-_\'!"' - source_string="" - destination_string="" - for i in range(256): - source_string=source_string+chr(i) - if chr(i) in alphanumeric: - destination_string=destination_string+chr(i) - else: - destination_string=destination_string+' ' - return string.maketrans(source_string,destination_string) - -def qlink(pagename, querystring, query, description=''): - # Returns a hyperlink constructed as a form query on pagename - if not description: - description=query - return ''+description+'' - -def navibar(target,querystring): - # Returns a navigational bar with PREV,THUMBS,NEXT - positions=Globs.originals.keys() - positions.sort() - # Append the action to the end of the URLS. This allows us to keep modes such as action=print - thumbs='THUMBS' - index=positions.index(target) - back,forward='','' - if not index==0: - # We are not the first so we can provide a back link - back=qlink(Globs.pagename, querystring, positions[index-1], 'PREV') - if not index==len(positions)-1: - # We are not the last so we can provide a forward link - forward=qlink(Globs.pagename, querystring, positions[index+1], 'NEXT') - return '
'+back+''+thumbs+''+forward+'
' - -def toolbar(target,naillevel): - if Globs.admin: - rotateleft='' - rotateright='' - deleteitem='' - htarget='' - compat='' - return '

'+rotateleft+''+rotateright+''+deleteitem+'
\n'+htarget+compat+'
' - else: - return '' - -def buildnails(items): - # For now we use commands.getoutput to do our dirty work - # Later we can build a batch job and fork it off. - - # Make sure our temp directory is writable and generate a message if it isn't - try: - if not os.path.isfile(Globs.gallerytempdir+'/tmp.writetest'): - # There is probably a less ugly was to do this using stat (later) - open(Globs.gallerytempdir+'/tmp.writetest','w').close() - except IOError: - message('I had some trouble writing to the temp directory. Is it owned by me and writable?',0) - - # Don't go further if there is a lock in place - if os.path.isfile(Globs.attachmentdir+'/tmp.lock'): - message("I'm currently busy generating thumbnails and webnails, please try again later.",0) - return '' - - # Find the convert binary in standard locations - if not globals().has_key('Image'): - if not os.path.isfile('/usr/bin/convert'): - if not os.path.isfile('/usr/X11R6/bin/convert'): - message('Please install ImageMagick or PIL so I can build thumbnails and webnails

',0) - return - else: - Globs.convertbin='/usr/X11R6/bin/convert' - else: - Globs.convertbin='/usr/bin/convert' - else: - # Use Python Imaging Library - Globs.convertbin='Image' - - # Create a lock file in the attachments dir so we can always remotely remove it if there is a problem - open(Globs.attachmentdir+'/tmp.lock','w').close() - - import time - tstart=time.time() - pid,pid2='','' - - # For each original file, check for the existance of a nail - for item in items: - basename,prefix,width=item - - # Check to see if we tarry too long on the road - if tstart and (time.time()-tstart) > Globs.timeout: - # This is taking waaay too long let us fork and detach else the browser will time out or worse, the webserver may kill us - pid = os.fork() - if pid != 0: - # We are in the parent so we break out - message('The thumbnail generation process was taking too long so it has been backgrounded. Please try again later to see the full set of thumbnails',0) - break - else: - # Once we are forked we want to ignore the time - tstart='' - # Break away from the controlling terminal, so that the web server cannot kill us by killing our parent - os.setsid() - # Fork again so we can get away without a controlling terminal - pid2 = os.fork() - if (pid2 != 0): - os._exit(0) - else: - # Close all open file descriptors - try: - max_fd = os.sysconf("SC_OPEN_MAX") - except (AttributeError, ValueError): - max_fd = 256 - for fd in range(0, max_fd): - try: - os.close(fd) - except OSError: - pass - # Redirect the standard file descriptors to /dev/null - os.open("/dev/null", os.O_RDONLY) # stdin - os.open("/dev/null", os.O_RDWR) # stdout - os.open("/dev/null", os.O_RDWR) # stderr - - # Now we are finally free to continue the conversions as a daemon - # If you would like to know more about the above, see: - # Advanced Programming in the Unix Environment: W. Richard Stevens - # It is also explained in: - # Unix Network Programming (Volume 1): W. Richard Stevens - - #pathtooriginal='"'+Globs.attachmentdir+'/'+Globs.originals[basename]+'"' - pathtooriginal='"'+os.path.join(Globs.attachmentdir,Globs.originals[basename])+'"' - # Warning: - # Take care if modifying the following line, - # you may inadvertantly overwrite your original images! - if not Globs.convertbin == 'Image': - #print 'building nail for '+pathtooriginal - #convout=commands.getoutput('%s -geometry %s \"%s\" "\"%s/%s.%s.jpg\""' % (Globs.convertbin,width+'x'+width,pathtooriginal,Globs.gallerytempdir,prefix,basename)) - convout=commands.getoutput('%s -geometry %s %s "%s/%s.%s.jpg"' % (Globs.convertbin,width+'x'+width,pathtooriginal,Globs.gallerytempdir,prefix,basename)) - convout='' - convout=string.strip(convout) - if convout: - message(convout) - else: - # Use PIL (strip off the "") - im = Image.open(pathtooriginal[1:-1]) - # Use the integer version for PIL - width=string.atoi(width) - im.thumbnail((width,width), Image.ANTIALIAS) - im.save(os.path.join(Globs.gallerytempdir,prefix)+'.'+basename+'.jpg','JPEG') - - if (not pid) and (not pid2): - # Release the lock file when finished - os.unlink(Globs.attachmentdir+'/tmp.lock') - - # We have built thumbnails so we can deposit an indicator file to prevent rebuilding next time - if not os.path.isfile(Globs.attachmentdir+'/delete.me.to.regenerate.thumbnails.and.webnails'): - open(Globs.attachmentdir+'/delete.me.to.regenerate.thumbnails.and.webnails','w').close() - - -def deletefromdisk(target): - # Rotate the images - # Don't go further if there is a lock in place - if os.path.isfile(Globs.attachmentdir+'/tmp.lock'): - message("I'm currently busy generating thumbnails and webnails. Please try your delete request again later.",0) - return '' - # Ok do the actual delete - if 1: - # Delete first the temp dir webnail and thumbnail - try: - os.unlink(Globs.gallerytempdir+'/tmp.webnail.'+target+'.jpg') - except: - pass - try: - os.unlink(Globs.gallerytempdir+'/tmp.thumbnail.'+target+'.jpg') - except: - pass - try: - os.unlink(Globs.gallerytempdir+'/tmp.rotated.'+target+'.jpg') - except: - pass - - # Now delete the original (except we actually just move it to /tmp) - # TODO: insert a random number in the destination filename to cope with deleting files with same name - origfn=Globs.originals[target] - try: - #shutil.copy(Globs.attachmentdir+'/'+origfn,'/tmp/deleted.'+origfn) - shutil.copy(Globs.attachmentdir+'/'+origfn,'/tmp/'+origfn) - os.unlink(Globs.attachmentdir+'/'+origfn) - except: - pass - try: - #shutil.copy(Globs.attachmentdir+'/tmp.annotation.'+target+'.txt','/tmp/deleted.tmp.annotation.'+target+'.txt') - shutil.copy(Globs.attachmentdir+'/tmp.annotation.'+target+'.txt','/tmp/tmp.annotation.'+target+'.txt') - os.unlink(Globs.attachmentdir+'/tmp.annotation.'+target+'.txt') - except: - pass - -def rotate(target,direction): - # Rotate the images - # Don't go further if there is a lock in place - if os.path.isfile(Globs.attachmentdir+'/tmp.lock'): - message("I'm currently busy generating thumbnails and webnails. Please try your rotate request again later.",0) - return '' - - # Find the correct binary - if not globals().has_key('Image'): - if not os.path.isfile('/usr/bin/mogrify'): - if not os.path.isfile('/usr/X11R6/bin/mogrify'): - message('Please install ImageMagick so I can build thumbnails and webnails

',0) - return - else: - Globs.convertbin='/usr/X11R6/bin/mogrify' - else: - Globs.convertbin='/usr/bin/mogrify' - else: - Globs.convertbin = 'Image' - - # Do the actual rotations - if direction=='rotate right': - degs='90' - else: - degs='270' - if not Globs.convertbin == 'Image': - convout=commands.getoutput(Globs.convertbin+' -rotate '+degs+' "'+Globs.gallerytempdir+'/tmp.webnail.'+target+'.jpg"') - convout=commands.getoutput(Globs.convertbin+' -rotate '+degs+' "'+Globs.gallerytempdir+'/tmp.thumbnail.'+target+'.jpg"') - # Don't bother rotating the original. Since we don't want to reduce its quality incase it is used for printing - #if not os.path.isfile(Globs.gallerytempdir+'/tmp.rotated.'+target+'.jpg'): - # # Generate from original - # pathtooriginal=Globs.attachmentdir+'/'+Globs.originals[target] - # shutil.copy(pathtooriginal,Globs.gallerytempdir+'/tmp.rotated.'+target+'.jpg') - #convout=commands.getoutput(Globs.convertbin+' -rotate '+degs+' "'+Globs.gallerytempdir+'/tmp.rotated.'+target+'.jpg"') - else: - # Use PIL (strip off the "") - if direction=='rotate right': - degs=270.0 - else: - degs=90.0 - im = os.path.join(Globs.gallerytempdir,'tmp.webnail.')+target+'.jpg' - imw = Image.open(im) - imw.rotate(degs).save(im,'JPEG') - im = os.path.join(Globs.gallerytempdir,'tmp.thumbnail.')+target+'.jpg' - imw = Image.open(im) - imw.rotate(degs).save(im,'JPEG') - imo = os.path.join(Globs.gallerytempdir,'tmp.rotated.')+target+'.jpg' - if not os.path.isfile(Globs.gallerytempdir+'/tmp.rotated.'+target+'.jpg'): - # Generate from original - im=Globs.attachmentdir+'/'+Globs.originals[target] - else: - im = imo - imw = Image.open(im) - imw.rotate(degs).save(imo,'JPEG') - -def getannotation(target): - # Annotations are stored as a file for now (later to be stored in images) - atext='' - if Globs.annotated.has_key(target): - try: - atext=open(Globs.attachmentdir+'/tmp.annotation.'+target+'.txt').readline() - except: - atext='' - message('was annotated') - else: - message('was not annotated') - # replace double quotes with the html escape so quoted annotations appear - return string.replace(atext,'"','"') - -def execute(macro, args): - - Globs.version=__version__ - - # Containers - formvals={} - thumbnails={} - webnails={} - rotated={} - try: - import wikiconfig - except: - wikiconfig='' - - # Class variables need to be specifically set - # (except for the case where a value is to be shared with another Gallery macro on the same wiki page) - Globs.originals={} - Globs.annotated={} - Globs.attachmentdir='' - Globs.admin='' - Globs.adminmsg='' - Globs.pagename='' - - # process arguments - if args: - # Arguments are comma delimited key=value pairs - sargs=string.split(args,',') - for item in sargs: - sitem=string.split(item,'=') - if len(sitem)==2: - key,value=sitem[0],sitem[1] - if key=='thumbnailwidth': - Globs.thumbnailwidth=value - elif key=='webnailwidth': - Globs.webnailwidth=value - elif key=='numberofcolumns': - try: - Globs.numberofcolumns=string.atoi(value) - except TypeError: - pass - # Experimental, uncomment at own risk - #elif key=='pagename': - # Globs.pagename=value - - transtable=mktrans() - - # Useful variables - dontregen='' - annotationmessage='' - Globs.baseurl=macro.request.getBaseURL()+'/' - if not Globs.pagename: - #Globs.pagename = string.replace(macro.formatter.page.page_name,'/','_2f') - Globs.pagename = macro.formatter.page.page_name - # This fixes the subpages bug. subname is now used instead of pagename when creating certain urls - Globs.subname = string.split(Globs.pagename,'/')[-1] - # Hmmm. A bug in moinmoin? underscores are getting escaped. These doubly escaped pagenames are even appearing in data/pages - try: - # Try the old MoinMoin-1.2.x way first - textdir=config.text_dir - pagepath = string.replace(wikiutil.getPagePath(Globs.pagename),'_5f','_') - except: - pagepath = macro.formatter.page.getPagePath() - Globs.attachmentdir = pagepath+'/attachments' - Globs.galleryrotchar='?' - if hasattr(macro,'cfg') and hasattr(macro.cfg,'gallerytempdir') and hasattr(macro.cfg,'gallerytempurl'): - Globs.gallerytempdirroot=macro.cfg.gallerytempdir - Globs.gallerytempdir=macro.cfg.gallerytempdir+'/'+Globs.pagename+'/' - Globs.gallerytempurl=macro.cfg.gallerytempurl+'/'+Globs.pagename+'/' - elif hasattr(wikiconfig,'gallerytempdir') and hasattr(wikiconfig,'gallerytempurl'): - message('gallerytempdir and gallerytempurl found') - Globs.gallerytempdirroot=wikiconfig.gallerytempdir - Globs.gallerytempdir=wikiconfig.gallerytempdir+'/'+Globs.pagename+'/' - Globs.gallerytempurl=wikiconfig.gallerytempurl+'/'+Globs.pagename+'/' - elif hasattr(wikiconfig,'attachments'): - Globs.gallerytempdirroot=wikiconfig.attachments['dir'] - Globs.gallerytempdir=wikiconfig.attachments['dir']+'/'+Globs.pagename+'/attachments/' - Globs.gallerytempurl=wikiconfig.attachments['url']+'/'+Globs.pagename+'/attachments/' - Globs.attachmentdir = Globs.gallerytempdir - else: - Globs.gallerytempdir=Globs.attachmentdir - Globs.gallerytempurl=Globs.subname+'?action=AttachFile&do=get&target=' - # MoinMoin no longer allows us to use a ? to trigger a refetch, so we pass it a & - Globs.galleryrotchar='&' - if args: - args=macro.request.getText(args) - - # HTML Constants - tleft='
' - tmidd='
' - trigh='
\n' - - # Process any form items into a dictionary (values become unique) - for item in macro.form.items(): - if not formvals.has_key(item[0]): - # Here is where we clean the untrusted web input - # (sometimes we get foreign keys from moinmoin when the page is edited) - try: - formvals[item[0]]=string.translate(item[1][0],transtable) - except AttributeError: - pass - - # Add this to the end of each URL to keep some versions of moinmoin happy - if formvals.has_key('action'): - if formvals['action']=='content': - # translate content action to print action for now - Globs.bcomp='&action=print' - else: - Globs.bcomp='&action='+formvals['action'] - else: - Globs.bcomp='&action=show' - - # Figure out if we have delete privs - try: - # If a user can delete the page containing the Gallery, then they are considered a Gallery administrator - # This probably should be configurable via a wikiconfig variable eg: galleryadminreq = - if macro.request.user.may.delete(macro.formatter.page.page_name): - Globs.admin='true' - except AttributeError: - pass - - out=cStringIO.StringIO() - - # Grab a list of the files in the attachment directory - if os.path.isdir(Globs.attachmentdir): - if Globs.gallerytempdir==Globs.attachmentdir: - afiles=os.listdir(Globs.attachmentdir) - else: - if not os.path.isdir(Globs.gallerytempdirroot): - message('You need to create the temp dir first:'+Globs.gallerytempdirroot,0) - return macro.formatter.rawHTML( - Globs.adminmsg+'

') - if not os.path.isdir(Globs.gallerytempdir): - # Try to create it if it is absent - spagename=string.split(Globs.pagename,'/') - compbit='' - for component in spagename: - compbit=compbit+'/'+component - try: - # The following line stops an exception being raised when trying - # to create a directory that already exists (thanks Magnus Wahrenberg) - if not os.access(Globs.gallerytempdirroot+compbit, os.F_OK): - os.mkdir(Globs.gallerytempdirroot+compbit) - - except: - message('Please check permissions on temp dir:'+Globs.gallerytempdirroot,0) - return macro.formatter.rawHTML( - Globs.adminmsg+'

') - - if os.path.isdir(Globs.gallerytempdir): - afiles=os.listdir(Globs.attachmentdir)+os.listdir(Globs.gallerytempdir) - else: - message('You need to create the temp dir first:'+Globs.gallerytempdir,0) - return macro.formatter.rawHTML( - Globs.adminmsg+'

') - - # Split out the thumbnails and webnails - for item in afiles: - if item.startswith('tmp.thumbnail.'): - origname=item[14:-4] - thumbnails[origname]='' - elif item.startswith('tmp.webnail.'): - origname=item[12:-4] - webnails[origname]='' - elif item.startswith('tmp.rotated.'): - origname=item[12:-4] - rotated[origname]='' - elif item.startswith('tmp.annotation.'): - origname=item[15:-4] - Globs.annotated[origname]='' - elif item == 'delete.me.to.regenerate.thumbnails.and.webnails': - dontregen='true' - elif item == 'tmp.writetest' or item == 'tmp.lock': - pass - else: - # This must be one of the original images - lastdot=string.rfind(item,'.') - origname=item[:lastdot] - ext = item[lastdot+1:] - if string.lower(ext) not in Globs.allowedextensions: - continue - Globs.originals[origname]=item - else: - message(version(),0) - return macro.formatter.rawHTML( Globs.adminmsg ) - - if not Globs.gallerytempdir==Globs.attachmentdir and os.path.isfile(Globs.attachmentdir+'/tmp.writetest'): - # If we are using the new gallerytempdir and we were using the old system then make sure there are no - # remnant files from the old system in the attachment dir to confuse us - message('You have changed to using a gallerytempdir so I am cleaning old tmp files from your attachment dir.',0) - for item in webnails.keys(): - try: - os.unlink(Globs.attachmentdir+'/tmp.webnail.'+item+'.jpg') - except: - pass - # Try deleting any old thumbnails which may be in the attachment directory - for item in thumbnails.keys(): - try: - os.unlink(Globs.attachmentdir+'/tmp.thumbnail.'+item+'.jpg') - except: - pass - # Try deleting any old rotated originals which may be in the attachment directory - for item in rotated.keys(): - try: - os.unlink(Globs.attachmentdir+'/tmp.rotated.'+item+'.jpg') - except: - pass - os.unlink(Globs.attachmentdir+'/tmp.writetest') - - newnails=[] - # Any thumbnails need to be built? - for key in Globs.originals.keys(): - if (not thumbnails.has_key(key)) or (not dontregen): - # Create a thumbnail for this original - newnails.append((key,'tmp.thumbnail',Globs.thumbnailwidth)) - # Any webnails need to be built? - for key in Globs.originals.keys(): - if (not webnails.has_key(key)) or (not dontregen): - # Create a webnail for this original - newnails.append((key,'tmp.webnail',Globs.webnailwidth)) - # Ok, lets build them all at once - if not len(newnails)==0: - buildnails(newnails) - - # If a regen of thumbnails and webnails has occurred, then we should also delete any tmp.rotated files. - if not dontregen: - for key in rotated.keys(): - # Wrapped in a try except since child processes may try to unlink a second time - try: - os.unlink(Globs.gallerytempdir+'/tmp.rotated.'+key+'.jpg') - except: - pass - - if formvals.has_key('annotate'): - if Globs.admin and formvals.has_key('target'): - target=formvals['target'] - # Write an annotation file - atext=string.replace(formvals['annotate'],'"','"') - ouf=open(Globs.attachmentdir+'/tmp.annotation.'+target+'.txt','w') - ouf.write(atext) - ouf.close() - message('Annotation updated to '+atext+'',0) - # Now update the annotated dictionary - if not Globs.annotated.has_key(target): - Globs.annotated[target]='' - - if formvals.has_key('webnail'): - # Does the webnail exist? - message('webnail requested') - target=formvals['webnail'] - rotend='' - if Globs.originals.has_key(target): - out.write(navibar(target,'webnail')) - out.write(toolbar(target,'webnail')) - if formvals.has_key('rotate'): - direction=formvals['rotate'] - message(direction) - rotate(target,direction) - rotend=Globs.galleryrotchar+'rot='+repr(randint(1,10000)) - if formvals.has_key('delete'): - message('Deleted '+target+'',0) - deletefromdisk(target) - # Put things in a table - out.write(tleft) - # Lets build up an image tag - out.write('\n') - out.write(trigh) - out.write(tleft) - - atext=getannotation(target) - - # Are we an administrator? - if Globs.admin: - # We always provide an annotation text field - out.write('

') - out.write('') - out.write('') - out.write('') - out.write('') - out.write('
') - else: - out.write(atext) - out.write(trigh) - #out.write(toolbar(target,'webnail')) - - else: - message('I do not have file: '+target,0) - elif formvals.has_key('original'): - # Now we just construct a single item rather than a table - # Does the webnail exist? - message('original requested') - target=formvals['original'] - rotend='' - if not Globs.originals.has_key(target): - message('I do not have file: '+target,0) - else: - if formvals.has_key('rotate'): - direction=formvals['rotate'] - message(direction) - rotate(target,direction) - rotend=Globs.galleryrotchar+'rot='+repr(randint(1,10000)) - rotated[target]='' - # Lets build up an image tag - out.write(navibar(target,'original')) - out.write(tleft) - originalfilename=Globs.originals[target] - # If there is a rotated version, show that instead - if rotated.has_key(target): - out.write('\n') - else: - out.write('\n') - out.write(trigh) - out.write(tleft) - - atext=getannotation(target) - - # Are we an administrator? - if Globs.admin: - # We always provide an annotation text field - out.write('
') - out.write('') - out.write('') - out.write('') - out.write('') - out.write('
') - else: - out.write(atext) - out.write(trigh) - out.write(toolbar(target,'original')) - - elif formvals.has_key('rotate'): - # We rotate all sizes of this image to the left or right - message('rotate requested') - target=formvals['target'] - direction=formvals['rotate'] - if not Globs.originals.has_key(target): - message('I do not have file: '+target,0) - else: - # Do the rotation - rotate(target,direction) - # Display the new image in webnail mode - # We may need a way of forcing the browser to reload the newly rotated image here (later) - out.write(tleft) - out.write('\n') - out.write(trigh) - - else: - # Finally lets build a table of thumbnails - thumbs=Globs.originals.keys() - thumbs.sort() - thumbs.reverse() - # If version number is requested (append a ?version=tellme&action=show to the page request) - # or if there are no original images, just give help message and return - if formvals.has_key('version') or len(thumbs)==0: - message(version(),0) - return macro.formatter.rawHTML( Globs.adminmsg ) - out.write('\n') - cease='' - rollover='' - while 1: - out.write('') - for i in range(Globs.numberofcolumns): - try: - item=thumbs.pop() - except IndexError: - cease='true' - break - - # Alt text - atext=getannotation(item) - rollover='alt="'+atext+'" title="'+atext+'"' - - # Table entry for thumbnail image - out.write('') - out.write('\n') - if cease: - out.write('
') - break - - out.seek(0) - # Finally output any administrative messages at the top followed by any generated content - return macro.formatter.rawHTML( - Globs.adminmsg+'

' - +out.read() - ) - diff --git a/wiki/macro/HostStatus.py b/wiki/macro/HostStatus.py deleted file mode 100644 index 6d504228..00000000 --- a/wiki/macro/HostStatus.py +++ /dev/null @@ -1,56 +0,0 @@ -# -*- coding: iso-8859-1 -*- - -import re -from commands import getstatusoutput,getoutput - -def execute(macro, text) : - - lines = open('/usr/scripts/var/local.status').readlines() - - f = macro.formatter - code = f.table(1) - - typlist = ['routes', 'serveurs', 'serveurs de la ferme', 'switches', 'bornes', u'services extérieurs au crans'] - - for typ in typlist: - lines = lines [1:] - trucsdown = '' - - while lines and not re.match('dummy_host_\d+ 0 \n', lines[0]): - if not re.search(' 0 ', lines[0]): - line = lines[0].split(' ') - trucsdown += f.table_row(1) - trucsdown += f.table_cell(1,{'style':'background-color:lightgrey;'}) - trucsdown += unicode(f.text('%s (%s)' % (line [0], getoutput("grep '^%s[^-a-zA-Z.]' /usr/scripts/var/autostatus/hosts | cut -d ' ' -f 5-" % line [0])) ), "iso-8859-15") - trucsdown += f.table_cell(0) - # nombre de non réponse au ping - if int(line[1]) > 2 : - trucsdown += f.table_cell(1,{'style':'background-color:red;'}) - trucsdown += f.text(u'down') - else : - trucsdown += f.table_cell(1,{'style':'background-color:blue;'}) - trucsdown += f.text(u'état incertain') - trucsdown += f.table_cell(0) - trucsdown += f.table_row(0) - lines = lines [1:] - - if trucsdown == '': - code += f.table_row(1) - code += f.table_cell(1,{'style':'background-color:silver;'}) - code += f.text(u'Autostatus des '+typ) - code += f.table_cell(0) - code += f.table_cell(1,{'style':'background-color:lime;'}) - code += f.text(u'OK') - code += f.table_cell(0) - code += f.table_row(0) - else: - code += f.table_row(1) - code += f.table_cell(1,{'style':'background-color:silver', 'colspan':'2'}) - code += f.text(u'Autostatus des '+typ) - code += f.table_cell(0) - code += f.table_row(0) - code += trucsdown - trucsdown = '' - - code += f.table(0) - return code diff --git a/wiki/macro/ImageLink.py b/wiki/macro/ImageLink.py deleted file mode 100644 index e280adfd..00000000 --- a/wiki/macro/ImageLink.py +++ /dev/null @@ -1,173 +0,0 @@ -# -*- coding: iso-8859-1 -*- -""" - MoinMoin - ImageLink Macro - - PURPOSE: - This macro is used to set a link as WikiName for an attached image. Optional the size of the - image could be adjusted. If no WikiName is given the attachment is linked to the image itselfs. - - CALLING SEQUENCE: - [[ImageLink(attachment|URL,[WikiName|URL],[width=width,[height=heigt]])]] - - INPUTS: - attachment:image name of attachment or the URL to an image - - OPTIONAL INPUTS: - WikiName: the page to set the link to or the URL to link to - - - KEYWORD PARAMETERS: - width: width of the embedded image - height: height of the embedded image - - EXAMPLE: - [[ImageLink(plot.png,FrontPage,width=20,height=20)]] - [[ImageLink(plot.png,FrontPage,height=20)]] - [[ImageLink(plot.png,FrontPage)]] - [[ImageLink(plot.png,width=20,height=20)]] - [[ImageLink(plot.png,width=20)]] - [[ImageLink(plot.png)]] - [[ImageLink(http://localhost/wiki/modern/img/to_slide.png,http://localhost/StartSeite,width=50)]] - [[ImageLink(http://localhost/wiki/modern/img/to_slide.png,FrontPage,width=50)]] - [[ImageLink(plot.png,http://localhost/StartSeite,width=50)]] - [[ImageLink(http://localhost/wiki/modern/img/to_slide.png)]] - [[ImageLink(http://localhost/wiki/modern/img/to_slide.png,alt=whateveryouwant)]] - - PROCEDURE: - This routine requires attachment enabled. If the attachment isn't downloaded at all - the attachment line is shown. - If you give only one image size argument e.g. width only the other one is calculated - - It must be in "MoinMoin/macro" - - Please remove the version number from the file name! - - From JeffKunce ImageLink.py I have copied _is_URL to this routine. I have no better idea too. - - HISTORY: - The first published version on MoinMoin I know of ImageLink was written by JeffKunce in 2001. - - MODIFICATION HISTORY: - @copyright: 2004 by Reimar Bauer (R.Bauer@fz-juelich.de) - @license: GNU GPL, see COPYING for details. - - Marcin Zalewski: - Some things that were causing problems on my wiki are changed - (wikiutil.link_tag and macro.formatter.pagelink implemented) - - Marcin Zalewski: - Added title attribute to the created link. One could generalize that to - add arbitrary attributes. - - One could also add class attributes to and/or - elements. I do not see the need for such modifications. If however this is - to be done in the future one would need to add 'html_class' key to the kw dictionary - with a corresponding value to add class to element. To add class to element - one needs to add 'css_class' key with a corresponding value to the dictionary passed to - pagelink call. - Reimar Bauer: - 2004-12-23 Adopted to MoinMoin Version 1.3.1-1 - 2004-12-23 SYNTAX CHANGE Version 1.3.1-2 - width and height and probably other keywords must be called as keywords (e.g. height=20) - 2004-12-31 Version 1.3.1-3 code clean up - 2005-01-16 Bug fixed in the errorhandler found and patch code from Malte Helmert - 2005-03-05 Version 1.3.3-5 Bug fixed found by cypress - ''If I put [[ImageLink(moinmoin.png)]] it bombs'' - 2005-03-28 Version 1.3.3-6 feature request added by CDPark: - ''Can we use an external image? And an external target? '' - 2005-04-16 Version 1.3.3-7 no default alt tag definition requested by CDPark and AlexanderSchremmer - Chong-Dae Park: - 2005-04-17 Version 1.3.3-8 code refactored - IMG with no alt tag is not recommended in the HTML standard. - It keeps user specified alt tag. If it is not, it tries to use WikiName or image name instead. - Reimar Bauer: - 2005-04-21 Version 1.3.3-9 bug fixed - When the image does not exist yet, it gives you a "Upload Image" link, this link does not - work. I suspect that this only is a problem on sub-pages, caused by incorrect escaping of - "/". -- CraigJohnson - - -""" - -from MoinMoin.action import AttachFile -from MoinMoin import wikiutil, config -import os,string - -def _is_URL(aString): - '''answer true if aString is a URL. - The method used here is pretty dumb. Improvements are welcome. - jjk 03/28/01''' - return string.find(aString, '://')>0 - - -def execute(macro, text): - - kw ={} # create a dictionary for the formatter.image call - - if text: - args=text.split(',') - else: - args=[] - - number_args=len(args) - count=0 - for a in args : - if (a.find('=') > -1): - count=count+1 - key=a.split('=') - kw[str(key[0])]=wikiutil.escape(string.join(key[1],''), quote=1) - - number_args=number_args-count - - if (number_args < 1): - msg='Not enough arguments to ImageLink macro! Try [[ImageLink(attachment,[WikiName],[width=width,[height=heigt]])]]' - return macro.formatter.sysmsg(1)+macro.formatter.text(msg)+ macro.formatter.sysmsg(0) - - - attname=wikiutil.taintfilename(macro.formatter.text(args[0])) - if (number_args >= 2) : - wikiname=args[1] - current_pagename=macro.formatter.page.page_name - - - if _is_URL(args[0]): - kw['src']=args[0] - else: - kw['src']=AttachFile.getAttachUrl(current_pagename,attname,macro.request) - attachment_path = os.path.join(AttachFile.getAttachDir(macro.request,current_pagename), attname) - - if not os.path.exists(attachment_path): - - import urllib - linktext = macro.request.getText('Upload new attachment "%(filename)s"'%{ - "filename":attname}) - - return wikiutil.link_tag(macro.request, - "%(pagename)s?action=AttachFile&rename=%(newname)s" % { - "pagename":current_pagename, - "newname": attname},linktext) - - - - if not kw.has_key('alt'): - if (number_args == 1) or _is_URL(args[1]): - if _is_URL(args[0]): - # Get image name http://here.com/dir/image.gif -> image.gif - kw['alt'] = wikiutil.taintfilename(macro.formatter.text(args[0].split('/')[-1])) - kw['alt'] = args[0].split('/')[-1] - else: - kw['alt'] = attname - else: - kw['alt'] = wikiname - - if (number_args == 1): - image_link=macro.formatter.image(**kw) - return macro.formatter.url(1,kw['src'] )+image_link +macro.formatter.url(0) - - if (number_args == 2 ): - image_link=macro.formatter.image(**kw) - if _is_URL(args[1]): - return macro.formatter.url(1,args[1] )+image_link+macro.formatter.url(0) - else: - return macro.formatter.pagelink(1,wikiname)+image_link+macro.formatter.url(0) - diff --git a/wiki/macro/InfosBornes.py b/wiki/macro/InfosBornes.py deleted file mode 100755 index e52d0b0c..00000000 --- a/wiki/macro/InfosBornes.py +++ /dev/null @@ -1,89 +0,0 @@ -#! /usr/bin/env python -# -*- encoding: iso-8859-15 -*- - -# Génération d'un fichier XML indiquant le status des bornes - -import sys -import os -import time, urllib2 -import xml.dom.minidom - -def execute(macro, text): - f=macro.formatter - - # ouverture du fichier d'info et parsage - try: - #os.putenv("http_proxy", "http://proxy.crans.org:3128") - status=xml.dom.minidom.parseString(urllib2.urlopen("https://wifi.crans.org/status.xml").read()) - except: - return f.text(u"Impossible d'accéder aux informations des bornes") - - # On récupère l'ensemble des bornes - bornes = status.childNodes[0] - code = f.text(u"Mise à jour le "+bornes.getAttribute("date")) - code += f.linebreak(0) - - code += f.table(True, {'tablealign': 'center'}) - - code += f.table_row(True, {'rowbgcolor': '#FFFFA0'}) - for nom_col in (u"Nom", u"Hotspot", u"État", u"Localisation", u"Clients", - u"MAC", u"Canal", u"Uptime", u"°E", u"°N"): - code += f.table_cell(True) - code += f.strong(True) - code += f.text(nom_col) - code += f.strong(False) - code += f.table_cell(False) - code += f.table_row(False) - - - bornes.childNodes.sort(lambda x, y: cmp(x.getAttribute(u"nom"), - y.getAttribute(u"nom"))) - - dico = {u"hotspot": {u"1": f.smiley('(./)'), u"0": f.text(u"")}, - u"up": {u"1": f.smiley(u"(!)"), u"0": f.smiley(u"{X}")}} - - for b in bornes.childNodes: - code += f.table_row(1) - - code += f.table_cell(1) - code += f.text(b.getAttribute(u"nom")) - code += f.table_cell(0) - - - for nom_attribut in (u"hotspot", u"up"): - code += f.table_cell(1) - code += dico[nom_attribut][b.getAttribute(nom_attribut)] - code += f.table_cell(0) - - for tag in [u'description', u"clients",u"mac",u"canal"]: - code += f.table_cell(1) - if (b.getElementsByTagName(tag)!=[]): - code += f.text(b.getElementsByTagName(tag)[0].firstChild.data) - else: - code += f.text(u"") - code += f.table_cell(0) - - code += f.table_cell(1) - if (b.getElementsByTagName(u"uptime")!=[]): - code += f.text("%.2f" % float(b.getElementsByTagName(u"uptime")[0].firstChild.data)+" j") - else: - code += f.text(u"") - code += f.table_cell(0) - - if (b.getElementsByTagName(u"position")!=[]): - for nom_attribut in [u'x',u'y']: - code += f.table_cell(1) - code += f.text(b.getElementsByTagName(u"position")[0].getAttribute(nom_attribut)) - code += f.table_cell(0) - else: - code += f.table_cell(1) - code += f.text(u"") - code += f.table_cell(0) - code += f.table_cell(1) - code += f.text(u"") - code += f.table_cell(0) - - code += f.table_row(0) - - code += f.table(0) - return code diff --git a/wiki/macro/MonitStatus.py b/wiki/macro/MonitStatus.py deleted file mode 100644 index 965cc61f..00000000 --- a/wiki/macro/MonitStatus.py +++ /dev/null @@ -1,275 +0,0 @@ -# -*- coding: iso-8859-1 -*- - -import os, sys, sre, commands, time - -""" -Permet d'intégrer au wiki les résultats de Monit. - -La macro wiki est : - [[MonitStatus(hotes=host,categories=[All|Process|File],services=[All|Off|On])]] - -Exemple : - [[MonitStatus(All|Off|service@host) -""" - -statusfolder = '/usr/scripts/monit/status' - -def NotRunningHosts() : - """ - Retourne la liste des hotes ou Monit ne tourne pas ou que - le fichier de status est trop vieux - """ - hosts = [] - for host in os.listdir(statusfolder) : - if os.path.getmtime('/usr/scripts/monit/status/%s' % host) < time.time() - 240 : - hosts.append(host) - return hosts - -def HostStatus (host) : - """ - Retourne un dictionnaire représentation de l'état des services de - la machine. - """ - - status = {} - - f = open('%s/%s' % (statusfolder,host) ) - - # c'est un hote sous Debian - ########################### - - # s est le service qu'on est en trainde parser - s = None - for line in f.readlines()[2:] : - line = line.strip() - if not line : - # ligne vide, on passe au service suivant - s = None - elif not s : - # création d'un nouveau service - s = line.split(' ')[1][1:-1] - t = line.split(' ')[0] - # ajout du type s'il n'est pas dedans - if not status.has_key(t) : - status[t] = {} - status[t][s] = {} - else : - # on ajoute les données - status[t][s][line[:34].strip()] = line[34:].strip() - - # on supprime les données system - try : - status.pop('System') - except : - pass - - return status - -def AllStatus () : - """ - Retourne la configuration de toutes les machines - """ - status = {} - for host in os.listdir(statusfolder) : - status[host] = HostStatus(host) - return status - -def AllStatusOff () : - """ - Retourne status avec juste les services off - """ - - status = AllStatus() - - for h in status.keys() : - - # si c'est un host qui est down, on le laisse tel quel pour éviter qu'il le supprime - if h in NotRunningHosts() : - continue - - # on supprime les types - for t in status[h].keys() : - - for s in status[h][t].keys() : - - # on supprime un status s'il est Up - if status[h][t][s]['status'] in ['running','accessible'] : - status[h][t].pop(s) - - # reste-t-il des services dans le groupe - if not status[h][t] : - status[h].pop(t) - - # reste-t-il des groupes dans l'hote - if not status[h] : - status.pop(h) - - return status - -def FormatService(Type, Service, Data, f) : - """ - Retourne le code HTML d'un sercice - Type : type de service - Service : Nom du service - Data : dictionnaire contenant toutes les données Data[info] - f : formatter - """ - - result = '' - result += f.table_row(1) - result += f.table_cell(1,{'style':'background-color:silver'}) - if Type == 'Device' : - Service = Service[2:] - elif Type == 'File' : - Service = Service[4:] - result += f.strong(1) - result += f.text(Service) - result += f.strong(0) - result += f.table_cell(0) - if Data['status'] in ['running','accessible'] : - result += f.table_cell(1,{'style':'background-color:lime'}) - else : - result += f.table_cell(1,{'style':'background-color:red'}) - result += f.text(Data['status']) - result += f.table_cell(0) - result += f.table_row(0) - return result - -def FormatType(Type, Data, f) : - """ - Retourne le code HTML d'une liste de services - Host : nom de l'hote - Data : dictionnaire contenant toutes les données Data[service][info] - f : formatter - """ - - result = '' - - # titre - result += f.heading(1,3) - result += f.text(Type) - result += f.heading(0,3) - - # les services - result += f.table(1) - for s in Data.keys() : - result += FormatService(Type,s,Data[s],f) - result += f.table(0) - - return result - -def FormatHost (Host, Data, f) : - """ - Retourne le code HTML d'un hôte - Host : nom de l'hote - Data : dictionnaire contenant toutes les données Data[type][service][info] - f : formatter - """ - - result = '' - - # titre - result += f.heading(1,2) - result += f.text(Host)[0].upper() + f.text(Host)[1:] - result += f.heading(0,2) - - # si monit ne tourne pas - if Host in NotRunningHosts() : - return result + Cellule('Monit ne semble pas tourner sur %s' % Host,'yellow',f) - - result += f.table(1) - result += f.table_row(1) - for t in Data.keys() : - result += f.table_cell(1,{'valign':'top'}) - result += FormatType(t,Data[t],f) - result += f.table_cell(0) - - result += f.table_row(0) - result += f.table(0) - - return result - -def FormatHosts(Data, f) : - """ - Retourne le code HTML de tous les hotes fournis - Data : dictionnaire contenant toutes les données Data[hote][type][service][info] - f : formatter - """ - - result = '' - - for h in Data.keys() : - result += FormatHost(h,Data[h],f) - - return result - -def Cellule(texte, couleur, f) : - """ - Retourne le code HTML d'une cellule formattée aver le formatter f - """ - code = f.table(1) - code += f.table_row(1) - code += f.table_cell(1,{'style':'background-color:%s' % couleur }) - code += f.text(texte) - code += f.table_cell(0) - code += f.table_row(0) - code += f.table(0) - return code - -def execute(macro, filtre) : - """ - Corps principal de la macro - """ - f = macro.formatter - - # on met en forme le filtre - if not filtre : - filtre = 'all' - else : - filtre = filtre.lower() - - if filtre == 'off' : - # tous les services off - status = AllStatusOff() - if status : - return FormatHosts(status, f) - else : - # aucun service off, on affiche OK - return Cellule(u'Tous les services semblent opérationnels.','lime',f) - - elif filtre == 'all' : - # tous les services - status = AllStatus() - return FormatHosts(status, f) - - elif '@' in filtre : - # affichage d'un service simple - - host = filtre.split('@')[1] - service = filtre.split('@')[0] - status = HostStatus(host) - - # recherche du service dans la config - s = {} - for t in status.keys() : - if service in status[t].keys() : - s = status[t][service] - - if not s : - # service non trouvé - code = f.table_cell(0) - code += f.table_cell(1,{'style':'background-color:yellow'}) - code += f.text(u'Service introuvable') - return code - - # création de la chaine de retour - code = f.table_cell(0) - if s['status'] in ['running','accessible'] : - code += f.table_cell(1,{'style':'background-color:lime'}) - else : - code += f.table_cell(1,{'style':'background-color:red'}) - code += f.text(s['status']) - return code - - else : - return Cellule('Erreur de filtre','yellow',f) diff --git a/wiki/macro/PagesClubs.py b/wiki/macro/PagesClubs.py deleted file mode 100644 index 93a230e0..00000000 --- a/wiki/macro/PagesClubs.py +++ /dev/null @@ -1,19 +0,0 @@ -# -*- encoding: iso-8859-15 -*- - -import os -import PagesPerso - -def comptes(): - """Retourne la liste des comptes""" - return filter(lambda x: os.path.isdir(u"/home/club/%s" % x) and not os.path.islink(u"/home/club/%s" % x), - os.listdir(u"/home/club")) - -def url(self): - """URL vers la page perso""" - return u"http://clubs.ens-cachan.fr/%s/" % self.login - -PagesPerso.comptes = comptes -PagesPerso.account.home = "/home/club" -PagesPerso.account.www = "" -PagesPerso.account.url = url -execute = PagesPerso.execute diff --git a/wiki/macro/PagesPerso.py b/wiki/macro/PagesPerso.py deleted file mode 100644 index a4708a6d..00000000 --- a/wiki/macro/PagesPerso.py +++ /dev/null @@ -1,104 +0,0 @@ -# -*- encoding: iso-8859-15 -*- - -import os - -class account: - """Classe représentant la page perso d'une personne""" - - home = "/home" - www = "/www" - - def __init__(self, login): - """Instanciation avec le `login' de la personne""" - self.login = login - self.home = "%s/%s" % (self.home, login) - - _info = None - def info(self, champ): - """Retourne le contenu du champ `champ' dans le fichier info""" - if self._info == None: - try: - lignes = file("%s/.info" % self.home) - except IOError: - lignes = [] - - # self._info est un dictionnaire qui reprend le contenu du .info - self._info = dict(map(lambda z: (unicode(z[0].lower(),"iso-8859-15"), - unicode(z[1],"iso-8859-15")), - filter(lambda w: len(w) == 2 and len(w[1]), - map(lambda x: map(lambda y: y.strip(), - x.split(":")), - lignes)))) - print self._info - - if self._info.has_key(champ.lower()): - return self._info[champ.lower()] - else: - return u"" - - def chemin(self): - """Chemin vers le www""" - return u"%s%s" % (self.home, self.www) - - def url(self): - """URL vers la page perso""" - return u"http://perso.crans.org/%s/" % self.login - - def logo(self): - """URL du logo s'il y en a un""" - if self.info("logo"): - # Le logo peut être en absolu ou en relatif - if self.info("logo").startswith(self.chemin()): - logo = self.info("logo").replace("%s/" % self.chemin(), "") - else: - logo = self.info("logo") - if os.path.isfile("%s/%s" % (self.chemin(), logo)): - return u"%s%s" % (self.url(), logo) - return u"http://perso.crans.org/pageperso.png" - - def __str__(self): - """Renvoie le code HTML correspondant au fichier .info""" - html = [ u'

', - u'' % self.url(), - u'%s' % (self.logo(), self.login), - u'
', - self.info("nom") and u'%s
' % self.info("nom") or u'%s
' % self.login, - self.info("devise") and u'%s' % self.info("devise") or u'', - u'
' ] - return u'\n'.join(html) - -def comptes(): - """Retourne la liste des comptes""" - return filter(lambda x: os.path.isdir(u"/home/%s/www" % x) and not os.path.islink(u"/home/%s/www" % x), - os.listdir(u"/home")) - - -def makeAnchor(letter): - return u"" % ( letter, letter ) - -def makeIndex(letter_list): - index = u'' - for aLetter in letter_list: - index = u"%s%s" % ( index, aLetter, aLetter) - return u"
%s
" % index - -def execute(macro, args): - dirs = comptes() - dirs.sort() - - html = u"" - - premiere_lettre = '' - letter_list = [] - for d in dirs: - if premiere_lettre != d[0]: - premiere_lettre = d[0] - letter_list.append(premiere_lettre) - html = u"%s\n%s" % ( html, makeAnchor(premiere_lettre) ) - html = u"%s\n%s" % (html, account(d).__str__()) - - - index = makeIndex(letter_list) - html = index + html - html += u'
' - return html diff --git a/wiki/macro/ProgressBar.py b/wiki/macro/ProgressBar.py deleted file mode 100644 index 880698de..00000000 --- a/wiki/macro/ProgressBar.py +++ /dev/null @@ -1,225 +0,0 @@ -""" -MoinMoin - ProgressBar Macro -Generates a progress bar (in the form of a table) - -@copyright: Pascal Bauermeister -@license: GPL - -Updates: - - * [v0.1.1] Sun Dec 18 21:31:17 CET 2005 - Changed table cell percentage markup. - - * [v0.1.0] Fri Dec 16 22:30:10 CET 2005 - Original version - ----- - -The ProgressBar macro generates a table showing a progress indicator. - -Usage: - [[ ProgressBar ]] - [[ ProgressBar (TABLEWIDTH TABLEFORMAT PROGRESS%) ]] - [[ ProgressBar (TABLEWIDTH TABLEFORMAT CURRENT/STEPS) ]] - [[ ProgressBar (TABLEWIDTH TABLEFORMAT STARTDATE,ENDDATE) ]] - -If no arguments are given, the usage is inserted in the HTML result. - -Options: - - TABLEWIDTH (optional prefix) - A wiki tablewidth attribute value between []'s - Examples: - [100%] - [80px] - - TABLEFORMAT (optional prefix) - A pair of wiki table attribute, to format the inactive and active cells. - Examples: - # black on white bar - # same, 90% table - - A third format may be given for STARTDATE,ENDDATE usage - - By default: <><#8080ff> - - PROGRESS - Will display a table with two cells: - - left: completion, taking PROGRESS % of the table width - - right: remaining - - CURRENT/STEPS - Will display a table with STEPS cells, CURRENT of which are active. - - STARTDATE,ENDDATE - Will display a table with the number of days, with the cell - representing today in active format and background in inactive format. - - If today is before STARTDATE, the left-most cell will be in the - 3rd format. If today is after ENDDATE the rightmost cell will be - in the 3rd format. - - Dates are in this format: YYYY-MM-DD - -Debugging - Please prepend a '?' to the arguments. - -Examples: - [[ProgressBar(60%)]] - [[ProgressBar(6/10)]] - [[ProgressBar(2005-11-01,2006-01-06)]] - - [[ProgressBar([50%] 60%)]] - [[ProgressBar([50px] 60%)]] - [[ProgressBar([90%]<#8080ff><#808080> 6/10)]] ----- -""" - - -# Imports -import time, re, StringIO -from MoinMoin import version -from MoinMoin.parser import wiki - -Dependencies = ["time"] # macro cannot be cached - - -class _Error (Exception): - pass - - -def escape (str): - return str.replace ('&','&').replace ('<', '<').replace ('>', '>') - -def usage (full = False): - - """Returns the interesting part of the module's doc""" - - if full: - return __doc__ - else: - rx = re.compile ("--$(.*)^--", re.DOTALL + re.MULTILINE) - return rx.findall (__doc__) [0].strip () - - -def s2t (s): - return time.mktime (time.strptime (s, "%Y-%m-%d")) - - -def execute (macro, text, args_re=None): - - try: res = _execute (macro, text) - except Exception, msg: - return """ -

- Error: macro ProgressBar: %s

- """ % escape ("%s" % msg) - return res - - -def _execute (macro, text): - - fmt = ['#808080','','#8080ff'] - width ="100px" - res = "" - text = text.strip () - - # help if empty text - help = len (text) == 0 - - # debug if starts with '?' - if text.startswith ('?'): - debug = True - text = text [1:] - else: - debug = False - orig_text = text - - # Formats - try: - # Table width - if text.startswith ('['): - pos = text.rfind (']') - width = text [1:pos] - text = text [pos+1:].strip () - - # Cells format - if text.startswith ('<'): - pos = text.rfind ('>') - f = text [1:pos].split ('><') - text = text [pos+1:].strip () - fmt [:len (f)] = f - except: - help = True - - # Show help - if help: - return """ -

-

%s

- """ % escape (usage (0)) - - # Cell formatting utility - def cell (txt, fmt): - if len (txt) == 0: - fmt = 'tablewidth="%s" ' % width + fmt - txt = "||" - if len (fmt): t = "<%s> ||" % fmt - else: t = " ||" - return txt + t - - # Progress - if text.endswith ('%'): - # correction du bug des 0% - if text == "0%": - for f in [fmt [1]] : - res = cell (res, f) - else: - for f in fmt [0] + ' %s' % text, fmt [1] : - res = cell (res, f) - - # Current/Steps - elif text.find ('/') > 0: - cur, steps = map (int, text.split ('/')) - for i in range (steps): - res = cell (res, fmt [i>=cur]) - - # Start/end date - else: - starts, ends = map (lambda s:s.strip (), text.split (",")) - start, end = s2t (starts), s2t (ends) - now = time.mktime (time.localtime ()) - - duration = int ( (end-start) / 86400) - progress = int ( (now-start) / 86400) -1 - pcent = int (90 / duration) - - for i in range (duration): - if i == 0 and progress < 0: - f = fmt [2] - elif i == progress: - f = fmt [0] - else: - f = fmt [1] - res = cell (res, f) - - if progress >= duration: - res = cell (res, fmt [2]) - else: - res = cell (res, fmt [1]) - - # Output - if debug: - res = "{{{[[ProgressBar(%s)]]\n%s}}}\n%s" % (orig_text, res, res) - return _format (res, macro.request, macro.formatter) - - -def _format (src_text, request, formatter): - # parse the text (in wiki source format) and make HTML, - # after diverting sys.stdout to a string - str_out = StringIO.StringIO () # create str to collect output - request.redirect (str_out) # divert output to that string - # parse this line - wiki.Parser (src_text, request).format (formatter) - request.redirect () # restore output - return str_out.getvalue () # return what was generated diff --git a/wiki/macro/Questionnaire.py b/wiki/macro/Questionnaire.py deleted file mode 100755 index 70e25666..00000000 --- a/wiki/macro/Questionnaire.py +++ /dev/null @@ -1,142 +0,0 @@ -#! /usr/bin/env python -# -*- encoding: iso-8859-15 -*- - -#generation d'une question de questionnaire si il y a des arguments, sinon affiche le résultat - -class questionnaire: - execute = 0 - liste_questions = [] - min_point = 0 - max_point = 0 - fonction_affiche = True - -def int_try(point): - try: - return int(point) - except ValueError : - return 0 - -def parse(text): - ligne = text.split("\\") - question = [] - for l in ligne: - l = l.split(":",1) - if len(l)>=2: - question+=[(l[0],l[1])] - return question - -def question_choix_unique(f,QR,quest): - r="" - id = QR[0][0] - r+=f.rawHTML(""" -

%(id)i : %(Q)s
- """ % { "id" : quest.execute , "Q" : QR[0][1]}) - QR=QR[1:] - max = 0 - min = 0 - for (point,rep) in QR: - point = int_try(point) - if (max < point): - max = point - if (min > point): - min = point - r+=f.rawHTML(""" %(rep)s
\n"""% { "point" : point , "id" : quest.execute, "rep" : rep}) - quest.max_point += max - quest.min_point += min - r += f.rawHTML("\n

\n") - return r - - -def question_choix_multiple(f,QR,quest): - r = "" - r +=f.rawHTML("

%(id)i : %(Q)s
\n" % { "id" : quest.execute , "Q" : QR[0][1]}) - QR=QR[1:] - for (point,rep) in QR: - point = int_try(point) - if point > 0: - quest.max_point += point - else: - quest.min_point += point - r+=f.rawHTML(""" %(rep)s
\n"""% { "point" : point , "id" : quest.execute, "rep" : rep}) - r +=f.rawHTML("\n

\n") - return r - -def fonction_javascript(f,quest): - if (quest.fonction_affiche==True): - quest.fonction_affiche = False - return f.rawHTML(""" - -""" % {"min_point": quest.min_point, - "intervalle": quest.max_point-quest.min_point, - "nb_quest": quest.execute}) - else: - return "" - -def result(f,quest): - return f.rawHTML(""" 0 """) - -def result_pourcent(f,quest): - return f.rawHTML(' 0 ') - -def result_max(f,quest): - return f.text("%i" % quest.max_point) - -def result_min(f,quest): - return f.text("%i" % quest.min_point) - -def execute(macro,text): - try: - macro._macro_questionnaire.execute +=1 - except : - macro._macro_questionnaire = questionnaire() - - f = macro.formatter - quest = macro._macro_questionnaire - - if text == "": - return fonction_javascript(f,quest) + result(f,quest) - elif text == "%": - return fonction_javascript(f,quest) + result_pourcent(f,quest) - elif text == "M": - return fonction_javascript(f,quest) + result_max(f,quest) - elif text == "m": - return fonction_javascript(f,quest) + result_min(f,quest) - else: - QR = parse(text) - if QR[0][0][0]=='*': - return question_choix_multiple(f,QR,quest) - else: - return question_choix_unique(f,QR,quest) diff --git a/wiki/macro/RandomIncludeQuote.py b/wiki/macro/RandomIncludeQuote.py deleted file mode 100644 index 78efccb2..00000000 --- a/wiki/macro/RandomIncludeQuote.py +++ /dev/null @@ -1,244 +0,0 @@ -# -*- coding: iso-8859-1 -*- -""" - MoinMoin - RandomIncludeQuote macro - - This macro includes the formatted content of the given page(s). See - - http://purl.net/wiki/moinmaster/HelpOnMacros/Include - - for detailed docs. - - @copyright: 2000-2004 by Jürgen Hermann - @copyright: 2000-2001 by Richard Jones - @license: GNU GPL, see COPYING for details. -""" - -#Dependencies = ["pages"] # included page -Dependencies = ["time"] # works around MoinMoinBugs/TableOfContentsLacksLinks - -import re, StringIO -from MoinMoin import wikiutil -from MoinMoin.Page import Page -from MoinMoin.util import web - -_sysmsg = '

%s

' - -## keep in sync with TableOfContents macro! -_arg_heading = r'(?P,)\s*(|(?P[\'"])(?P.+?)(?P=hquote))' -_arg_level = r',\s*(?P\d*)' -_arg_from = r'(,\s*from=(?P[\'"])(?P.+?)(?P=fquote))?' -_arg_to = r'(,\s*to=(?P[\'"])(?P.+?)(?P=tquote))?' -_arg_sort = r'(,\s*sort=(?P(ascending|descending)))?' -_arg_items = r'(,\s*items=(?P\d+))?' -_arg_skipitems = r'(,\s*skipitems=(?P\d+))?' -_arg_titlesonly = r'(,\s*(?Ptitlesonly))?' -_arg_editlink = r'(,\s*(?Peditlink))?' -_args_re_pattern = r'^(?P[^,]+)(%s(%s)?%s%s%s%s%s%s%s)?$' % ( - _arg_heading, _arg_level, _arg_from, _arg_to, _arg_sort, _arg_items, - _arg_skipitems, _arg_titlesonly, _arg_editlink) - -_title_re = r"^(?P\s*(?P=+)\s.*\s(?P=hmarker))$" - -def extract_titles(body, title_re): - titles = [] - for title, _ in title_re.findall(body): - h = title.strip() - level = 1 - while h[level:level+1] == '=': level = level+1 - depth = min(5,level) - title_text = h[level:-level].strip() - titles.append((title_text, level)) - return titles - -def execute(macro, text, args_re=re.compile(_args_re_pattern), title_re=re.compile(_title_re, re.M), called_by_toc=0): - request = macro.request - _ = request.getText - - # return immediately if getting links for the current page - if request.mode_getpagelinks: - return '' - - # parse and check arguments - args = args_re.match(text) - if not args: - return (_sysmsg % ('error', _('Invalid include arguments "%s"!')) % (text,)) - - # prepare including page - result = [] - print_mode = macro.form.has_key('action') and macro.form['action'][0] == "print" - this_page = macro.formatter.page - if not hasattr(this_page, '_macroInclude_pagelist'): - this_page._macroInclude_pagelist = {} - - # get list of pages to include - inc_name = wikiutil.AbsPageName(request, this_page.page_name, args.group('name')) - pagelist = [inc_name] - if inc_name.startswith("^"): - try: - inc_match = re.compile(inc_name) - except re.error: - pass # treat as plain page name - else: - # Get user filtered readable page list - pagelist = request.rootpage.getPageList(filter=inc_match.match) - - # sort and limit page list - pagelist.sort() - sort_dir = args.group('sort') - if sort_dir == 'descending': - pagelist.reverse() - max_items = args.group('items') - if max_items: - pagelist = pagelist[:int(max_items)] - - skipitems = 0 - if args.group("skipitems"): - skipitems = int(args.group("skipitems")) - titlesonly = args.group('titlesonly') - editlink = args.group('editlink') - - # iterate over pages - for inc_name in pagelist: - if not request.user.may.read(inc_name): - continue - if this_page._macroInclude_pagelist.has_key(inc_name): - result.append(u'

Recursive include of "%s" forbidden

' % (inc_name,)) - continue - if skipitems: - skipitems -= 1 - continue - fmt = macro.formatter.__class__(request, is_included=True) - fmt._base_depth = macro.formatter._base_depth - inc_page = Page(request, inc_name, formatter=fmt) - inc_page._macroInclude_pagelist = this_page._macroInclude_pagelist - - # check for "from" and "to" arguments (allowing partial includes) - body = inc_page.get_raw_body() + '\n' - from_pos = 0 - to_pos = -1 - from_re = args.group('from') - if from_re: - try: - from_match = re.compile(from_re, re.M).search(body) - except re.error, e: - ##result.append("*** fe=%s ***" % e) - from_match = re.compile(re.escape(from_re), re.M).search(body) - if from_match: - from_pos = from_match.end() - else: - result.append(_sysmsg % ('warning', 'Include: ' + _('Nothing found for "%s"!')) % from_re) - to_re = args.group('to') - if to_re: - try: - to_match = re.compile(to_re, re.M).search(body, from_pos) - except re.error: - to_match = re.compile(re.escape(to_re), re.M).search(body, from_pos) - if to_match: - to_pos = to_match.start() - else: - result.append(_sysmsg % ('warning', 'Include: ' + _('Nothing found for "%s"!')) % to_re) - - if titlesonly: - newbody = [] - levelstack = [] - for title, level in extract_titles(body[from_pos:to_pos], title_re): - if levelstack: - if level > levelstack[-1]: - result.append(macro.formatter.bullet_list(1)) - levelstack.append(level) - else: - while levelstack and level < levelstack[-1]: - result.append(macro.formatter.bullet_list(0)) - levelstack.pop() - if not levelstack or level != levelstack[-1]: - result.append(macro.formatter.bullet_list(1)) - levelstack.append(level) - else: - result.append(macro.formatter.bullet_list(1)) - levelstack.append(level) - result.append(macro.formatter.listitem(1)) - result.append(inc_page.link_to(request, title)) - result.append(macro.formatter.listitem(0)) - while levelstack: - result.append(macro.formatter.bullet_list(0)) - levelstack.pop() - continue - - if from_pos or to_pos != -1: - inc_page.set_raw_body(body[from_pos:to_pos], modified=True) - ##result.append("*** f=%s t=%s ***" % (from_re, to_re)) - ##result.append("*** f=%d t=%d ***" % (from_pos, to_pos)) - - if called_by_toc: - result.append(inc_page.get_raw_body()) - continue - - if not hasattr(request, "_Include_backto"): - request._Include_backto = this_page.page_name - - # do headings - level = None - if args.group('heading') and args.group('hquote'): - heading = args.group('htext') or inc_page.split_title(request) - level = 1 - if args.group('level'): - level = int(args.group('level')) - if print_mode: - result.append(macro.formatter.heading(1, level) + - macro.formatter.text(heading) + - macro.formatter.heading(0, level)) - else: - import sha - from MoinMoin import config - # this heading id might produce duplicate ids, - # if the same page is included multiple times - # Encode stuf we feed into sha module. - pntt = (inc_name + heading).encode(config.charset) - hid = "head-" + sha.new(pntt).hexdigest() - request._page_headings.setdefault(pntt, 0) - request._page_headings[pntt] += 1 - if request._page_headings[pntt] > 1: - hid += '-%d'%(request._page_headings[pntt],) - result.append( - #macro.formatter.heading(1, level, hid, - # icons=edit_icon.replace(' 1: - this_page._macroInclude_pagelist[inc_name] = \ - this_page._macroInclude_pagelist[inc_name] - 1 - else: - del this_page._macroInclude_pagelist[inc_name] - - # if no heading and not in print mode, then output a helper link - if editlink and not (level or print_mode): - result.extend([ - '', - ]) - # XXX page.link_to is wrong now, it escapes the edit_icon html as it escapes normal text - - # return include text - return ''.join(result) - -# vim:ts=4:sw=4:et diff --git a/wiki/macro/RandomPageInclude.py b/wiki/macro/RandomPageInclude.py deleted file mode 100644 index dc4844fb..00000000 --- a/wiki/macro/RandomPageInclude.py +++ /dev/null @@ -1,219 +0,0 @@ -# -*- coding: iso-8859-1 -*- -#Dependencies = ["pages"] # included page -Dependencies = ["time"] # works around MoinMoinBugs/TableOfContentsLacksLinks - -import re, StringIO -from MoinMoin import wikiutil, search -from MoinMoin.Page import Page -from MoinMoin.util import web -from random import choice - -_sysmsg = '

%s

' - -## keep in sync with TableOfContents macro! -_arg_heading = r'(?P,)\s*(|(?P[\'"])(?P.+?)(?P=hquote))' -_arg_level = r',\s*(?P\d*)' -_arg_from = r'(,\s*from=(?P[\'"])(?P.+?)(?P=fquote))?' -_arg_to = r'(,\s*to=(?P[\'"])(?P.+?)(?P=tquote))?' -_arg_sort = r'(,\s*sort=(?P(ascending|descending)))?' -_arg_items = r'(,\s*items=(?P\d+))?' -_arg_skipitems = r'(,\s*skipitems=(?P\d+))?' -_arg_titlesonly = r'(,\s*(?Ptitlesonly))?' -_arg_editlink = r'(,\s*(?Peditlink))?' -_args_re_pattern = r'^(?P[^,]+)(%s(%s)?%s%s%s%s%s%s%s)?$' % ( - _arg_heading, _arg_level, _arg_from, _arg_to, _arg_sort, _arg_items, - _arg_skipitems, _arg_titlesonly, _arg_editlink) - -_title_re = r"^(?P\s*(?P=+)\s.*\s(?P=hmarker))$" - -def extract_titles(body, title_re): - titles = [] - for title, _ in title_re.findall(body): - h = title.strip() - level = 1 - while h[level:level+1] == '=': level = level+1 - depth = min(5,level) - title_text = h[level:-level].strip() - titles.append((title_text, level)) - return titles - -def execute(macro, text, args_re=re.compile(_args_re_pattern), title_re=re.compile(_title_re, re.M), called_by_toc=0): - request = macro.request - _ = request.getText - - qnumber = choice(range(1, 10, 1)) - text = u'QuestionnaireCrans/Question\d+[a-z]?$,, from="^= Question =$", to="^----$"' - - # return immediately if getting links for the current page - if request.mode_getpagelinks: - return '' - - # parse and check arguments - args = args_re.match(text) - if not args: - return (_sysmsg % ('error', _('Invalid include arguments "%s"!')) % (text,)) - - # Search the pages and return the results - query = search.QueryParser(regex=1).parse_query(args.group('name')) - results = search.searchPages(request, query) - results.sortByPagename() - pagelist = [results.hits[qnumber].page_name] - - # prepare including page - result = [] - print_mode = macro.form.has_key('action') and macro.form['action'][0] == "print" - this_page = macro.formatter.page - if not hasattr(this_page, '_macroInclude_pagelist'): - this_page._macroInclude_pagelist = {} - - skipitems = 0 - if args.group("skipitems"): - skipitems = int(args.group("skipitems")) - titlesonly = args.group('titlesonly') - editlink = args.group('editlink') - - # iterate over pages - for inc_name in pagelist: - if not request.user.may.read(inc_name): - continue - if this_page._macroInclude_pagelist.has_key(inc_name): - result.append(u'

Recursive include of "%s" forbidden

' % (inc_name,)) - continue - if skipitems: - skipitems -= 1 - continue - fmt = macro.formatter.__class__(request, is_included=True) - fmt._base_depth = macro.formatter._base_depth - inc_page = Page(request, inc_name, formatter=fmt) - inc_page._macroInclude_pagelist = this_page._macroInclude_pagelist - - # check for "from" and "to" arguments (allowing partial includes) - body = inc_page.get_raw_body() + '\n' - from_pos = 0 - to_pos = -1 - from_re = args.group('from') - if from_re: - try: - from_match = re.compile(from_re, re.M).search(body) - except re.error, e: - ##result.append("*** fe=%s ***" % e) - from_match = re.compile(re.escape(from_re), re.M).search(body) - if from_match: - from_pos = from_match.end() - else: - result.append(_sysmsg % ('warning', 'Include: ' + _('Nothing found for "%s"!')) % from_re) - to_re = args.group('to') - if to_re: - try: - to_match = re.compile(to_re, re.M).search(body, from_pos) - except re.error: - to_match = re.compile(re.escape(to_re), re.M).search(body, from_pos) - if to_match: - to_pos = to_match.start() - else: - result.append(_sysmsg % ('warning', 'Include: ' + _('Nothing found for "%s"!')) % to_re) - - if titlesonly: - newbody = [] - levelstack = [] - for title, level in extract_titles(body[from_pos:to_pos], title_re): - if levelstack: - if level > levelstack[-1]: - result.append(macro.formatter.bullet_list(1)) - levelstack.append(level) - else: - while levelstack and level < levelstack[-1]: - result.append(macro.formatter.bullet_list(0)) - levelstack.pop() - if not levelstack or level != levelstack[-1]: - result.append(macro.formatter.bullet_list(1)) - levelstack.append(level) - else: - result.append(macro.formatter.bullet_list(1)) - levelstack.append(level) - result.append(macro.formatter.listitem(1)) - result.append(inc_page.link_to(request, title)) - result.append(macro.formatter.listitem(0)) - while levelstack: - result.append(macro.formatter.bullet_list(0)) - levelstack.pop() - continue - - if from_pos or to_pos != -1: - inc_page.set_raw_body(body[from_pos:to_pos], modified=True) - ##result.append("*** f=%s t=%s ***" % (from_re, to_re)) - ##result.append("*** f=%d t=%d ***" % (from_pos, to_pos)) - - if called_by_toc: - result.append(inc_page.get_raw_body()) - continue - - if not hasattr(request, "_Include_backto"): - request._Include_backto = this_page.page_name - - # do headings - level = None - if args.group('heading') and args.group('hquote'): - heading = args.group('htext') or inc_page.split_title(request) - level = 1 - if args.group('level'): - level = int(args.group('level')) - if print_mode: - result.append(macro.formatter.heading(1, level) + - macro.formatter.text(heading) + - macro.formatter.heading(0, level)) - else: - import sha - from MoinMoin import config - # this heading id might produce duplicate ids, - # if the same page is included multiple times - # Encode stuf we feed into sha module. - pntt = (inc_name + heading).encode(config.charset) - hid = "head-" + sha.new(pntt).hexdigest() - request._page_headings.setdefault(pntt, 0) - request._page_headings[pntt] += 1 - if request._page_headings[pntt] > 1: - hid += '-%d'%(request._page_headings[pntt],) - result.append( - #macro.formatter.heading(1, level, hid, - # icons=edit_icon.replace(' 1: - this_page._macroInclude_pagelist[inc_name] = \ - this_page._macroInclude_pagelist[inc_name] - 1 - else: - del this_page._macroInclude_pagelist[inc_name] - - # if no heading and not in print mode, then output a helper link - if editlink and not (level or print_mode): - result.extend([ - '', - ]) - # XXX page.link_to is wrong now, it escapes the edit_icon html as it escapes normal text - - # return include text - return ''.join(result) - -# vim:ts=4:sw=4:et diff --git a/wiki/macro/RandomQuoteNum.py b/wiki/macro/RandomQuoteNum.py deleted file mode 100644 index 5b237729..00000000 --- a/wiki/macro/RandomQuoteNum.py +++ /dev/null @@ -1,57 +0,0 @@ -# -*- coding: iso-8859-1 -*- -""" - MoinMoin - RandomQuote Macro - - Selects a random quote from FortuneCookies or a given page. - - Usage: - [[RandomQuote()]] - [[RandomQuote(WikiTips)]] - - Comments: - It will look for list delimiters on the page in question. - It will ignore anything that is not in an "*" list. - - @copyright: 2002-2004 by Jürgen Hermann - @license: GNU GPL, see COPYING for details. - - Originally written by Thomas Waldmann. - Gustavo Niemeyer added wiki markup parsing of the quotes. -""" - -import random, StringIO -from MoinMoin.Page import Page, wikiutil - -Dependencies = ["time"] - -def execute(macro, args): - _ = macro.request.getText - - pagename = args or 'FortuneCookies' - if macro.request.user.may.read(pagename): - page = Page(macro.request, pagename) - raw = page.get_raw_body() - else: - raw = "" - - # this selects lines looking like a list item - # !!! TODO: make multi-line quotes possible (optionally split by "----" or something) - quotes = raw.splitlines() - quotes = [quote.strip() for quote in quotes] - quotes = [quote[2:] for quote in quotes if quote.startswith('1. ')] - - if not quotes: - return (macro.formatter.highlight(1) + - _('No quotes on %(pagename)s.') % {'pagename': pagename} + - macro.formatter.highlight(0)) - - quote = random.choice(quotes) - page.set_raw_body(quote, 1) - out = StringIO.StringIO() - macro.request.redirect(out) - page.send_page(macro.request, content_only=1, content_id="RandomQuote_%s" % wikiutil.quoteWikinameFS(page.page_name) ) - quote = out.getvalue() - macro.request.redirect() - - return quote - diff --git a/wiki/macro/TV.py b/wiki/macro/TV.py deleted file mode 100644 index d209885d..00000000 --- a/wiki/macro/TV.py +++ /dev/null @@ -1,93 +0,0 @@ -Dependencies = ["Time"] - - - -SAP_FILE_URL = "http://tv/sap.txt" -BASE_IMAGE_URL = "http://tv/images/" -IMAGE_SUFFIX = ".jpg" -SMALL_IMAGE_SUFFIX = "_petites.jpg" - - -def image_url_for_channel(channel_name, channel_ip, small=0 ): - if small: - return BASE_IMAGE_URL + str(channel_ip) + IMAGE_SUFFIX - else: - return BASE_IMAGE_URL + str(channel_ip) + SMALL_IMAGE_SUFFIX - -def get_channel_list(): - import urllib - # Getsap file from web sever. - f = urllib.urlopen(SAP_FILE_URL) - # Read it. - s = f.read() - f.close() - - s = s.split("\n") - - channel_list = [] - for a_line in s: - try: - ch_name, ch_ip = a_line.split(":") - url = "udp://@%s:1234" % ch_ip - d = { - "name": ch_name, - "url": url, - "image_url": image_url_for_channel( ch_name, ch_ip ), - "small_image_url": image_url_for_channel( ch_name, ch_ip, small=1 ), - } - channel_list.append(d) - except: - pass - return channel_list - - -def execute(macro, args): - opt = {"col":4,"cat":False,"ch":False, "width":"10em"} - # parse args - if args: - try: - for name, value in [(x.split("=")[0].strip(), x.split("=")[1].strip()) for x in args.split(",")]: - opt[name] = value - except: - pass - - IMAGES_PER_LINE = int(opt["col"]) - CATHEGORY = opt["cat"] - CHANNEL = opt["ch"] - IMAGE_WIDTH = opt["width"] - # display all channel - ch_list = get_channel_list() - text = macro.formatter.table(1,{}) - i = 0 - for a_channel in ch_list: - if CATHEGORY: - if not a_channel["name"].startswith(CATHEGORY): - continue - if CHANNEL: - if a_channel["name"].find(CHANNEL)<0: - continue - if i == 0: - text+= macro.formatter.table_row(1) - text+= macro.formatter.table_cell(1, {'style':'text-align:center;'}) - text+= macro.formatter.strong( 1 ) - text+= macro.formatter.text( a_channel["name"] ) - text+= macro.formatter.strong( 0 ) - text+= macro.formatter.linebreak( 0 ) - #text+= macro.formatter.url(1, href=a_channel["url"], style="text-decoration:none;") - text+= macro.formatter.url(1, url=a_channel["url"], style="text-decoration:none;") - text+= macro.formatter.image( src=a_channel["image_url"], alt="No image", style="width:%s;" % IMAGE_WIDTH ) - text+= macro.formatter.linebreak( 0 ) - text+= macro.formatter.text( "Regarder maintenant" ) - text+= macro.formatter.url(0) - text+= macro.formatter.table_cell(0) - if i == IMAGES_PER_LINE - 1: - text+= macro.formatter.table_row(0) - i = (i + 1) % IMAGES_PER_LINE - while i != 0 and i < IMAGES_PER_LINE: - text+= macro.formatter.table_cell(1) - text+= macro.formatter.table_cell(0) - i += 1 - text+= macro.formatter.table(0) - return text - - diff --git a/wiki/macro/TableOfContents.py b/wiki/macro/TableOfContents.py deleted file mode 100644 index 3242c7d4..00000000 --- a/wiki/macro/TableOfContents.py +++ /dev/null @@ -1,186 +0,0 @@ -# -*- coding: iso-8859-1 -*- -""" - MoinMoin - TableOfContents Macro - - Optional integer argument: maximal depth of listing. - - @copyright: 2000, 2001, 2002 by Jürgen Hermann - @copyright: 2006 by Grégoire Détrez - @license: GNU GPL, see COPYING for details. -""" - -import re, sha -from MoinMoin import config, wikiutil - -#Dependencies = ["page"] -Dependencies = ["time"] # works around MoinMoinBugs/TableOfContentsLacksLinks - -# from macro Include (keep in sync!) -_arg_heading = r'(?P,)\s*(|(?P[\'"])(?P.+?)(?P=hquote))' -_arg_level = r',\s*(?P\d*)' -_arg_from = r'(,\s*from=(?P[\'"])(?P.+?)(?P=fquote))?' -_arg_to = r'(,\s*to=(?P[\'"])(?P.+?)(?P=tquote))?' -_arg_sort = r'(,\s*sort=(?P(ascending|descending)))?' -_arg_items = r'(,\s*items=(?P\d+))?' -_arg_skipitems = r'(,\s*skipitems=(?P\d+))?' -_arg_titlesonly = r'(,\s*(?Ptitlesonly))?' -_arg_editlink = r'(,\s*(?Peditlink))?' -_args_re_pattern = r'^(?P[^,]+)(%s(%s)?%s%s%s%s%s%s%s)?$' % ( - _arg_heading, _arg_level, _arg_from, _arg_to, _arg_sort, _arg_items, - _arg_skipitems, _arg_titlesonly, _arg_editlink) - -# from Include, too, but with extra htext group around header text -_title_re = r"^(?P(?P=+)\s(?P.*)\s(?P=hmarker))$" - -class TableOfContents: - """ - TOC Macro wraps all global variables without disturbing threads - """ - - def __init__(self, macro, args): - self.macro = macro - - self.inc_re = re.compile(r"^\[\[Include\((.*)\)\]\]") - self.arg_re = re.compile(_args_re_pattern) - self.head_re = re.compile(_title_re) # single lines only - self.pre_re = re.compile(r'\{\{\{.+?\}\}\}', re.S) - - self.result = [] - self.baseindent = 0 - self.indent = 0 - self.lineno = 0 - self.titles = {} - - self.include_macro = None - - try: - self.mindepth = int(macro.request.getPragma('section-numbers', 1)) - except (ValueError, TypeError): - self.mindepth = 1 - - try: - self.maxdepth = max(int(args), 1) - except (ValueError, TypeError): - self.maxdepth = 99 - - def IncludeMacro(self, *args, **kwargs): - if self.include_macro is None: - self.include_macro = wikiutil.importPlugin(self.macro.request.cfg, - 'macro', "Include") - return self.pre_re.sub('',apply(self.include_macro, args, kwargs)).split('\n') - - def run(self): - f = self.macro.formatter - r = self.result - try: - # Wikipedia-style table of contents - r.append(f.open('div', True, {'id': 'tableOfContents'})) - r.append(f.open('h2', False, {'id': 'toctitle'})) - r.append(f.text(u'Sommaire')) - r.append(f.close('h2', True)) - r.append(f.open('div', True, {'id': 'tableOfContentsList'})) - except: - pass - - self.process_lines(self.pre_re.sub('',self.macro.parser.raw).split('\n'), - self.macro.formatter.page.page_name) - # Close pending lists - for i in range(self.baseindent, self.indent): - self.result.append(self.macro.formatter.listitem(0)) - self.result.append(self.macro.formatter.number_list(0)) - - try: - r.append(f.close('div', True)) - r.append(f.close('div', True)) - r.append(f.open('div', False, {'class': 'visualClear'})) - r.append(f.close('div', True)) - r.append(f.open('script', False, - {'type': 'text/javascript', - 'src': '/wiki/common/toc/toc.js'})) - r.append(f.close('script', True)) - except: - pass - - return u''.join(r) - - def process_lines(self, lines, pagename): - for line in lines: - # Filter out the headings - self.lineno = self.lineno + 1 - match = self.inc_re.match(line) - if match: - # this is an [[Include()]] line. - # now parse the included page and do the work on it. - - ## get heading and level from Include() line. - tmp = self.arg_re.match(match.group(1)) - if tmp and tmp.group("name"): - inc_pagename = tmp.group("name") - else: - # no pagename? ignore it - continue - if tmp.group("heading"): - if tmp.group("htext"): - heading = tmp.group("htext") - else: - heading = inc_pagename - if tmp.group("level"): - level = int(tmp.group("level")) - else: - level = 1 - inc_page_lines = ["%s %s %s" %("=" * level, heading, "=" * level)] - else: - inc_page_lines = [] - - inc_page_lines = inc_page_lines + self.IncludeMacro(self.macro, match.group(1), called_by_toc=1) - - self.process_lines(inc_page_lines, inc_pagename) - else: - self.parse_line(line, pagename) - - def parse_line(self, line, pagename): - # FIXME this also finds "headlines" in {{{ code sections }}}: - match = self.head_re.match(line) - if not match: return - title_text = match.group('htext').strip() - pntt = pagename + title_text - self.titles.setdefault(pntt, 0) - self.titles[pntt] += 1 - - # Get new indent level - newindent = len(match.group('hmarker')) - if newindent > self.maxdepth: return - if newindent < self.mindepth: return - if not self.indent: - self.baseindent = newindent - 1 - self.indent = self.baseindent - - # Close lists - for i in range(0,self.indent-newindent): - self.result.append(self.macro.formatter.listitem(0)) - self.result.append(self.macro.formatter.number_list(0)) - - # Open Lists - for i in range(0,newindent-self.indent): - self.result.append(self.macro.formatter.number_list(1)) - - # Add the heading - unique_id = '' - if self.titles[pntt] > 1: - unique_id = '-%d' % (self.titles[pntt],) - - if self.indent == newindent: - self.result.append(self.macro.formatter.listitem(0)) - - self.result.append(self.macro.formatter.listitem(1)) - self.result.append(self.macro.formatter.anchorlink(1, - "head-" + sha.new(pntt.encode(config.charset)).hexdigest() + unique_id) + - self.macro.formatter.text(title_text) + - self.macro.formatter.anchorlink(0)) - - # Set new indent level - self.indent = newindent - -def execute(macro, args): - toc=TableOfContents(macro,args) - return toc.run() diff --git a/wiki/macro/TerminalSsh.py b/wiki/macro/TerminalSsh.py deleted file mode 100644 index 39234a22..00000000 --- a/wiki/macro/TerminalSsh.py +++ /dev/null @@ -1,53 +0,0 @@ -Dependencies = ["Time"] - -class ssh: - settings = { - 'protocol' : "ssh2", - 'server' : 'ssh.crans.org', - 'port' : '22', - "auth-method" : "keyboard-interactive", - "bg-color" : "black", - "fg-color" : "white", - "cursor-color" : "yellow", - "menus" : "pop3", - "geometry" : "94x32", - "allow-new-server" : "false", - } - - #appletLocation = "/wiki/applets/mindterm.jar" - appletLocation = "https://ssh.crans.org/mindterm.jar" - - def parseArgs(self, args): - argList = args.split(u',') - - for anArg in argList: - try: - key = anArg.split(u'=')[0] - value = anArg.split(u'=')[1] - self.settings[key] = value - except:pass - - def formatParams(self): - html = [] - for key, value in self.settings.items(): - html.append(u'' % (key, value)) - return u'\n'.join(html) - - def __init__(self, args): - self.parseArgs(args) - - def run(self): - html = [ - u'

', - u'' % self.appletLocation, - self.formatParams(), - u'', - u'

', - ] - return u'\n'.join(html) - -def execute(macro, args): -# return macro.formatter.text("I got these args from a macro %s: %s" % -# (str(macro), args)) - o = ssh(args) - return o.run() diff --git a/wiki/macro/YouTube.py b/wiki/macro/YouTube.py deleted file mode 100644 index 2858941e..00000000 --- a/wiki/macro/YouTube.py +++ /dev/null @@ -1,27 +0,0 @@ -# -*- coding: iso-8859-1 -*- -""" - MoinMoin - YouTube Macro - Jesus L. Alvaro 2006 - v 0.0.2 - You can include YouTube videos in the wiki by using this macro: - [[YouTube(V8tSRJ8e3b0)]] or - [[YouTube(http://www.youtube.com/v/V8tSRJ8e3b0)]] - visit "http://www.iesvaldebernardo.es/w/Post/2006-11-30-1447/YouTube_en_la_Wiki." - -""" - -def execute(macro, text): - if text.find('http://')> -1: - try: - text = text.split('v=')[1] - except: - return u"URL non valide..." - url = 'http://www.youtube.com/v/%s' % text - html = u''' - - - - - - ''' % {"youtubelink": url} - return html diff --git a/wiki/macro/latex.py b/wiki/macro/latex.py deleted file mode 100644 index 16b2baa9..00000000 --- a/wiki/macro/latex.py +++ /dev/null @@ -1,44 +0,0 @@ -#FORMAT python -""" -See the latex parser, this is just a thin wrapper around it. -""" -# Imports -from MoinMoin import wikiutil -import re - -Dependencies = [] - -splitre = re.compile(r'([^\\])%') - -class latex: - def __init__(self, macro, args): - self.macro = macro - self.formatter = macro.formatter - self.text = args - - def renderInPage(self): - # return immediately if getting links for the current page - if self.macro.request.mode_getpagelinks: - return '' - - if self.text is None: # macro call without parameters - return '' - - # get an exception? for moin before 1.3.2 use the following line instead: - # L = wikiutil.importPlugin('parser', 'latex', 'Parser', self.macro.cfg.data_dir) - L = wikiutil.importPlugin(self.macro.cfg, 'parser', 'latex', 'Parser') - if L is None: - return self.formatter.text("<>") - l = L('', self.macro.request) - tmp = splitre.split(self.text, 1) - if len(tmp) == 3: - prologue,p2,tex=tmp - prologue += p2 - else: - prologue = '' - tex = tmp[0] - return l.get(self.formatter, tex, prologue) - - -def execute(macro, args): - return latex(macro, args).renderInPage() diff --git a/wiki/mail.py b/wiki/mail.py deleted file mode 100644 index 77489bce..00000000 --- a/wiki/mail.py +++ /dev/null @@ -1,181 +0,0 @@ -# -*- coding: iso-8859-1 -*- -""" - MoinMoin - email helper functions - - @copyright: 2003 by Jürgen Hermann - @license: GNU GPL, see COPYING for details. -""" - -import os, re -from email.Header import Header -from MoinMoin import config - -_transdict = {"AT": "@", "DOT": ".", "DASH": "-"} - - -def encodeAddress(address, charset): - """ Encode email address to enable non ascii names - - e.g. '"Jürgen Hermann" '. According to the RFC, the name - part should be encoded, the address should not. - - @param address: email address, posibly using '"name"
' format - @type address: unicode - @param charset: sepcifying both the charset and the encoding, e.g - quoted printble or base64. - @type charset: email.Charset.Charset instance - @rtype: string - @return: encoded address - """ - composite = re.compile(r'(?P.+)(?P\<.*\>)', - re.UNICODE) - match = composite.match(address) - if match: - phrase = match.group('phrase').encode(config.charset) - phrase = str(Header(phrase, charset)) - angle_addr = match.group('angle_addr').encode(config.charset) - return phrase + angle_addr - else: - return address.encode(config.charset) - - -def sendmail(request, to, subject, text, **kw): - """ Create and send a text/plain message - - Return a tuple of success or error indicator and message. - - @param request: the request object - @param to: recipients (list) - @param subject: subject of email (unicode) - @param text: email body text (unicode) - @keyword mail_from: override default mail_from - @type mail_from: unicode - @rtype: tuple - @return: (is_ok, Description of error or OK message) - """ - import smtplib, socket - from email.Message import Message - from email.Charset import Charset, QP - from email.Utils import formatdate, make_msgid - - _ = request.getText - cfg = request.cfg - mail_from = kw.get('mail_from', '') or cfg.mail_from - subject = subject.encode(config.charset) - - # Create a text/plain body using CRLF (see RFC2822) - text = text.replace(u'\n', u'\r\n') - text = text.encode(config.charset) - - # Create a message using config.charset and quoted printable - # encoding, which should be supported better by mail clients. - # TODO: check if its really works better for major mail clients - msg = Message() - charset = Charset(config.charset) - charset.header_encoding = QP - charset.body_encoding = QP - msg.set_charset(charset) - - #### HACK BACKPORT - # work around a bug in python 2.4.3 and above: - msg.set_payload('=') - if msg.as_string().endswith('='): - text = charset.body_encode(text) - #### FIN DU HACK - - msg.set_payload(text) - - # Create message headers - # Don't expose emails addreses of the other subscribers, instead we - # use the same mail_from, e.g. u"Jürgen Wiki " - address = encodeAddress(mail_from, charset) - msg['From'] = address - msg['To'] = address - msg['Date'] = formatdate() - msg['Message-ID'] = make_msgid() - msg['Subject'] = Header(subject, charset) - - if cfg.mail_sendmail: - # Set the BCC. This will be stripped later by sendmail. - msg['BCC'] = ','.join(to) - # Set Return-Path so that it isn't set (generally incorrectly) for us. - msg['Return-Path'] = address - - # Send the message - if not cfg.mail_sendmail: - try: - host, port = (cfg.mail_smarthost + ':25').split(':')[:2] - server = smtplib.SMTP(host, int(port)) - try: - #server.set_debuglevel(1) - if cfg.mail_login: - user, pwd = cfg.mail_login.split() - try: # try to do tls - server.ehlo() - if server.has_extn('starttls'): - server.starttls() - server.ehlo() - except: - pass - server.login(user, pwd) - server.sendmail(mail_from, to, msg.as_string()) - finally: - try: - server.quit() - except AttributeError: - # in case the connection failed, SMTP has no "sock" attribute - pass - except smtplib.SMTPException, e: - return (0, str(e)) - except (os.error, socket.error), e: - return (0, _("Connection to mailserver '%(server)s' failed: %(reason)s") % { - 'server': cfg.mail_smarthost, - 'reason': str(e) - }) - else: - try: - sendmailp = os.popen(cfg.mail_sendmail, "w") - # msg contains everything we need, so this is a simple write - sendmailp.write(msg.as_string()) - sendmail_status = sendmailp.close() - if sendmail_status: - return (0, str(sendmail_status)) - except: - return (0, _("Mail not sent")) - - return (1, _("Mail sent OK")) - - -def decodeSpamSafeEmail(address): - """ Decode obfuscated email address to standard email address - - Decode a spam-safe email address in `address` by applying the - following rules: - - Known all-uppercase words and their translation: - "DOT" -> "." - "AT" -> "@" - "DASH" -> "-" - - Any unknown all-uppercase words simply get stripped. - Use that to make it even harder for spam bots! - - Blanks (spaces) simply get stripped. - - @param address: obfuscated email address string - @rtype: string - @return: decoded email address - """ - email = [] - - # words are separated by blanks - for word in address.split(): - # is it all-uppercase? - if word.isalpha() and word == word.upper(): - # strip unknown CAPS words - word = _transdict.get(word, '') - email.append(word) - - # return concatenated parts - return ''.join(email) - diff --git a/wiki/parser/Box.py b/wiki/parser/Box.py deleted file mode 100644 index 447d17bc..00000000 --- a/wiki/parser/Box.py +++ /dev/null @@ -1,119 +0,0 @@ -# -*- coding: iso-8859-1 -*- -""" - MoinMoin - Portail parser - - PURPOSE: - une boite jolie - - CALLING SEQUENCE: - {{{ - #!Box titre - blablabla - - tables, images.... - }}} - -""" -from MoinMoin.parser import wiki -import os,string,re,StringIO -from MoinMoin.action import AttachFile - -color_list = ['orange', 'black', 'red', 'green', 'blue', 'gray'] - - -##################################################################### -# Fonctions # -##################################################################### -# to_wikiname : transfome la chaine text avec le parser wiki -# classique et le formateur formatter -# (je sais pas a quoi sert request, mais faut pas -# l'enlever !) -####### - -def to_wikiname(request,formatter,text): - ##taken from MiniPage - out=StringIO.StringIO() - request.redirect(out) - wikiizer = wiki.Parser(text,request) - wikiizer.format(formatter) - result=out.getvalue() - request.redirect() - del out - - return result.strip() - -##################################################################### -# BoxFormatter : creer le code html -####### -class BoxFormatter: - - def __init__(self, request, formatter): - self.formatter = formatter - self.request = request - self.counter = 0 - def make(self, title, body_html, color=None): - if color==None: - css_color_class=u"" - else: - css_color_class = u" %s_box" % color - html = [ - self.formatter.rawHTML(u'
' % css_color_class), - self.formatter.rawHTML(u'
'), - self.formatter.heading(1,3), - title, - self.formatter.heading(0,3), - self.formatter.rawHTML(u'
'), - self.formatter.rawHTML(u'
'), - self.formatter.rawHTML(u'
'), - body_html, - self.formatter.rawHTML(u'
'), - self.formatter.rawHTML(u'
'), - self.formatter.rawHTML(u'
'), - ] - self.request.write(u'\n'.join(html)) - -##################################################################### -# Parser : classe principale, c'est elle qui parse -####### -class Parser: - - def __init__(self, raw, request, **kw): - self.request = request - self.raw = raw - self.settings={'title': u'|'.join([u" ".join(kw.keys()), u" ".join(kw.values())])} - self.settings = self.parseArgs(kw["format_args"]) - - def getRandomColor(self): - nb_of_colors = color_list.__len__() - from random import randint - colorNum = randint(0, nb_of_colors - 1) - return color_list[colorNum] - - def parseArgs(self, argsString): - argList = argsString.split(u',') - settings = {} - for anArg in argList: - anArg = anArg.strip(u' ') - if anArg.find(u'color=')!=-1: - theColor = anArg.split(u'=')[1].lower() - if theColor == 'random': - theColor = self.getRandomColor() - settings['color'] = theColor - else: - settings['title'] = anArg - return settings - - def format(self, formatter): - quotes = self.raw - - # on utilise la classe qui va fabriquer le code html - boite = BoxFormatter(self.request, formatter) - title = self.settings['title'] - content = to_wikiname(self.request, formatter, quotes) - try: - color = self.settings['color'] - except: - color=None - boite.make(title, content, color) - return - diff --git a/wiki/parser/EXIF.py b/wiki/parser/EXIF.py deleted file mode 100644 index 154499f0..00000000 --- a/wiki/parser/EXIF.py +++ /dev/null @@ -1,1197 +0,0 @@ -# Library to extract EXIF information in digital camera image files -# -# To use this library call with: -# f=open(path_name, 'rb') -# tags=EXIF.process_file(f) -# tags will now be a dictionary mapping names of EXIF tags to their -# values in the file named by path_name. You can process the tags -# as you wish. In particular, you can iterate through all the tags with: -# for tag in tags.keys(): -# if tag not in ('JPEGThumbnail', 'TIFFThumbnail', 'Filename', -# 'EXIF MakerNote'): -# print "Key: %s, value %s" % (tag, tags[tag]) -# (This code uses the if statement to avoid printing out a few of the -# tags that tend to be long or boring.) -# -# The tags dictionary will include keys for all of the usual EXIF -# tags, and will also include keys for Makernotes used by some -# cameras, for which we have a good specification. -# -# Contains code from "exifdump.py" originally written by Thierry Bousch -# and released into the public domain. -# -# Updated and turned into general-purpose library by Gene Cash -# -# This copyright license is intended to be similar to the FreeBSD license. -# -# Copyright 2002 Gene Cash All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are -# met: -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in the -# documentation and/or other materials provided with the -# distribution. -# -# THIS SOFTWARE IS PROVIDED BY GENE CASH ``AS IS'' AND ANY EXPRESS OR -# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES -# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -# DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR -# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS -# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, -# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -# -# This means you may do anything you want with this code, except claim you -# wrote it. Also, if it breaks you get to keep both pieces. -# -# Patch Contributors: -# * Simon J. Gerraty -# s2n fix & orientation decode -# * John T. Riedl -# Added support for newer Nikon type 3 Makernote format for D70 and some -# other Nikon cameras. -# * Joerg Schaefer -# Fixed subtle bug when faking an EXIF header, which affected maker notes -# using relative offsets, and a fix for Nikon D100. -# -# 21-AUG-99 TB Last update by Thierry Bousch to his code. -# 17-JAN-02 CEC Discovered code on web. -# Commented everything. -# Made small code improvements. -# Reformatted for readability. -# 19-JAN-02 CEC Added ability to read TIFFs and JFIF-format JPEGs. -# Added ability to extract JPEG formatted thumbnail. -# Added ability to read GPS IFD (not tested). -# Converted IFD data structure to dictionaries indexed by -# tag name. -# Factored into library returning dictionary of IFDs plus -# thumbnail, if any. -# 20-JAN-02 CEC Added MakerNote processing logic. -# Added Olympus MakerNote. -# Converted data structure to single-level dictionary, avoiding -# tag name collisions by prefixing with IFD name. This makes -# it much easier to use. -# 23-JAN-02 CEC Trimmed nulls from end of string values. -# 25-JAN-02 CEC Discovered JPEG thumbnail in Olympus TIFF MakerNote. -# 26-JAN-02 CEC Added ability to extract TIFF thumbnails. -# Added Nikon, Fujifilm, Casio MakerNotes. -# 30-NOV-03 CEC Fixed problem with canon_decode_tag() not creating an -# IFD_Tag() object. -# 15-FEB-04 CEC Finally fixed bit shift warning by converting Y to 0L. -# - -# field type descriptions as (length, abbreviation, full name) tuples -FIELD_TYPES=( - (0, 'X', 'Proprietary'), # no such type - (1, 'B', 'Byte'), - (1, 'A', 'ASCII'), - (2, 'S', 'Short'), - (4, 'L', 'Long'), - (8, 'R', 'Ratio'), - (1, 'SB', 'Signed Byte'), - (1, 'U', 'Undefined'), - (2, 'SS', 'Signed Short'), - (4, 'SL', 'Signed Long'), - (8, 'SR', 'Signed Ratio') - ) - -# dictionary of main EXIF tag names -# first element of tuple is tag name, optional second element is -# another dictionary giving names to values -EXIF_TAGS={ - 0x0100: ('ImageWidth', ), - 0x0101: ('ImageLength', ), - 0x0102: ('BitsPerSample', ), - 0x0103: ('Compression', - {1: 'Uncompressed TIFF', - 6: 'JPEG Compressed'}), - 0x0106: ('PhotometricInterpretation', ), - 0x010A: ('FillOrder', ), - 0x010D: ('DocumentName', ), - 0x010E: ('ImageDescription', ), - 0x010F: ('Make', ), - 0x0110: ('Model', ), - 0x0111: ('StripOffsets', ), - 0x0112: ('Orientation', - {1: 'Horizontal (normal)', - 2: 'Mirrored horizontal', - 3: 'Rotated 180', - 4: 'Mirrored vertical', - 5: 'Mirrored horizontal then rotated 90 CCW', - 6: 'Rotated 90 CW', - 7: 'Mirrored horizontal then rotated 90 CW', - 8: 'Rotated 90 CCW'}), - 0x0115: ('SamplesPerPixel', ), - 0x0116: ('RowsPerStrip', ), - 0x0117: ('StripByteCounts', ), - 0x011A: ('XResolution', ), - 0x011B: ('YResolution', ), - 0x011C: ('PlanarConfiguration', ), - 0x0128: ('ResolutionUnit', - {1: 'Not Absolute', - 2: 'Pixels/Inch', - 3: 'Pixels/Centimeter'}), - 0x012D: ('TransferFunction', ), - 0x0131: ('Software', ), - 0x0132: ('DateTime', ), - 0x013B: ('Artist', ), - 0x013E: ('WhitePoint', ), - 0x013F: ('PrimaryChromaticities', ), - 0x0156: ('TransferRange', ), - 0x0200: ('JPEGProc', ), - 0x0201: ('JPEGInterchangeFormat', ), - 0x0202: ('JPEGInterchangeFormatLength', ), - 0x0211: ('YCbCrCoefficients', ), - 0x0212: ('YCbCrSubSampling', ), - 0x0213: ('YCbCrPositioning', ), - 0x0214: ('ReferenceBlackWhite', ), - 0x828D: ('CFARepeatPatternDim', ), - 0x828E: ('CFAPattern', ), - 0x828F: ('BatteryLevel', ), - 0x8298: ('Copyright', ), - 0x829A: ('ExposureTime', ), - 0x829D: ('FNumber', ), - 0x83BB: ('IPTC/NAA', ), - 0x8769: ('ExifOffset', ), - 0x8773: ('InterColorProfile', ), - 0x8822: ('ExposureProgram', - {0: 'Unidentified', - 1: 'Manual', - 2: 'Program Normal', - 3: 'Aperture Priority', - 4: 'Shutter Priority', - 5: 'Program Creative', - 6: 'Program Action', - 7: 'Portrait Mode', - 8: 'Landscape Mode'}), - 0x8824: ('SpectralSensitivity', ), - 0x8825: ('GPSInfo', ), - 0x8827: ('ISOSpeedRatings', ), - 0x8828: ('OECF', ), - # print as string - #0x9000: ('ExifVersion', lambda x: ''.join(map(chr, x))), - 0x9003: ('DateTimeOriginal', ), - 0x9004: ('DateTimeDigitized', ), - 0x9101: ('ComponentsConfiguration', - {0: '', - 1: 'Y', - 2: 'Cb', - 3: 'Cr', - 4: 'Red', - 5: 'Green', - 6: 'Blue'}), - 0x9102: ('CompressedBitsPerPixel', ), - 0x9201: ('ShutterSpeedValue', ), - 0x9202: ('ApertureValue', ), - 0x9203: ('BrightnessValue', ), - 0x9204: ('ExposureBiasValue', ), - 0x9205: ('MaxApertureValue', ), - 0x9206: ('SubjectDistance', ), - 0x9207: ('MeteringMode', - {0: 'Unidentified', - 1: 'Average', - 2: 'CenterWeightedAverage', - 3: 'Spot', - 4: 'MultiSpot'}), - 0x9208: ('LightSource', - {0: 'Unknown', - 1: 'Daylight', - 2: 'Fluorescent', - 3: 'Tungsten', - 10: 'Flash', - 17: 'Standard Light A', - 18: 'Standard Light B', - 19: 'Standard Light C', - 20: 'D55', - 21: 'D65', - 22: 'D75', - 255: 'Other'}), - 0x9209: ('Flash', {0: 'No', - 1: 'Fired', - 5: 'Fired (?)', # no return sensed - 7: 'Fired (!)', # return sensed - 9: 'Fill Fired', - 13: 'Fill Fired (?)', - 15: 'Fill Fired (!)', - 16: 'Off', - 24: 'Auto Off', - 25: 'Auto Fired', - 29: 'Auto Fired (?)', - 31: 'Auto Fired (!)', - 32: 'Not Available'}), - 0x920A: ('FocalLength', ), - 0x927C: ('MakerNote', ), - # print as string - #0x9286: ('UserComment', lambda x: ''.join(map(chr, x))), - 0x9290: ('SubSecTime', ), - 0x9291: ('SubSecTimeOriginal', ), - 0x9292: ('SubSecTimeDigitized', ), - # print as string - #0xA000: ('FlashPixVersion', lambda x: ''.join(map(chr, x))), - 0xA001: ('ColorSpace', ), - 0xA002: ('ExifImageWidth', ), - 0xA003: ('ExifImageLength', ), - 0xA005: ('InteroperabilityOffset', ), - 0xA20B: ('FlashEnergy', ), # 0x920B in TIFF/EP - 0xA20C: ('SpatialFrequencyResponse', ), # 0x920C - - - 0xA20E: ('FocalPlaneXResolution', ), # 0x920E - - - 0xA20F: ('FocalPlaneYResolution', ), # 0x920F - - - 0xA210: ('FocalPlaneResolutionUnit', ), # 0x9210 - - - 0xA214: ('SubjectLocation', ), # 0x9214 - - - 0xA215: ('ExposureIndex', ), # 0x9215 - - - 0xA217: ('SensingMethod', ), # 0x9217 - - - 0xA300: ('FileSource', - {3: 'Digital Camera'}), - 0xA301: ('SceneType', - {1: 'Directly Photographed'}), - 0xA302: ('CVAPattern',), - } - -# interoperability tags -INTR_TAGS={ - 0x0001: ('InteroperabilityIndex', ), - 0x0002: ('InteroperabilityVersion', ), - 0x1000: ('RelatedImageFileFormat', ), - 0x1001: ('RelatedImageWidth', ), - 0x1002: ('RelatedImageLength', ), - } - -# GPS tags (not used yet, haven't seen camera with GPS) -GPS_TAGS={ - 0x0000: ('GPSVersionID', ), - 0x0001: ('GPSLatitudeRef', ), - 0x0002: ('GPSLatitude', ), - 0x0003: ('GPSLongitudeRef', ), - 0x0004: ('GPSLongitude', ), - 0x0005: ('GPSAltitudeRef', ), - 0x0006: ('GPSAltitude', ), - 0x0007: ('GPSTimeStamp', ), - 0x0008: ('GPSSatellites', ), - 0x0009: ('GPSStatus', ), - 0x000A: ('GPSMeasureMode', ), - 0x000B: ('GPSDOP', ), - 0x000C: ('GPSSpeedRef', ), - 0x000D: ('GPSSpeed', ), - 0x000E: ('GPSTrackRef', ), - 0x000F: ('GPSTrack', ), - 0x0010: ('GPSImgDirectionRef', ), - 0x0011: ('GPSImgDirection', ), - 0x0012: ('GPSMapDatum', ), - 0x0013: ('GPSDestLatitudeRef', ), - 0x0014: ('GPSDestLatitude', ), - 0x0015: ('GPSDestLongitudeRef', ), - 0x0016: ('GPSDestLongitude', ), - 0x0017: ('GPSDestBearingRef', ), - 0x0018: ('GPSDestBearing', ), - 0x0019: ('GPSDestDistanceRef', ), - 0x001A: ('GPSDestDistance', ) - } - -# Nikon E99x MakerNote Tags -# http://members.tripod.com/~tawba/990exif.htm -MAKERNOTE_NIKON_NEWER_TAGS={ - 0x0002: ('ISOSetting', ), - 0x0003: ('ColorMode', ), - 0x0004: ('Quality', ), - 0x0005: ('Whitebalance', ), - 0x0006: ('ImageSharpening', ), - 0x0007: ('FocusMode', ), - 0x0008: ('FlashSetting', ), - 0x0009: ('AutoFlashMode', ), - 0x000B: ('WhiteBalanceBias', ), - 0x000C: ('WhiteBalanceRBCoeff', ), - 0x000F: ('ISOSelection', ), - 0x0012: ('FlashCompensation', ), - 0x0013: ('ISOSpeedRequested', ), - 0x0016: ('PhotoCornerCoordinates', ), - 0x0018: ('FlashBracketCompensationApplied', ), - 0x0019: ('AEBracketCompensationApplied', ), - 0x0080: ('ImageAdjustment', ), - 0x0081: ('ToneCompensation', ), - 0x0082: ('AuxiliaryLens', ), - 0x0083: ('LensType', ), - 0x0084: ('LensMinMaxFocalMaxAperture', ), - 0x0085: ('ManualFocusDistance', ), - 0x0086: ('DigitalZoomFactor', ), - 0x0088: ('AFFocusPosition', - {0x0000: 'Center', - 0x0100: 'Top', - 0x0200: 'Bottom', - 0x0300: 'Left', - 0x0400: 'Right'}), - 0x0089: ('BracketingMode', - {0x00: 'Single frame, no bracketing', - 0x01: 'Continuous, no bracketing', - 0x02: 'Timer, no bracketing', - 0x10: 'Single frame, exposure bracketing', - 0x11: 'Continuous, exposure bracketing', - 0x12: 'Timer, exposure bracketing', - 0x40: 'Single frame, white balance bracketing', - 0x41: 'Continuous, white balance bracketing', - 0x42: 'Timer, white balance bracketing'}), - 0x008D: ('ColorMode', ), - 0x008F: ('SceneMode?', ), - 0x0090: ('LightingType', ), - 0x0092: ('HueAdjustment', ), - 0x0094: ('Saturation', - {-3: 'B&W', - -2: '-2', - -1: '-1', - 0: '0', - 1: '1', - 2: '2'}), - 0x0095: ('NoiseReduction', ), - 0x00A7: ('TotalShutterReleases', ), - 0x00A9: ('ImageOptimization', ), - 0x00AA: ('Saturation', ), - 0x00AB: ('DigitalVariProgram', ), - 0x0010: ('DataDump', ) - } - -MAKERNOTE_NIKON_OLDER_TAGS={ - 0x0003: ('Quality', - {1: 'VGA Basic', - 2: 'VGA Normal', - 3: 'VGA Fine', - 4: 'SXGA Basic', - 5: 'SXGA Normal', - 6: 'SXGA Fine'}), - 0x0004: ('ColorMode', - {1: 'Color', - 2: 'Monochrome'}), - 0x0005: ('ImageAdjustment', - {0: 'Normal', - 1: 'Bright+', - 2: 'Bright-', - 3: 'Contrast+', - 4: 'Contrast-'}), - 0x0006: ('CCDSpeed', - {0: 'ISO 80', - 2: 'ISO 160', - 4: 'ISO 320', - 5: 'ISO 100'}), - 0x0007: ('WhiteBalance', - {0: 'Auto', - 1: 'Preset', - 2: 'Daylight', - 3: 'Incandescent', - 4: 'Fluorescent', - 5: 'Cloudy', - 6: 'Speed Light'}) - } - -# decode Olympus SpecialMode tag in MakerNote -def olympus_special_mode(v): - a={ - 0: 'Normal', - 1: 'Unknown', - 2: 'Fast', - 3: 'Panorama'} - b={ - 0: 'Non-panoramic', - 1: 'Left to right', - 2: 'Right to left', - 3: 'Bottom to top', - 4: 'Top to bottom'} - return '%s - sequence %d - %s' % (a[v[0]], v[1], b[v[2]]) - -MAKERNOTE_OLYMPUS_TAGS={ - # ah HAH! those sneeeeeaky bastids! this is how they get past the fact - # that a JPEG thumbnail is not allowed in an uncompressed TIFF file - 0x0100: ('JPEGThumbnail', ), - 0x0200: ('SpecialMode', olympus_special_mode), - 0x0201: ('JPEGQual', - {1: 'SQ', - 2: 'HQ', - 3: 'SHQ'}), - 0x0202: ('Macro', - {0: 'Normal', - 1: 'Macro'}), - 0x0204: ('DigitalZoom', ), - 0x0207: ('SoftwareRelease', ), - 0x0208: ('PictureInfo', ), - # print as string - 0x0209: ('CameraID', lambda x: ''.join(map(chr, x))), - 0x0F00: ('DataDump', ) - } - -MAKERNOTE_CASIO_TAGS={ - 0x0001: ('RecordingMode', - {1: 'Single Shutter', - 2: 'Panorama', - 3: 'Night Scene', - 4: 'Portrait', - 5: 'Landscape'}), - 0x0002: ('Quality', - {1: 'Economy', - 2: 'Normal', - 3: 'Fine'}), - 0x0003: ('FocusingMode', - {2: 'Macro', - 3: 'Auto Focus', - 4: 'Manual Focus', - 5: 'Infinity'}), - 0x0004: ('FlashMode', - {1: 'Auto', - 2: 'On', - 3: 'Off', - 4: 'Red Eye Reduction'}), - 0x0005: ('FlashIntensity', - {11: 'Weak', - 13: 'Normal', - 15: 'Strong'}), - 0x0006: ('Object Distance', ), - 0x0007: ('WhiteBalance', - {1: 'Auto', - 2: 'Tungsten', - 3: 'Daylight', - 4: 'Fluorescent', - 5: 'Shade', - 129: 'Manual'}), - 0x000B: ('Sharpness', - {0: 'Normal', - 1: 'Soft', - 2: 'Hard'}), - 0x000C: ('Contrast', - {0: 'Normal', - 1: 'Low', - 2: 'High'}), - 0x000D: ('Saturation', - {0: 'Normal', - 1: 'Low', - 2: 'High'}), - 0x0014: ('CCDSpeed', - {64: 'Normal', - 80: 'Normal', - 100: 'High', - 125: '+1.0', - 244: '+3.0', - 250: '+2.0',}) - } - -MAKERNOTE_FUJIFILM_TAGS={ - 0x0000: ('NoteVersion', lambda x: ''.join(map(chr, x))), - 0x1000: ('Quality', ), - 0x1001: ('Sharpness', - {1: 'Soft', - 2: 'Soft', - 3: 'Normal', - 4: 'Hard', - 5: 'Hard'}), - 0x1002: ('WhiteBalance', - {0: 'Auto', - 256: 'Daylight', - 512: 'Cloudy', - 768: 'DaylightColor-Fluorescent', - 769: 'DaywhiteColor-Fluorescent', - 770: 'White-Fluorescent', - 1024: 'Incandescent', - 3840: 'Custom'}), - 0x1003: ('Color', - {0: 'Normal', - 256: 'High', - 512: 'Low'}), - 0x1004: ('Tone', - {0: 'Normal', - 256: 'High', - 512: 'Low'}), - 0x1010: ('FlashMode', - {0: 'Auto', - 1: 'On', - 2: 'Off', - 3: 'Red Eye Reduction'}), - 0x1011: ('FlashStrength', ), - 0x1020: ('Macro', - {0: 'Off', - 1: 'On'}), - 0x1021: ('FocusMode', - {0: 'Auto', - 1: 'Manual'}), - 0x1030: ('SlowSync', - {0: 'Off', - 1: 'On'}), - 0x1031: ('PictureMode', - {0: 'Auto', - 1: 'Portrait', - 2: 'Landscape', - 4: 'Sports', - 5: 'Night', - 6: 'Program AE', - 256: 'Aperture Priority AE', - 512: 'Shutter Priority AE', - 768: 'Manual Exposure'}), - 0x1100: ('MotorOrBracket', - {0: 'Off', - 1: 'On'}), - 0x1300: ('BlurWarning', - {0: 'Off', - 1: 'On'}), - 0x1301: ('FocusWarning', - {0: 'Off', - 1: 'On'}), - 0x1302: ('AEWarning', - {0: 'Off', - 1: 'On'}) - } - -MAKERNOTE_CANON_TAGS={ - 0x0006: ('ImageType', ), - 0x0007: ('FirmwareVersion', ), - 0x0008: ('ImageNumber', ), - 0x0009: ('OwnerName', ) - } - -# see http://www.burren.cx/david/canon.html by David Burren -# this is in element offset, name, optional value dictionary format -MAKERNOTE_CANON_TAG_0x001={ - 1: ('Macromode', - {1: 'Macro', - 2: 'Normal'}), - 2: ('SelfTimer', ), - 3: ('Quality', - {2: 'Normal', - 3: 'Fine', - 5: 'Superfine'}), - 4: ('FlashMode', - {0: 'Flash Not Fired', - 1: 'Auto', - 2: 'On', - 3: 'Red-Eye Reduction', - 4: 'Slow Synchro', - 5: 'Auto + Red-Eye Reduction', - 6: 'On + Red-Eye Reduction', - 16: 'external flash'}), - 5: ('ContinuousDriveMode', - {0: 'Single Or Timer', - 1: 'Continuous'}), - 7: ('FocusMode', - {0: 'One-Shot', - 1: 'AI Servo', - 2: 'AI Focus', - 3: 'MF', - 4: 'Single', - 5: 'Continuous', - 6: 'MF'}), - 10: ('ImageSize', - {0: 'Large', - 1: 'Medium', - 2: 'Small'}), - 11: ('EasyShootingMode', - {0: 'Full Auto', - 1: 'Manual', - 2: 'Landscape', - 3: 'Fast Shutter', - 4: 'Slow Shutter', - 5: 'Night', - 6: 'B&W', - 7: 'Sepia', - 8: 'Portrait', - 9: 'Sports', - 10: 'Macro/Close-Up', - 11: 'Pan Focus'}), - 12: ('DigitalZoom', - {0: 'None', - 1: '2x', - 2: '4x'}), - 13: ('Contrast', - {0xFFFF: 'Low', - 0: 'Normal', - 1: 'High'}), - 14: ('Saturation', - {0xFFFF: 'Low', - 0: 'Normal', - 1: 'High'}), - 15: ('Sharpness', - {0xFFFF: 'Low', - 0: 'Normal', - 1: 'High'}), - 16: ('ISO', - {0: 'See ISOSpeedRatings Tag', - 15: 'Auto', - 16: '50', - 17: '100', - 18: '200', - 19: '400'}), - 17: ('MeteringMode', - {3: 'Evaluative', - 4: 'Partial', - 5: 'Center-weighted'}), - 18: ('FocusType', - {0: 'Manual', - 1: 'Auto', - 3: 'Close-Up (Macro)', - 8: 'Locked (Pan Mode)'}), - 19: ('AFPointSelected', - {0x3000: 'None (MF)', - 0x3001: 'Auto-Selected', - 0x3002: 'Right', - 0x3003: 'Center', - 0x3004: 'Left'}), - 20: ('ExposureMode', - {0: 'Easy Shooting', - 1: 'Program', - 2: 'Tv-priority', - 3: 'Av-priority', - 4: 'Manual', - 5: 'A-DEP'}), - 23: ('LongFocalLengthOfLensInFocalUnits', ), - 24: ('ShortFocalLengthOfLensInFocalUnits', ), - 25: ('FocalUnitsPerMM', ), - 28: ('FlashActivity', - {0: 'Did Not Fire', - 1: 'Fired'}), - 29: ('FlashDetails', - {14: 'External E-TTL', - 13: 'Internal Flash', - 11: 'FP Sync Used', - 7: '2nd("Rear")-Curtain Sync Used', - 4: 'FP Sync Enabled'}), - 32: ('FocusMode', - {0: 'Single', - 1: 'Continuous'}) - } - -MAKERNOTE_CANON_TAG_0x004={ - 7: ('WhiteBalance', - {0: 'Auto', - 1: 'Sunny', - 2: 'Cloudy', - 3: 'Tungsten', - 4: 'Fluorescent', - 5: 'Flash', - 6: 'Custom'}), - 9: ('SequenceNumber', ), - 14: ('AFPointUsed', ), - 15: ('FlashBias', - {0XFFC0: '-2 EV', - 0XFFCC: '-1.67 EV', - 0XFFD0: '-1.50 EV', - 0XFFD4: '-1.33 EV', - 0XFFE0: '-1 EV', - 0XFFEC: '-0.67 EV', - 0XFFF0: '-0.50 EV', - 0XFFF4: '-0.33 EV', - 0X0000: '0 EV', - 0X000C: '0.33 EV', - 0X0010: '0.50 EV', - 0X0014: '0.67 EV', - 0X0020: '1 EV', - 0X002C: '1.33 EV', - 0X0030: '1.50 EV', - 0X0034: '1.67 EV', - 0X0040: '2 EV'}), - 19: ('SubjectDistance', ) - } - -# extract multibyte integer in Motorola format (little endian) -def s2n_motorola(str): - x=0 - for c in str: - x=(x << 8) | ord(c) - return x - -# extract multibyte integer in Intel format (big endian) -def s2n_intel(str): - x=0 - y=0L - for c in str: - x=x | (ord(c) << y) - y=y+8 - return x - -# ratio object that eventually will be able to reduce itself to lowest -# common denominator for printing -def gcd(a, b): - if b == 0: - return a - else: - return gcd(b, a % b) - -class Ratio: - def __init__(self, num, den): - self.num=num - self.den=den - - def __repr__(self): - self.reduce() - if self.den == 1: - return str(self.num) - return '%d/%d' % (self.num, self.den) - - def reduce(self): - div=gcd(self.num, self.den) - if div > 1: - self.num=self.num/div - self.den=self.den/div - -# for ease of dealing with tags -class IFD_Tag: - def __init__(self, printable, tag, field_type, values, field_offset, - field_length): - # printable version of data - self.printable=printable - # tag ID number - self.tag=tag - # field type as index into FIELD_TYPES - self.field_type=field_type - # offset of start of field in bytes from beginning of IFD - self.field_offset=field_offset - # length of data field in bytes - self.field_length=field_length - # either a string or array of data items - self.values=values - - def __str__(self): - return self.printable - - def __repr__(self): - return '(0x%04X) %s=%s @ %d' % (self.tag, - FIELD_TYPES[self.field_type][2], - self.printable, - self.field_offset) - -# class that handles an EXIF header -class EXIF_header: - def __init__(self, file, endian, offset, fake_exif, debug=0): - self.file=file - self.endian=endian - self.offset=offset - self.fake_exif=fake_exif - self.debug=debug - self.tags={} - - # convert slice to integer, based on sign and endian flags - # usually this offset is assumed to be relative to the beginning of the - # start of the EXIF information. For some cameras that use relative tags, - # this offset may be relative to some other starting point. - def s2n(self, offset, length, signed=0): - self.file.seek(self.offset+offset) - slice=self.file.read(length) - if self.endian == 'I': - val=s2n_intel(slice) - else: - val=s2n_motorola(slice) - # Sign extension ? - if signed: - msb=1L << (8*length-1) - if val & msb: - val=val-(msb << 1) - return val - - # convert offset to string - def n2s(self, offset, length): - s='' - for i in range(length): - if self.endian == 'I': - s=s+chr(offset & 0xFF) - else: - s=chr(offset & 0xFF)+s - offset=offset >> 8 - return s - - # return first IFD - def first_IFD(self): - return self.s2n(4, 4) - - # return pointer to next IFD - def next_IFD(self, ifd): - entries=self.s2n(ifd, 2) - return self.s2n(ifd+2+12*entries, 4) - - # return list of IFDs in header - def list_IFDs(self): - i=self.first_IFD() - a=[] - while i: - a.append(i) - i=self.next_IFD(i) - return a - - # return list of entries in this IFD - def dump_IFD(self, ifd, ifd_name, dict=EXIF_TAGS, relative=0): - entries=self.s2n(ifd, 2) - for i in range(entries): - # entry is index of start of this IFD in the file - entry=ifd+2+12*i - tag=self.s2n(entry, 2) - # get tag name. We do it early to make debugging easier - tag_entry=dict.get(tag) - if tag_entry: - tag_name=tag_entry[0] - else: - tag_name='Tag 0x%04X' % tag - field_type=self.s2n(entry+2, 2) - if not 0 < field_type < len(FIELD_TYPES): - # unknown field type - raise ValueError, \ - 'unknown type %d in tag 0x%04X' % (field_type, tag) - typelen=FIELD_TYPES[field_type][0] - count=self.s2n(entry+4, 4) - offset=entry+8 - if count*typelen > 4: - # offset is not the value; it's a pointer to the value - # if relative we set things up so s2n will seek to the right - # place when it adds self.offset. Note that this 'relative' - # is for the Nikon type 3 makernote. Other cameras may use - # other relative offsets, which would have to be computed here - # slightly differently. - if relative: - tmp_offset=self.s2n(offset, 4) - offset=tmp_offset+ifd-self.offset+4 - if self.fake_exif: - offset=offset+18 - else: - offset=self.s2n(offset, 4) - field_offset=offset - if field_type == 2: - # special case: null-terminated ASCII string - if count != 0: - self.file.seek(self.offset+offset) - values=self.file.read(count) - values=values.strip().replace('\x00','') - else: - values='' - else: - values=[] - signed=(field_type in [6, 8, 9, 10]) - for j in range(count): - if field_type in (5, 10): - # a ratio - value_j=Ratio(self.s2n(offset, 4, signed), - self.s2n(offset+4, 4, signed)) - else: - value_j=self.s2n(offset, typelen, signed) - values.append(value_j) - offset=offset+typelen - # now "values" is either a string or an array - if count == 1 and field_type != 2: - printable=str(values[0]) - else: - printable=str(values) - # compute printable version of values - if tag_entry: - if len(tag_entry) != 1: - # optional 2nd tag element is present - if callable(tag_entry[1]): - # call mapping function - printable=tag_entry[1](values) - else: - printable='' - for i in values: - # use lookup table for this tag - printable+=tag_entry[1].get(i, repr(i)) - self.tags[ifd_name+' '+tag_name]=IFD_Tag(printable, tag, - field_type, - values, field_offset, - count*typelen) - if self.debug: - print ' debug: %s: %s' % (tag_name, - repr(self.tags[ifd_name+' '+tag_name])) - - # extract uncompressed TIFF thumbnail (like pulling teeth) - # we take advantage of the pre-existing layout in the thumbnail IFD as - # much as possible - def extract_TIFF_thumbnail(self, thumb_ifd): - entries=self.s2n(thumb_ifd, 2) - # this is header plus offset to IFD ... - if self.endian == 'M': - tiff='MM\x00*\x00\x00\x00\x08' - else: - tiff='II*\x00\x08\x00\x00\x00' - # ... plus thumbnail IFD data plus a null "next IFD" pointer - self.file.seek(self.offset+thumb_ifd) - tiff+=self.file.read(entries*12+2)+'\x00\x00\x00\x00' - - # fix up large value offset pointers into data area - for i in range(entries): - entry=thumb_ifd+2+12*i - tag=self.s2n(entry, 2) - field_type=self.s2n(entry+2, 2) - typelen=FIELD_TYPES[field_type][0] - count=self.s2n(entry+4, 4) - oldoff=self.s2n(entry+8, 4) - # start of the 4-byte pointer area in entry - ptr=i*12+18 - # remember strip offsets location - if tag == 0x0111: - strip_off=ptr - strip_len=count*typelen - # is it in the data area? - if count*typelen > 4: - # update offset pointer (nasty "strings are immutable" crap) - # should be able to say "tiff[ptr:ptr+4]=newoff" - newoff=len(tiff) - tiff=tiff[:ptr]+self.n2s(newoff, 4)+tiff[ptr+4:] - # remember strip offsets location - if tag == 0x0111: - strip_off=newoff - strip_len=4 - # get original data and store it - self.file.seek(self.offset+oldoff) - tiff+=self.file.read(count*typelen) - - # add pixel strips and update strip offset info - old_offsets=self.tags['Thumbnail StripOffsets'].values - old_counts=self.tags['Thumbnail StripByteCounts'].values - for i in range(len(old_offsets)): - # update offset pointer (more nasty "strings are immutable" crap) - offset=self.n2s(len(tiff), strip_len) - tiff=tiff[:strip_off]+offset+tiff[strip_off+strip_len:] - strip_off+=strip_len - # add pixel strip to end - self.file.seek(self.offset+old_offsets[i]) - tiff+=self.file.read(old_counts[i]) - - self.tags['TIFFThumbnail']=tiff - - # decode all the camera-specific MakerNote formats - - # Note is the data that comprises this MakerNote. The MakerNote will - # likely have pointers in it that point to other parts of the file. We'll - # use self.offset as the starting point for most of those pointers, since - # they are relative to the beginning of the file. - # - # If the MakerNote is in a newer format, it may use relative addressing - # within the MakerNote. In that case we'll use relative addresses for the - # pointers. - # - # As an aside: it's not just to be annoying that the manufacturers use - # relative offsets. It's so that if the makernote has to be moved by the - # picture software all of the offsets don't have to be adjusted. Overall, - # this is probably the right strategy for makernotes, though the spec is - # ambiguous. (The spec does not appear to imagine that makernotes would - # follow EXIF format internally. Once they did, it's ambiguous whether - # the offsets should be from the header at the start of all the EXIF info, - # or from the header at the start of the makernote.) - def decode_maker_note(self): - note=self.tags['EXIF MakerNote'] - make=self.tags['Image Make'].printable - model=self.tags['Image Model'].printable - - # Nikon - # The maker note usually starts with the word Nikon, followed by the - # type of the makernote (1 or 2, as a short). If the word Nikon is - # not at the start of the makernote, it's probably type 2, since some - # cameras work that way. - if make in ('NIKON', 'NIKON CORPORATION'): - if note.values[0:7] == [78, 105, 107, 111, 110, 00, 01]: - if self.debug: - print "Looks like a type 1 Nikon MakerNote." - self.dump_IFD(note.field_offset+8, 'MakerNote', - dict=MAKERNOTE_NIKON_OLDER_TAGS) - elif note.values[0:7] == [78, 105, 107, 111, 110, 00, 02]: - if self.debug: - print "Looks like a labeled type 2 Nikon MakerNote" - if note.values[12:14] != [0, 42] and note.values[12:14] != [42L, 0L]: - raise ValueError, "Missing marker tag '42' in MakerNote." - # skip the Makernote label and the TIFF header - self.dump_IFD(note.field_offset+10+8, 'MakerNote', - dict=MAKERNOTE_NIKON_NEWER_TAGS, relative=1) - else: - # E99x or D1 - if self.debug: - print "Looks like an unlabeled type 2 Nikon MakerNote" - self.dump_IFD(note.field_offset, 'MakerNote', - dict=MAKERNOTE_NIKON_NEWER_TAGS) - return - - # Olympus - if make[:7] == 'OLYMPUS': - self.dump_IFD(note.field_offset+8, 'MakerNote', - dict=MAKERNOTE_OLYMPUS_TAGS) - return - - # Casio - if make == 'Casio': - self.dump_IFD(note.field_offset, 'MakerNote', - dict=MAKERNOTE_CASIO_TAGS) - return - - # Fujifilm - if make == 'FUJIFILM': - # bug: everything else is "Motorola" endian, but the MakerNote - # is "Intel" endian - endian=self.endian - self.endian='I' - # bug: IFD offsets are from beginning of MakerNote, not - # beginning of file header - offset=self.offset - self.offset+=note.field_offset - # process note with bogus values (note is actually at offset 12) - self.dump_IFD(12, 'MakerNote', dict=MAKERNOTE_FUJIFILM_TAGS) - # reset to correct values - self.endian=endian - self.offset=offset - return - - # Canon - if make == 'Canon': - self.dump_IFD(note.field_offset, 'MakerNote', - dict=MAKERNOTE_CANON_TAGS) - for i in (('MakerNote Tag 0x0001', MAKERNOTE_CANON_TAG_0x001), - ('MakerNote Tag 0x0004', MAKERNOTE_CANON_TAG_0x004)): - self.canon_decode_tag(self.tags[i[0]].values, i[1]) - return - - # decode Canon MakerNote tag based on offset within tag - # see http://www.burren.cx/david/canon.html by David Burren - def canon_decode_tag(self, value, dict): - for i in range(1, len(value)): - x=dict.get(i, ('Unknown', )) - if self.debug: - print i, x - name=x[0] - if len(x) > 1: - val=x[1].get(value[i], 'Unknown') - else: - val=value[i] - # it's not a real IFD Tag but we fake one to make everybody - # happy. this will have a "proprietary" type - self.tags['MakerNote '+name]=IFD_Tag(str(val), None, 0, None, - None, None) - -# process an image file (expects an open file object) -# this is the function that has to deal with all the arbitrary nasty bits -# of the EXIF standard -def process_file(file, debug=0): - # determine whether it's a JPEG or TIFF - data=file.read(12) - if data[0:4] in ['II*\x00', 'MM\x00*']: - # it's a TIFF file - file.seek(0) - endian=file.read(1) - file.read(1) - offset=0 - elif data[0:2] == '\xFF\xD8': - # it's a JPEG file - # skip JFIF style header(s) - fake_exif=0 - while data[2] == '\xFF' and data[6:10] in ('JFIF', 'JFXX', 'OLYM'): - length=ord(data[4])*256+ord(data[5]) - file.read(length-8) - # fake an EXIF beginning of file - data='\xFF\x00'+file.read(10) - fake_exif=1 - if data[2] == '\xFF' and data[6:10] == 'Exif': - # detected EXIF header - offset=file.tell() - endian=file.read(1) - else: - # no EXIF information - return {} - else: - # file format not recognized - return {} - - # deal with the EXIF info we found - if debug: - print {'I': 'Intel', 'M': 'Motorola'}[endian], 'format' - hdr=EXIF_header(file, endian, offset, fake_exif, debug) - ifd_list=hdr.list_IFDs() - ctr=0 - for i in ifd_list: - if ctr == 0: - IFD_name='Image' - elif ctr == 1: - IFD_name='Thumbnail' - thumb_ifd=i - else: - IFD_name='IFD %d' % ctr - if debug: - print ' IFD %d (%s) at offset %d:' % (ctr, IFD_name, i) - hdr.dump_IFD(i, IFD_name) - # EXIF IFD - exif_off=hdr.tags.get(IFD_name+' ExifOffset') - if exif_off: - if debug: - print ' EXIF SubIFD at offset %d:' % exif_off.values[0] - hdr.dump_IFD(exif_off.values[0], 'EXIF') - # Interoperability IFD contained in EXIF IFD - intr_off=hdr.tags.get('EXIF SubIFD InteroperabilityOffset') - if intr_off: - if debug: - print ' EXIF Interoperability SubSubIFD at offset %d:' \ - % intr_off.values[0] - hdr.dump_IFD(intr_off.values[0], 'EXIF Interoperability', - dict=INTR_TAGS) - # GPS IFD - gps_off=hdr.tags.get(IFD_name+' GPSInfo') - if gps_off: - if debug: - print ' GPS SubIFD at offset %d:' % gps_off.values[0] - hdr.dump_IFD(gps_off.values[0], 'GPS', dict=GPS_TAGS) - ctr+=1 - - # extract uncompressed TIFF thumbnail - thumb=hdr.tags.get('Thumbnail Compression') - if thumb and thumb.printable == 'Uncompressed TIFF': - hdr.extract_TIFF_thumbnail(thumb_ifd) - - # JPEG thumbnail (thankfully the JPEG data is stored as a unit) - thumb_off=hdr.tags.get('Thumbnail JPEGInterchangeFormat') - if thumb_off: - file.seek(offset+thumb_off.values[0]) - size=hdr.tags['Thumbnail JPEGInterchangeFormatLength'].values[0] - hdr.tags['JPEGThumbnail']=file.read(size) - - # deal with MakerNote contained in EXIF IFD - if hdr.tags.has_key('EXIF MakerNote'): - hdr.decode_maker_note() - - # Sometimes in a TIFF file, a JPEG thumbnail is hidden in the MakerNote - # since it's not allowed in a uncompressed TIFF IFD - if not hdr.tags.has_key('JPEGThumbnail'): - thumb_off=hdr.tags.get('MakerNote JPEGThumbnail') - if thumb_off: - file.seek(offset+thumb_off.values[0]) - hdr.tags['JPEGThumbnail']=file.read(thumb_off.field_length) - - return hdr.tags - -# library test/debug function (dump given files) -if __name__ == '__main__': - import sys - - if len(sys.argv) < 2: - print 'Usage: %s files...\n' % sys.argv[0] - sys.exit(0) - - for filename in sys.argv[1:]: - try: - file=open(filename, 'rb') - except: - print filename, 'unreadable' - print - continue - print filename+':' - # data=process_file(file, 1) # with debug info - data=process_file(file) - if not data: - print 'No EXIF information found' - continue - - x=data.keys() - x.sort() - for i in x: - if i in ('JPEGThumbnail', 'TIFFThumbnail'): - continue - try: - print ' %s (%s): %s' % \ - (i, FIELD_TYPES[data[i].field_type][2], data[i].printable) - except: - print 'error', i, '"', data[i], '"' - if data.has_key('JPEGThumbnail'): - print 'File has JPEG thumbnail' - print - - -class Parser: - pass diff --git a/wiki/parser/Portail.py b/wiki/parser/Portail.py deleted file mode 100644 index 31d69677..00000000 --- a/wiki/parser/Portail.py +++ /dev/null @@ -1,134 +0,0 @@ -# -*- coding: iso-8859-1 -*- -""" -# -*- coding: utf-8 -*- - .. - .... ............ ........ - . ....... . .... .. - . ... .. .. .. .. ..... . .. - .. .. ....@@@. .. . ........ . - .. . .. ..@.@@..@@. .@@@@@@@ @@@@@@. .... - .@@@@. .@@@@. .@@@@..@@.@@..@@@..@@@..@@@@.... .... - @@@@... .@@@.. @@ @@ .@..@@..@@...@@@. .@@@@@. .. - .@@@.. . @@@. @@.@@..@@.@@..@@@ @@ .@@@@@@.. ..... - ...@@@.... @@@ .@@.......... ........ ..... .. - . ..@@@@.. . .@@@@. .. ....... . ............. - . .. .... .. .. . ... .... - . . .... ............. .. ... - .. .. ... ........ ... ... - ................................ - -MoinMoin - Portail parser - - PURPOSE: - Pour afficher un portail a la wikipedia. - - CALLING SEQUENCE: - {{{ - #!Portail - image1.png @@ title1 @@ description 1 - image2.png @@ title2 @@ description 2 - image3.png @@ title3 @@ description 3 - }}} - - CREDIT - Le code est derive de celui de Gallery2. - -""" -from MoinMoin.parser import wiki -import os,string,re,StringIO -from MoinMoin.action import AttachFile - -##################################################################### -# Fonctions # -##################################################################### -# to_wikiname : transfome la chaine text avec le parser wiki -# classique et le formateur formatter -# (je sais pas a quoi sert request, mais faut pas -# l'enlever !) -####### - -def to_wikiname(request,formatter,text): - ##taken from MiniPage - out=StringIO.StringIO() - request.redirect(out) - wikiizer = wiki.Parser(text.strip(),request) - wikiizer.format(formatter) - result=out.getvalue() - request.redirect() - del out - - return result.strip() - -##################################################################### -# PortailFormatter : creer le code html du portail a l'aide de -# de formatter et l'envoie a request -####### -class PortailFormatter: - - def __init__(self, request, formatter): - self.formatter = formatter - self.request = request - self.counter = 0 - - def open(self): - self.request.write(self.formatter.table(1,{'style':'width:100%;padding:10px;'})) - - def cell(self, title, description, image): - if self.counter==0: - self.request.write(self.formatter.table_row(1)) - self.request.write(self.formatter.table_cell(1,{'style':'width:50%;border:none;padding:20px 20px 20px 50px;background:transparent url(\'' + image.replace("\'","\\\'") + '\') center left no-repeat; vertical-align:middle;'})) - self.request.write(title) - self.request.write(description) - self.request.write(self.formatter.table_cell(0)) - if self.counter==1: - self.request.write(self.formatter.table_row(0)) - self.counter = (self.counter + 1)%2 - - def close(self): - if self.counter==1: - self.request.write(self.formatter.table_cell(1,{'style':'width:50%;border:none;padding:20px 20px 20px 50px;'})) - self.request.write(self.formatter.table_cell(0)) - self.request.write(self.formatter.table_row(0)) - self.request.write(self.formatter.table(0)) - -##################################################################### -# Parser : classe principale, c'est elle qui parse -####### -class Parser: - - def __init__(self, raw, request, **kw): - self.request = request - self.raw = raw - return - - - def format(self, formatter): - - # on divise le textes en lignes (1 ligne = une entree dans le portail) - quotes = self.raw.split('\n') - - # on récupere le chemin des fichiers attaches pour les images - current_pagename=formatter.page.page_name - attachment_path = AttachFile.getAttachDir(self.request, current_pagename, create=1) - - # on initialise la classe qui va fabriquer le code html - portail = PortailFormatter(self.request, formatter) - portail.open() - - # on traite les ligne une à une - for line in quotes: - line=line.strip() - items=line.split('@@',2) - if items.__len__()<3: - self.request.write('') - else: - description=items.pop().strip() - link=items.pop().strip() - image = AttachFile.getAttachUrl(current_pagename, items.pop().strip(), self.request).replace('& ','&') - - link = to_wikiname(self.request, formatter, link) - description = to_wikiname(self.request, formatter, description) - portail.cell(link, description, image) - portail.close() - - return diff --git a/wiki/parser/__init__.py b/wiki/parser/__init__.py deleted file mode 100644 index e4ed3b60..00000000 --- a/wiki/parser/__init__.py +++ /dev/null @@ -1,5 +0,0 @@ -# -*- coding: iso-8859-1 -*- - -from MoinMoin.util import pysupport - -modules = pysupport.getPackageModules(__file__) diff --git a/wiki/parser/latex.py b/wiki/parser/latex.py deleted file mode 100644 index d2f43a75..00000000 --- a/wiki/parser/latex.py +++ /dev/null @@ -1,214 +0,0 @@ -#FORMAT python -#!/usr/bin/python -# -*- coding: iso-8859-15 -*- - -""" -New latex formatter using dvipng and tempfile - -Author: JohannesBerg - -This parser (and the corresponding macro) was tested with Python 2.3.4 and - * Debian Linux with out-of-the-box tetex-bin and dvipng packages installed - * Windows XP (not by me) - -In the parser, you can add stuff to the prologue by writing -%%end-prologue%% -somewhere in the document, before that write stuff like \\usepackage and after it put -the actual latex display code. -""" - -Dependencies = [] - -import sha, os, tempfile, shutil, re -from MoinMoin.action import AttachFile -from MoinMoin.Page import Page - -latex_template = r''' -\documentclass[12pt]{article} -\pagestyle{empty} -%(prologue)s -\begin{document} -%(raw)s -\end{document} -''' - -max_pages = 10 -MAX_RUN_TIME = 5 # seconds - -latex = "latex" # edit full path here, e.g. reslimit = "C:\\path\\to\\latex.exe" -dvipng = "dvipng" # edit full path here (or reslimit = r'C:\path\to\latex.exe') - -# last arg must have %s in it! -latex_args = ("--interaction=nonstopmode", "%s.tex") - -# last arg must have %s in it! -dvipng_args = ("-bgTransparent", "-Ttight", "--noghostscript", "-l%s" % max_pages, "%s.dvi") - -# this is formatted with hexdigest(texcode), -# page number and extension are appended by -# the tools -latex_name_template = "latex_%s_p" - -# keep this up-to-date, also with max_pages!! -latex_attachment = re.compile((latex_name_template+'%s%s') % (r'[0-9a-fA-F]{40}', r'[0-9]{1,2}', r'\.png')) - -anchor = re.compile(r'^%%anchor:[ ]*([a-zA-Z0-9_-]+)$', re.MULTILINE | re.IGNORECASE) -# the anchor re must start with a % sign to be ignored by latex as a comment! -end_prologue = '%%end-prologue%%' - -def call_command_in_dir_NT(app, args, targetdir): - reslimit = "runlimit.exe" # edit full path here - os.environ['openin_any'] = 'p' - os.environ['openout_any'] = 'p' - os.environ['shell_escape'] = 'f' - stdouterr = os.popen('%s %d "%s" %s %s < NUL' % (reslimit, MAX_RUN_TIME, targetdir, app, ' '.join(args)), 'r') - output = ''.join(stdouterr.readlines()) - err = stdouterr.close() - if not err is None: - return ' error! exitcode was %d, transscript follows:\n\n%s' % (err,output) - return None - -def call_command_in_dir_unix(app, args, targetdir): - # this is the unix implementation - (r,w) = os.pipe() - pid = os.fork() - if pid == -1: - return 'could not fork' - if pid == 0: - # child - os.close(r) - os.dup2(os.open("/dev/null", os.O_WRONLY), 0) - os.dup2(w, 1) - os.dup2(w, 2) - os.chdir(targetdir) - os.environ['openin_any'] = 'p' - os.environ['openout_any'] = 'p' - os.environ['shell_escape'] = 'f' - import resource - resource.setrlimit(resource.RLIMIT_CPU, - (MAX_RUN_TIME * 1000, MAX_RUN_TIME * 1000)) # docs say this is seconds, but it is msecs on my system. - os.execvp(app, [app] + list(args)) - print "failed to exec()",app - os._exit(2) - else: - # parent - os.close(w) - r = os.fdopen(r,"r") - output = ''.join(r.readlines()) - (npid, exi) = os.waitpid(pid, 0) - r.close() - sig = exi & 0xFF - stat = exi >> 8 - if stat != 0 or sig != 0: - return ' error! exitcode was %d (signal %d), transscript follows:\n\n%s' % (stat,sig,output) - return None - # notreached - -if os.name == 'nt': - call_command_in_dir = call_command_in_dir_NT -else: - call_command_in_dir = call_command_in_dir_unix - - -class Parser: - extensions = ['.tex'] - def __init__ (self, raw, request, **kw): - self.raw = raw - if len(self.raw)>0 and self.raw[0] == '#': - self.raw[0] = '%' - self.request = request - self.exclude = [] - if not hasattr(request, "latex_cleanup_done"): - request.latex_cleanup_done = {} - - def cleanup(self, pagename): - attachdir = AttachFile.getAttachDir(self.request, pagename, create=1) - for f in os.listdir(attachdir): - if not latex_attachment.match(f) is None: - os.remove("%s/%s" % (attachdir, f)) - - def _internal_format(self, formatter, text): - tmp = text.split(end_prologue, 1) - if len(tmp) == 2: - prologue,tex=tmp - else: - prologue = '' - tex = tmp[0] - if callable(getattr(formatter, 'johill_sidecall_emit_latex', None)): - return formatter.johill_sidecall_emit_latex(tex) - return self.get(formatter, tex, prologue, True) - - def format(self, formatter): - self.request.write(self._internal_format(formatter, self.raw)) - - def get(self, formatter, inputtex, prologue, para=False): - if not self.request.latex_cleanup_done.has_key(formatter.page.page_name): - self.request.latex_cleanup_done[formatter.page.page_name] = True - self.cleanup(formatter.page.page_name) - - if len(inputtex) == 0: return '' - - if callable(getattr(formatter, 'johill_sidecall_emit_latex', None)): - return formatter.johill_sidecall_emit_latex(inputtex) - - extra_preamble = '' - preamble_page = self.request.pragma.get('latex_preamble', None) - if preamble_page is not None: - extra_preamble = Page(self.request, preamble_page).get_raw_body() - extra_preamble = re.sub(re.compile('^#'), '%', extra_preamble) - - tex = latex_template % { 'raw': inputtex, 'prologue': extra_preamble + prologue } - enctex = tex.encode('utf-8') - fn = latex_name_template % sha.new(enctex).hexdigest() - - attachdir = AttachFile.getAttachDir(self.request, formatter.page.page_name, create=1) - dst = "%s/%s%%d.png" % (attachdir, fn) - if not os.access(dst % 1, os.R_OK): - tmpdir = tempfile.mkdtemp() - try: - data = open("%s/%s.tex" % (tmpdir, fn), "w") - data.write(enctex) - data.close() - args = list(latex_args) - args[-1] = args[-1] % fn - res = call_command_in_dir(latex, args, tmpdir) - if not res is None: - return formatter.preformatted(1)+formatter.text('latex'+res)+formatter.preformatted(0) - args = list(dvipng_args) - args[-1] = args[-1] % fn - res = call_command_in_dir(dvipng, args, tmpdir) - if not res is None: - return formatter.preformatted(1)+formatter.text('dvipng'+res)+formatter.preformatted(0) - - page = 1 - while os.access("%s/%s%d.png" % (tmpdir, fn, page), os.R_OK): - shutil.copyfile ("%s/%s%d.png" % (tmpdir, fn, page), dst % page) - page += 1 - - finally: - for root,dirs,files in os.walk(tmpdir, topdown=False): - for name in files: - os.remove(os.path.join(root,name)) - for name in dirs: - os.rmdir(os.path.join(root,name)) - os.rmdir(tmpdir) - - result = "" - page = 1 - loop = False - for match in anchor.finditer(inputtex): - result += formatter.anchordef(match.group(1)) - for match in anchor.finditer(prologue): - result += formatter.anchordef(match.group(1)) - while os.access(dst % page, os.R_OK): - url = AttachFile.getAttachUrl(formatter.page.page_name, fn+"%d.png" % page, self.request) - if loop: - result += formatter.linebreak(0)+formatter.linebreak(0) - if para: - result += formatter.paragraph(1) - result += formatter.image(src="%s" % url, alt=inputtex, title=inputtex, align="absmiddle") - if para: - result += formatter.paragraph(0) - page += 1 - loop = True - return result diff --git a/wiki/request.py b/wiki/request.py deleted file mode 100644 index 0c44050e..00000000 --- a/wiki/request.py +++ /dev/null @@ -1,2164 +0,0 @@ -# -*- coding: iso-8859-1 -*- -""" - MoinMoin - Data associated with a single Request - - @copyright: 2001-2003 by Jürgen Hermann - @copyright: 2003-2004 by Thomas Waldmann - @license: GNU GPL, see COPYING for details. -""" - -import os, re, time, sys, cgi, StringIO -import copy -from MoinMoin import config, wikiutil, user, caching -from MoinMoin.util import MoinMoinNoFooter, IsWin9x - -# Timing --------------------------------------------------------------- - -class Clock: - """ Helper class for code profiling - we do not use time.clock() as this does not work across threads - """ - - def __init__(self): - self.timings = {'total': time.time()} - - def start(self, timer): - self.timings[timer] = time.time() - self.timings.get(timer, 0) - - def stop(self, timer): - self.timings[timer] = time.time() - self.timings[timer] - - def value(self, timer): - return "%.3f" % (self.timings[timer],) - - def dump(self): - outlist = [] - for timing in self.timings.items(): - outlist.append("%s = %.3fs" % timing) - outlist.sort() - return outlist - - -# Utilities - -def cgiMetaVariable(header, scheme='http'): - """ Return CGI meta variable for header name - - e.g 'User-Agent' -> 'HTTP_USER_AGENT' - See http://www.faqs.org/rfcs/rfc3875.html section 4.1.18 - """ - var = '%s_%s' % (scheme, header) - return var.upper().replace('-', '_') - - -# Request Base ---------------------------------------------------------- - -class RequestBase(object): - """ A collection for all data associated with ONE request. """ - - # Header set to force misbehaved proxies and browsers to keep their - # hands off a page - # Details: http://support.microsoft.com/support/kb/articles/Q234/0/67.ASP - nocache = [ - "Pragma: no-cache", - "Cache-Control: no-cache", - "Expires: -1", - ] - - # Defaults (used by sub classes) - http_accept_language = 'en' - server_name = 'localhost' - server_port = '80' - - # Extra headers we support. Both standalone and twisted store - # headers as lowercase. - moin_location = 'x-moin-location' - proxy_host = 'x-forwarded-host' - - def __init__(self, properties={}): - # Decode values collected by sub classes - self.path_info = self.decodePagename(self.path_info) - - self.failed = 0 - self._available_actions = None - self._known_actions = None - - # Pages meta data that we collect in one request - self.pages = {} - - self.sent_headers = 0 - self.user_headers = [] - self.cacheable = 0 # may this output get cached by http proxies/caches? - self.page = None - self._dicts = None - - # Fix dircaching problems on Windows 9x - if IsWin9x(): - import dircache - dircache.reset() - - # Check for dumb proxy requests - # TODO relying on request_uri will not work on all servers, especially - # not on external non-Apache servers - self.forbidden = False - if self.request_uri.startswith('http://'): - self.makeForbidden403() - - # Init - else: - self.writestack = [] - self.clock = Clock() - # order is important here! - self.__dict__.update(properties) - self._load_multi_cfg() - - self.isSpiderAgent = self.check_spider() - - # Set decode charsets. Input from the user is always in - # config.charset, which is the page charsets. Except - # path_info, which may use utf-8, and handled by decodePagename. - self.decode_charsets = [config.charset] - - # hierarchical wiki - set rootpage - from MoinMoin.Page import Page - #path = self.getPathinfo() - #if path.startswith('/'): - # pages = path[1:].split('/') - # if 0: # len(path) > 1: - # ## breaks MainPage/SubPage on flat storage - # rootname = u'/'.join(pages[:-1]) - # else: - # # this is the usual case, as it ever was... - # rootname = u"" - #else: - # # no extra path after script name - # rootname = u"" - - self.args = {} - self.form = {} - - # MOVED: this was in run() method, but moved here for auth module being able to use it - if not self.query_string.startswith('action=xmlrpc'): - self.args = self.form = self.setup_args() - - rootname = u'' - self.rootpage = Page(self, rootname, is_rootpage=1) - - self.user = self.get_user_from_form() - - if not self.query_string.startswith('action=xmlrpc'): - if not self.forbidden and self.isForbidden(): - self.makeForbidden403() - if not self.forbidden and self.surge_protect(): - self.makeUnavailable503() - - from MoinMoin import i18n - - self.logger = None - self.pragma = {} - self.mode_getpagelinks = 0 - self.no_closing_html_code = 0 - - self.i18n = i18n - self.lang = i18n.requestLanguage(self) - # Language for content. Page content should use the wiki - # default lang, but generated content like search results - # should use the user language. - self.content_lang = self.cfg.language_default - self.getText = lambda text, i18n=self.i18n, request=self, lang=self.lang, **kv: i18n.getText(text, request, lang, kv.get('formatted', True)) - - self.opened_logs = 0 - self.reset() - - def surge_protect(self): - """ check if someone requesting too much from us """ - validuser = self.user.valid - current_id = validuser and self.user.name or self.remote_addr - - #### DEBUT HACK : Excemption pour nos proxies - if not validuser and (current_id.startswith('127.') or current_id in self.cfg.ip_url_replace.keys()): # localnet - #### FIN DU HACK - return False - current_action = self.form.get('action', ['show'])[0] - - limits = self.cfg.surge_action_limits - default_limit = self.cfg.surge_action_limits.get('default', (30, 60)) - - now = int(time.time()) - surgedict = {} - surge_detected = False - - try: - cache = caching.CacheEntry(self, 'surgeprotect', 'surge-log') - if cache.exists(): - data = cache.content() - data = data.split("\n") - for line in data: - try: - id, t, action, surge_indicator = line.split("\t") - t = int(t) - maxnum, dt = limits.get(action, default_limit) - if t >= now - dt: - events = surgedict.setdefault(id, copy.copy({})) - timestamps = events.setdefault(action, copy.copy([])) - timestamps.append((t, surge_indicator)) - except StandardError, err: - pass - - maxnum, dt = limits.get(current_action, default_limit) - events = surgedict.setdefault(current_id, copy.copy({})) - timestamps = events.setdefault(current_action, copy.copy([])) - surge_detected = len(timestamps) > maxnum - - surge_indicator = surge_detected and "!" or "" - timestamps.append((now, surge_indicator)) - if surge_detected: - if len(timestamps) < maxnum*2: - timestamps.append((now + self.cfg.surge_lockout_time, surge_indicator)) # continue like that and get locked out - - if current_action != 'AttachFile': # don't add AttachFile accesses to all or picture galleries will trigger SP - current_action = 'all' # put a total limit on user's requests - maxnum, dt = limits.get(current_action, default_limit) - events = surgedict.setdefault(current_id, copy.copy({})) - timestamps = events.setdefault(current_action, copy.copy([])) - surge_detected = surge_detected or len(timestamps) > maxnum - - surge_indicator = surge_detected and "!" or "" - timestamps.append((now, surge_indicator)) - if surge_detected: - if len(timestamps) < maxnum*2: - timestamps.append((now + self.cfg.surge_lockout_time, surge_indicator)) # continue like that and get locked out - - data = [] - for id, events in surgedict.items(): - for action, timestamps in events.items(): - for t, surge_indicator in timestamps: - data.append("%s\t%d\t%s\t%s" % (id, t, action, surge_indicator)) - data = "\n".join(data) - cache.update(data) - except StandardError, err: - pass - - return surge_detected - - def getDicts(self): - """ Lazy initialize the dicts on the first access """ - if self._dicts is None: - from MoinMoin import wikidicts - dicts = wikidicts.GroupDict(self) - dicts.scandicts() - self._dicts = dicts - return self._dicts - - def delDicts(self): - """ Delete the dicts, used by some tests """ - del self._dicts - self._dicts = None - - dicts = property(getDicts, None, delDicts) - - def _load_multi_cfg(self): - # protect against calling multiple times - if not hasattr(self, 'cfg'): - from MoinMoin import multiconfig - self.cfg = multiconfig.getConfig(self.url) - - def setAcceptedCharsets(self, accept_charset): - """ Set accepted_charsets by parsing accept-charset header - - Set self.accepted_charsets to an ordered list based on - http_accept_charset. - - Reference: http://www.w3.org/Protocols/rfc2616/rfc2616.txt - - TODO: currently no code use this value. - - @param accept_charset: accept-charset header - """ - charsets = [] - if accept_charset: - accept_charset = accept_charset.lower() - # Add iso-8859-1 if needed - if (not '*' in accept_charset and - accept_charset.find('iso-8859-1') < 0): - accept_charset += ',iso-8859-1' - - # Make a list, sorted by quality value, using Schwartzian Transform - # Create list of tuples (value, name) , sort, extract names - for item in accept_charset.split(','): - if ';' in item: - name, qval = item.split(';') - qval = 1.0 - float(qval.split('=')[1]) - else: - name, qval = item, 0 - charsets.append((qval, name)) - charsets.sort() - # Remove *, its not clear what we should do with it later - charsets = [name for qval, name in charsets if name != '*'] - - self.accepted_charsets = charsets - - def _setup_vars_from_std_env(self, env): - """ Set common request variables from CGI environment - - Parse a standard CGI environment as created by common web - servers. Reference: http://www.faqs.org/rfcs/rfc3875.html - - @param env: dict like object containing cgi meta variables - """ - # Values we can just copy - self.env = env - self.http_accept_language = env.get('HTTP_ACCEPT_LANGUAGE', - self.http_accept_language) - self.server_name = env.get('SERVER_NAME', self.server_name) - self.server_port = env.get('SERVER_PORT', self.server_port) - self.saved_cookie = env.get('HTTP_COOKIE', '') - self.script_name = env.get('SCRIPT_NAME', '') - self.path_info = env.get('PATH_INFO', '') - self.query_string = env.get('QUERY_STRING', '') - self.request_method = env.get('REQUEST_METHOD', None) - self.remote_addr = env.get('REMOTE_ADDR', '') - self.http_user_agent = env.get('HTTP_USER_AGENT', '') - - # REQUEST_URI is not part of CGI spec, but an addition of Apache. - self.request_uri = env.get('REQUEST_URI', '') - - # Values that need more work - self.setHttpReferer(env.get('HTTP_REFERER')) - self.setIsSSL(env) - self.setHost(env.get('HTTP_HOST')) - self.fixURI(env) - self.setURL(env) - - ##self.debugEnvironment(env) - - def setHttpReferer(self, referer): - """ Set http_referer, making sure its ascii - - IE might send non-ascii value. - """ - value = '' - if referer: - value = unicode(referer, 'ascii', 'replace') - value = value.encode('ascii', 'replace') - self.http_referer = value - - def setIsSSL(self, env): - """ Set is_ssl - - @param env: dict like object containing cgi meta variables - """ - self.is_ssl = bool(env.get('SSL_PROTOCOL') or - env.get('SSL_PROTOCOL_VERSION') or - env.get('HTTPS') == 'on') - - def setHost(self, host=None): - """ Set http_host - - Create from server name and port if missing. Previous code - default to localhost. - """ - if not host: - port = '' - standardPort = ('80', '443')[self.is_ssl] - if self.server_port != standardPort: - port = ':' + self.server_port - host = self.server_name + port - self.http_host = host - - def fixURI(self, env): - """ Fix problems with script_name and path_info - - Handle the strange charset semantics on Windows and other non - posix systems. path_info is transformed into the system code - page by the web server. Additionally, paths containing dots let - most webservers choke. - - Broken environment variables in different environments: - path_info script_name - Apache1 X X PI does not contain dots - Apache2 X X PI is not encoded correctly - IIS X X path_info include script_name - Other ? - ? := Possible and even RFC-compatible. - - := Hopefully not. - - @param env: dict like object containing cgi meta variables - """ - # Fix the script_name when using Apache on Windows. - server_software = env.get('SERVER_SOFTWARE', '') - if os.name == 'nt' and server_software.find('Apache/') != -1: - # Removes elements ending in '.' from the path. - self.script_name = '/'.join([x for x in self.script_name.split('/') - if not x.endswith('.')]) - - # Fix path_info - if os.name != 'posix' and self.request_uri != '': - # Try to recreate path_info from request_uri. - import urlparse - scriptAndPath = urlparse.urlparse(self.request_uri)[2] - path = scriptAndPath.replace(self.script_name, '', 1) - self.path_info = wikiutil.url_unquote(path, want_unicode=False) - elif os.name == 'nt': - # Recode path_info to utf-8 - path = wikiutil.decodeWindowsPath(self.path_info) - self.path_info = path.encode("utf-8") - - # Fix bug in IIS/4.0 when path_info contain script_name - if self.path_info.startswith(self.script_name): - self.path_info = self.path_info[len(self.script_name):] - - def setURL(self, env): - """ Set url, used to locate wiki config - - This is the place to manipulate url parts as needed. - - @param env: dict like object containing cgi meta variables or - http headers. - """ - # If we serve on localhost:8000 and use a proxy on - # example.com/wiki, our urls will be example.com/wiki/pagename - # Same for the wiki config - they must use the proxy url. - self.rewriteHost(env) - self.rewriteURI(env) - - if not self.request_uri: - self.request_uri = self.makeURI() - self.url = self.http_host + self.request_uri - - def rewriteHost(self, env): - """ Rewrite http_host transparently - - Get the proxy host using 'X-Forwarded-Host' header, added by - Apache 2 and other proxy software. - - TODO: Will not work for Apache 1 or others that don't add this - header. - - TODO: If we want to add an option to disable this feature it - should be in the server script, because the config is not - loaded at this point, and must be loaded after url is set. - - @param env: dict like object containing cgi meta variables or - http headers. - """ - proxy_host = (env.get(self.proxy_host) or - env.get(cgiMetaVariable(self.proxy_host))) - if proxy_host: - self.http_host = proxy_host - - def rewriteURI(self, env): - """ Rewrite request_uri, script_name and path_info transparently - - Useful when running mod python or when running behind a proxy, - e.g run on localhost:8000/ and serve as example.com/wiki/. - - Uses private 'X-Moin-Location' header to set the script name. - This allow setting the script name when using Apache 2 - directive:: - - - RequestHeader set X-Moin-Location /my/wiki/ - - - TODO: does not work for Apache 1 and others that do not allow - setting custom headers per request. - - @param env: dict like object containing cgi meta variables or - http headers. - """ - location = (env.get(self.moin_location) or - env.get(cgiMetaVariable(self.moin_location))) - if location is None: - return - - scriptAndPath = self.script_name + self.path_info - location = location.rstrip('/') - self.script_name = location - - # This may happen when using mod_python - if scriptAndPath.startswith(location): - self.path_info = scriptAndPath[len(location):] - - # Recreate the URI from the modified parts - if self.request_uri: - self.request_uri = self.makeURI() - - def makeURI(self): - """ Return uri created from uri parts """ - uri = self.script_name + wikiutil.url_quote(self.path_info) - if self.query_string: - uri += '?' + self.query_string - return uri - - def splitURI(self, uri): - """ Return path and query splited from uri - - Just like CGI environment, the path is unquoted, the query is - not. - """ - if '?' in uri: - path, query = uri.split('?', 1) - else: - path, query = uri, '' - return wikiutil.url_unquote(path, want_unicode=False), query - - def get_user_from_form(self): - """ read the maybe present UserPreferences form and call get_user with the values """ - name = self.form.get('name', [None])[0] - password = self.form.get('password', [None])[0] - login = self.form.has_key('login') - logout = self.form.has_key('logout') - u = self.get_user_default_unknown(name=name, password=password, - login=login, logout=logout, - user_obj=None) - return u - - def get_user_default_unknown(self, **kw): - """ call do_auth and if it doesnt return a user object, make some "Unknown User" """ - user_obj = self.get_user_default_None(**kw) - if user_obj is None: - user_obj = user.User(self, auth_method="request:427") - return user_obj - - def get_user_default_None(self, **kw): - """ loop over auth handlers, return a user obj or None """ - name = kw.get('name') - password = kw.get('password') - login = kw.get('login') - logout = kw.get('logout') - user_obj = kw.get('user_obj') - for auth in self.cfg.auth: - user_obj, continue_flag = auth(self, - name=name, password=password, - login=login, logout=logout, - user_obj=user_obj) - if not continue_flag: - break - return user_obj - - def reset(self): - """ Reset request state. - - Called after saving a page, before serving the updated - page. Solves some practical problems with request state - modified during saving. - - """ - # This is the content language and has nothing to do with - # The user interface language. The content language can change - # during the rendering of a page by lang macros - self.current_lang = self.cfg.language_default - - self._all_pages = None - # caches unique ids - self._page_ids = {} - # keeps track of pagename/heading combinations - # parsers should use this dict and not a local one, so that - # macros like TableOfContents in combination with Include - # can work - self._page_headings = {} - - if hasattr(self, "_fmt_hd_counters"): - del self._fmt_hd_counters - - def loadTheme(self, theme_name): - """ Load the Theme to use for this request. - - @param theme_name: the name of the theme - @type theme_name: str - @rtype: int - @return: success code - 0 on success - 1 if user theme could not be loaded, - 2 if a hard fallback to modern theme was required. - """ - fallback = 0 - if theme_name == "": - theme_name = self.cfg.theme_default - - try: - Theme = wikiutil.importPlugin(self.cfg, 'theme', theme_name, - 'Theme') - except wikiutil.PluginMissingError: - fallback = 1 - try: - Theme = wikiutil.importPlugin(self.cfg, 'theme', - self.cfg.theme_default, 'Theme') - except wikiutil.PluginMissingError: - fallback = 2 - from MoinMoin.theme.modern import Theme - - self.theme = Theme(self) - return fallback - - def setContentLanguage(self, lang): - """ Set the content language, used for the content div - - Actions that generate content in the user language, like search, - should set the content direction to the user language before they - call send_title! - """ - self.content_lang = lang - self.current_lang = lang - - def getPragma(self, key, defval=None): - """ Query a pragma value (#pragma processing instruction) - - Keys are not case-sensitive. - """ - return self.pragma.get(key.lower(), defval) - - def setPragma(self, key, value): - """ Set a pragma value (#pragma processing instruction) - - Keys are not case-sensitive. - """ - self.pragma[key.lower()] = value - - def getPathinfo(self): - """ Return the remaining part of the URL. """ - return self.path_info - - def getScriptname(self): - """ Return the scriptname part of the URL ('/path/to/my.cgi'). """ - if self.script_name == '/': - return '' - return self.script_name - - def getPageNameFromQueryString(self): - """ Try to get pagename from the query string - - Support urls like http://netloc/script/?page_name. Allow - solving path_info encoding problems by calling with the page - name as a query. - """ - pagename = wikiutil.url_unquote(self.query_string, want_unicode=False) - pagename = self.decodePagename(pagename) - pagename = self.normalizePagename(pagename) - return pagename - - def getKnownActions(self): - """ Create a dict of avaiable actions - - Return cached version if avaiable. - - @rtype: dict - @return: dict of all known actions - """ - try: - self.cfg._known_actions # check - except AttributeError: - from MoinMoin import wikiaction - # Add built in actions from wikiaction - actions = [name[3:] for name in wikiaction.__dict__ - if name.startswith('do_')] - - # Add plugins - dummy, plugins = wikiaction.getPlugins(self) - actions.extend(plugins) - - # Add extensions - from MoinMoin.action import extension_actions - actions.extend(extension_actions) - - # TODO: Use set when we require Python 2.3 - actions = dict(zip(actions, [''] * len(actions))) - self.cfg._known_actions = actions - - # Return a copy, so clients will not change the dict. - return self.cfg._known_actions.copy() - - def getAvailableActions(self, page): - """ Get list of avaiable actions for this request - - The dict does not contain actions that starts with lower - case. Themes use this dict to display the actions to the user. - - @param page: current page, Page object - @rtype: dict - @return: dict of avaiable actions - """ - if self._available_actions is None: - # Add actions for existing pages only, including deleted pages. - # Fix *OnNonExistingPage bugs. - if not (page.exists(includeDeleted=1) and - self.user.may.read(page.page_name)): - return [] - - # Filter non ui actions (starts with lower case letter) - actions = self.getKnownActions() - for key in actions.keys(): - if key[0].islower(): - del actions[key] - - # Filter wiki excluded actions - for key in self.cfg.actions_excluded: - if key in actions: - del actions[key] - - # Filter actions by page type, acl and user state - excluded = [] - if ((page.isUnderlayPage() and not page.isStandardPage()) or - not self.user.may.write(page.page_name) or - not self.user.may.delete(page.page_name)): - # Prevent modification of underlay only pages, or pages - # the user can't write and can't delete - excluded = [u'RenamePage', u'DeletePage',] # AttachFile must NOT be here! - for key in excluded: - if key in actions: - del actions[key] - - self._available_actions = actions - - # Return a copy, so clients will not change the dict. - return self._available_actions.copy() - - def redirectedOutput(self, function, *args, **kw): - """ Redirect output during function, return redirected output """ - buffer = StringIO.StringIO() - self.redirect(buffer) - try: - function(*args, **kw) - finally: - self.redirect() - text = buffer.getvalue() - buffer.close() - return text - - def redirect(self, file=None): - """ Redirect output to file, or restore saved output """ - if file: - self.writestack.append(self.write) - self.write = file.write - else: - self.write = self.writestack.pop() - - def reset_output(self): - """ restore default output method - destroy output stack - (useful for error messages) - """ - if self.writestack: - self.write = self.writestack[0] - self.writestack = [] - - def log(self, msg): - """ Log to stderr, which may be error.log """ - msg = msg.strip() - # Encode unicode msg - if isinstance(msg, unicode): - msg = msg.encode(config.charset) - # Add time stamp - msg = '[%s] %s\n' % (time.asctime(), msg) - sys.stderr.write(msg) - - def write(self, *data): - """ Write to output stream. - """ - raise NotImplementedError - - def encode(self, data): - """ encode data (can be both unicode strings and strings), - preparing for a single write() - """ - wd = [] - for d in data: - try: - if isinstance(d, unicode): - # if we are REALLY sure, we can use "strict" - d = d.encode(config.charset, 'replace') - wd.append(d) - except UnicodeError: - print >>sys.stderr, "Unicode error on: %s" % repr(d) - return ''.join(wd) - - def decodePagename(self, name): - """ Decode path, possibly using non ascii characters - - Does not change the name, only decode to Unicode. - - First split the path to pages, then decode each one. This enables - us to decode one page using config.charset and another using - utf-8. This situation happens when you try to add to a name of - an existing page. - - See http://www.w3.org/TR/REC-html40/appendix/notes.html#h-B.2.1 - - @param name: page name, string - @rtype: unicode - @return decoded page name - """ - # Split to pages and decode each one - pages = name.split('/') - decoded = [] - for page in pages: - # Recode from utf-8 into config charset. If the path - # contains user typed parts, they are encoded using 'utf-8'. - if config.charset != 'utf-8': - try: - page = unicode(page, 'utf-8', 'strict') - # Fit data into config.charset, replacing what won't - # fit. Better have few "?" in the name than crash. - page = page.encode(config.charset, 'replace') - except UnicodeError: - pass - - # Decode from config.charset, replacing what can't be decoded. - page = unicode(page, config.charset, 'replace') - decoded.append(page) - - # Assemble decoded parts - name = u'/'.join(decoded) - return name - - def normalizePagename(self, name): - """ Normalize page name - - Convert '_' to spaces - allows using nice URLs with spaces, with no - need to quote. - - Prevent creating page names with invisible characters or funny - whitespace that might confuse the users or abuse the wiki, or - just does not make sense. - - Restrict even more group pages, so they can be used inside acl - lines. - - @param name: page name, unicode - @rtype: unicode - @return: decoded and sanitized page name - """ - # Replace underscores with spaces - name = name.replace(u'_', u' ') - - # Strip invalid characters - name = config.page_invalid_chars_regex.sub(u'', name) - - # Split to pages and normalize each one - pages = name.split(u'/') - normalized = [] - for page in pages: - # Ignore empty or whitespace only pages - if not page or page.isspace(): - continue - - # Cleanup group pages. - # Strip non alpha numeric characters, keep white space - if wikiutil.isGroupPage(self, page): - page = u''.join([c for c in page - if c.isalnum() or c.isspace()]) - - # Normalize white space. Each name can contain multiple - # words separated with only one space. Split handle all - # 30 unicode spaces (isspace() == True) - page = u' '.join(page.split()) - - normalized.append(page) - - # Assemble components into full pagename - name = u'/'.join(normalized) - return name - - def read(self, n): - """ Read n bytes from input stream. - """ - raise NotImplementedError - - def flush(self): - """ Flush output stream. - """ - raise NotImplementedError - - def check_spider(self): - """ check if the user agent for current request is a spider/bot """ - isSpider = False - spiders = self.cfg.ua_spiders - if spiders: - ua = self.getUserAgent() - if ua: - isSpider = re.search(spiders, ua, re.I) is not None - return isSpider - - def isForbidden(self): - """ check for web spiders and refuse anything except viewing """ - forbidden = 0 - # we do not have a parsed query string here, so we can just do simple matching - qs = self.query_string - if ((qs != '' or self.request_method != 'GET') and - not 'action=rss_rc' in qs and - # allow spiders to get attachments and do 'show' - not ('action=AttachFile' in qs and 'do=get' in qs) and - not 'action=show' in qs - ): - forbidden = self.isSpiderAgent - - if not forbidden and self.cfg.hosts_deny: - ip = self.remote_addr - for host in self.cfg.hosts_deny: - if host[-1] == '.' and ip.startswith(host): - forbidden = 1 - #self.log("hosts_deny (net): %s" % str(forbidden)) - break - if ip == host: - forbidden = 1 - #self.log("hosts_deny (ip): %s" % str(forbidden)) - break - return forbidden - - def setup_args(self, form=None): - """ Return args dict - - In POST request, invoke _setup_args_from_cgi_form to handle - possible file uploads. For other request simply parse the query - string. - - Warning: calling with a form might fail, depending on the type - of the request! Only the request know which kind of form it can - handle. - - TODO: The form argument should be removed in 1.5. - """ - if form is not None or self.request_method == 'POST': - return self._setup_args_from_cgi_form(form) - args = cgi.parse_qs(self.query_string, keep_blank_values=1) - return self.decodeArgs(args) - - def _setup_args_from_cgi_form(self, form=None): - """ Return args dict from a FieldStorage - - Create the args from a standard cgi.FieldStorage or from given - form. Each key contain a list of values. - - @param form: a cgi.FieldStorage - @rtype: dict - @return: dict with form keys, each contains a list of values - """ - if form is None: - form = cgi.FieldStorage() - - args = {} - for key in form: - values = form[key] - if not isinstance(values, list): - values = [values] - fixedResult = [] - for item in values: - fixedResult.append(item.value) - if isinstance(item, cgi.FieldStorage) and item.filename: - # Save upload file name in a separate key - args[key + '__filename__'] = item.filename - args[key] = fixedResult - - return self.decodeArgs(args) - - def decodeArgs(self, args): - """ Decode args dict - - Decoding is done in a separate path because it is reused by - other methods and sub classes. - """ - decode = wikiutil.decodeUserInput - result = {} - for key in args: - if key + '__filename__' in args: - # Copy file data as is - result[key] = args[key] - elif key.endswith('__filename__'): - result[key] = decode(args[key], self.decode_charsets) - else: - result[key] = [decode(value, self.decode_charsets) - for value in args[key]] - return result - - def getBaseURL(self): - """ Return a fully qualified URL to this script. """ - return self.getQualifiedURL(self.getScriptname()) - - def getQualifiedURL(self, uri=''): - """ Return an absolute URL starting with schema and host. - - Already qualified urls are returned unchanged. - - @param uri: server rooted uri e.g /scriptname/pagename. It - must start with a slash. Must be ascii and url encoded. - """ - import urlparse - scheme = urlparse.urlparse(uri)[0] - if scheme: - return uri - - scheme = ('http', 'https')[self.is_ssl] - result = "%s://%s%s" % (scheme, self.http_host, uri) - - # This might break qualified urls in redirects! - # e.g. mapping 'http://netloc' -> '/' - return wikiutil.mapURL(self, result) - - def getUserAgent(self): - """ Get the user agent. """ - return self.http_user_agent - - def makeForbidden(self, resultcode, msg): - statusmsg = { - 403: 'FORBIDDEN', - 503: 'Service unavailable', - } - self.http_headers([ - 'Status: %d %s' % (resultcode, statusmsg[resultcode]), - 'Content-Type: text/plain' - ]) - self.write(msg) - self.setResponseCode(resultcode) - self.forbidden = True - - def makeForbidden403(self): - self.makeForbidden(403, 'You are not allowed to access this!\r\n') - - def makeUnavailable503(self): - self.makeForbidden(503, "Warning:\r\n" - "You triggered the wiki's surge protection by doing too many requests in a short time.\r\n" - "Please make a short break reading the stuff you already got.\r\n" - "When you restart doing requests AFTER that, slow down or you might get locked out for a longer time!\r\n") - - def initTheme(self): - """ Set theme - forced theme, user theme or wiki default """ - if self.cfg.theme_force: - theme_name = self.cfg.theme_default - #### DEBUT HACK : Utilisation d'un thème différent pour www.crans.org - if self.remote_addr in self.cfg.ip_theme.keys(): - theme_name = self.cfg.ip_theme[self.remote_addr] - #### FIN DU HACK - else: - theme_name = self.user.theme_name - self.loadTheme(theme_name) - - def run(self): - # Exit now if __init__ failed or request is forbidden - if self.failed or self.forbidden: - #Don't sleep()! Seems to bind too much resources, so twisted will - #run out of threads, files, whatever (with low CPU load) and stop - #serving requests. - #if self.forbidden: - # time.sleep(10) # let the sucker wait! - return self.finish() - - self.open_logs() - _ = self.getText - self.clock.start('run') - - # Imports - from MoinMoin.Page import Page - - if self.query_string == 'action=xmlrpc': - from MoinMoin.wikirpc import xmlrpc - xmlrpc(self) - return self.finish() - - if self.query_string == 'action=xmlrpc2': - from MoinMoin.wikirpc import xmlrpc2 - xmlrpc2(self) - return self.finish() - - # parse request data - try: - self.initTheme() - - # MOVED: moved to __init__() for auth module being able to use it - #self.args = self.setup_args() - #self.form = self.args - - action = self.form.get('action',[None])[0] - - # Get pagename - # The last component in path_info is the page name, if any - path = self.getPathinfo() - if path.startswith('/'): - pagename = self.normalizePagename(path) - else: - pagename = None - - # Handle request. We have these options: - - # 1. If user has a bad user name, delete its bad cookie and - # send him to UserPreferences to make a new account. - if not user.isValidName(self, self.user.name): - msg = _("""Invalid user name {{{'%s'}}}. -Name may contain any Unicode alpha numeric character, with optional one -space between words. Group page name is not allowed.""") % self.user.name - self.user = self.get_user_default_unknown(name=self.user.name, logout=True) - page = wikiutil.getSysPage(self, 'UserPreferences') - page.send_page(self, msg=msg) - - # 2. Or jump to page where user left off - elif not pagename and not action and self.user.remember_last_visit: - pagetrail = self.user.getTrail() - if pagetrail: - # Redirect to last page visited - if ":" in pagetrail[-1]: - wikitag, wikiurl, wikitail, error = wikiutil.resolve_wiki(self, pagetrail[-1]) - url = wikiurl + wikiutil.quoteWikinameURL(wikitail) - else: - url = Page(self, pagetrail[-1]).url(self) - else: - # Or to localized FrontPage - url = wikiutil.getFrontPage(self).url(self) - self.http_redirect(url) - return self.finish() - - # 3. Or save drawing - elif (self.form.has_key('filepath') and - self.form.has_key('noredirect')): - # looks like user wants to save a drawing - from MoinMoin.action.AttachFile import execute - # TODO: what if pagename is None? - execute(pagename, self) - raise MoinMoinNoFooter - - # 4. Or handle action - elif action: - # Use localized FrontPage if pagename is empty - if not pagename: - self.page = wikiutil.getFrontPage(self) - else: - self.page = Page(self, pagename) - - # Complain about unknown actions - if not action in self.getKnownActions(): - self.http_headers() - self.write(u'

Unknown action %s

' % wikiutil.escape(action)) - - # Disallow non available actions - elif (action[0].isupper() and - not action in self.getAvailableActions(self.page)): - # Send page with error - msg = _("You are not allowed to do %s on this page.") % wikiutil.escape(action) - if not self.user.valid: - # Suggest non valid user to login - msg += _(" %s and try again.", formatted=0) % _('Login') # XXX merge into 1 string after 1.5.3 release - self.page.send_page(self, msg=msg) - - # Try action - else: - from MoinMoin.wikiaction import getHandler - handler = getHandler(self, action) - handler(self.page.page_name, self) - - # 5. Or redirect to another page - elif self.form.has_key('goto'): - self.http_redirect(Page(self, self.form['goto'][0]).url(self)) - return self.finish() - - # 6. Or (at last) visit pagename - else: - if not pagename and self.query_string: - pagename = self.getPageNameFromQueryString() - # pagename could be empty after normalization e.g. '///' -> '' - if not pagename: - pagename = wikiutil.getFrontPage(self).page_name - - # Visit pagename - self.page = Page(self, pagename) - self.page.send_page(self, count_hit=1) - - # generate page footer (actions that do not want this footer - # use raise util.MoinMoinNoFooter to break out of the - # default execution path, see the "except MoinMoinNoFooter" - # below) - - self.clock.stop('run') - self.clock.stop('total') - - # Close html code - if not self.no_closing_html_code: - if (self.cfg.show_timings and - self.form.get('action', [None])[0] != 'print'): - self.write('
    \n') - for t in self.clock.dump(): - self.write('
  • %s
  • \n' % t) - self.write('
\n') - #self.write('' % repr(self.user.auth_method)) - self.write('\n\n\n') - - except MoinMoinNoFooter: - pass - except Exception, err: - self.fail(err) - - return self.finish() - - def http_redirect(self, url): - """ Redirect to a fully qualified, or server-rooted URL - - @param url: relative or absolute url, ascii using url encoding. - """ - url = self.getQualifiedURL(url) - - #### DEBUT HACK : pour le www, on redirige vers du www - if self.remote_addr in self.cfg.ip_url_replace.keys(): - url = url.replace(self.cfg.ip_url_replace[self.remote_addr][0],self.cfg.ip_url_replace[self.remote_addr][1]) - #### FIN DU HACK - - self.http_headers(["Status: 302 Found", "Location: %s" % url]) - - def setHttpHeader(self, header): - """ Save header for later send. """ - self.user_headers.append(header) - - def setResponseCode(self, code, message=None): - pass - - def fail(self, err): - """ Fail when we can't continue - - Send 500 status code with the error name. Reference: - http://www.w3.org/Protocols/rfc2616/rfc2616-sec6.html#sec6.1.1 - - Log the error, then let failure module handle it. - - @param err: Exception instance or subclass. - """ - self.failed = 1 # save state for self.run() - self.http_headers(['Status: 500 MoinMoin Internal Error']) - self.setResponseCode(500) - self.log('%s: %s' % (err.__class__.__name__, str(err))) - from MoinMoin import failure - failure.handle(self) - - def open_logs(self): - pass - - def makeUniqueID(self, base): - """ - Generates a unique ID using a given base name. Appends a - running count to the base. - - @param base: the base of the id - @type base: unicode - - @returns: an unique id - @rtype: unicode - """ - if not isinstance(base, unicode): - base = unicode(str(base), 'ascii', 'ignore') - count = self._page_ids.get(base, -1) + 1 - self._page_ids[base] = count - if count == 0: - return base - return u'%s_%04d' % (base, count) - - def httpDate(self, when=None, rfc='1123'): - """ Returns http date string, according to rfc2068 - - See http://www.cse.ohio-state.edu/cgi-bin/rfc/rfc2068.html#sec-3.3 - - A http 1.1 server should use only rfc1123 date, but cookie's - "expires" field should use the older obsolete rfc850 date. - - Note: we can not use strftime() because that honors the locale - and rfc2822 requires english day and month names. - - We can not use email.Utils.formatdate because it formats the - zone as '-0000' instead of 'GMT', and creates only rfc1123 - dates. This is a modified version of email.Utils.formatdate - from Python 2.4. - - @param when: seconds from epoch, as returned by time.time() - @param rfc: conform to rfc ('1123' or '850') - @rtype: string - @return: http date conforming to rfc1123 or rfc850 - """ - if when is None: - when = time.time() - now = time.gmtime(when) - month = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', - 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'][now.tm_mon - 1] - if rfc == '1123': - day = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'][now.tm_wday] - date = '%02d %s %04d' % (now.tm_mday, month, now.tm_year) - elif rfc == '850': - day = ["Monday", "Tuesday", "Wednesday", "Thursday", - "Friday", "Saturday", "Sunday"][now.tm_wday] - date = '%02d-%s-%s' % (now.tm_mday, month, str(now.tm_year)[-2:]) - else: - raise ValueError("Invalid rfc value: %s" % rfc) - - return '%s, %s %02d:%02d:%02d GMT' % (day, date, now.tm_hour, - now.tm_min, now.tm_sec) - - def disableHttpCaching(self): - """ Prevent caching of pages that should not be cached - - This is important to prevent caches break acl by providing one - user pages meant to be seen only by another user, when both users - share the same caching proxy. - """ - # Run only once - if hasattr(self, 'http_caching_disabled'): - return - self.http_caching_disabled = 1 - - # Set Cache control header for http 1.1 caches - # See http://www.cse.ohio-state.edu/cgi-bin/rfc/rfc2109.html#sec-4.2.3 - # and http://www.cse.ohio-state.edu/cgi-bin/rfc/rfc2068.html#sec-14.9 - self.setHttpHeader('Cache-Control: no-cache="set-cookie"') - self.setHttpHeader('Cache-Control: private') - self.setHttpHeader('Cache-Control: max-age=0') - - # Set Expires for http 1.0 caches (does not support Cache-Control) - yearago = time.time() - (3600 * 24 * 365) - self.setHttpHeader('Expires: %s' % self.httpDate(when=yearago)) - - # Set Pragma for http 1.0 caches - # See http://www.cse.ohio-state.edu/cgi-bin/rfc/rfc2068.html#sec-14.32 - self.setHttpHeader('Pragma: no-cache') - - def finish(self): - """ General cleanup on end of request - - Delete circular references - all object that we create using - self.name = class(self) - This helps Python to collect these objects and keep our - memory footprint lower - """ - try: - del self.user - del self.theme - del self.dicts - except: - pass - - # ------------------------------------------------------------------ - # Debug - - def debugEnvironment(self, env): - """ Environment debugging aid """ - # Keep this one name per line so its easy to comment stuff - names = [ -# 'http_accept_language', -# 'http_host', -# 'http_referer', -# 'http_user_agent', -# 'is_ssl', - 'path_info', - 'query_string', -# 'remote_addr', - 'request_method', -# 'request_uri', -# 'saved_cookie', - 'script_name', -# 'server_name', -# 'server_port', - ] - names.sort() - attributes = [] - for name in names: - attributes.append(' %s = %r\n' % (name, - getattr(self, name, None))) - attributes = ''.join(attributes) - - environment = [] - names = env.keys() - names.sort() - for key in names: - environment.append(' %s = %r\n' % (key, env[key])) - environment = ''.join(environment) - - data = '\nRequest Attributes\n%s\nEnviroment\n%s' % (attributes, - environment) - f = open('/tmp/env.log','a') - try: - f.write(data) - finally: - f.close() - - -# CGI --------------------------------------------------------------- - -class RequestCGI(RequestBase): - """ specialized on CGI requests """ - - def __init__(self, properties={}): - try: - # force input/output to binary - if sys.platform == "win32": - import msvcrt - msvcrt.setmode(sys.stdin.fileno(), os.O_BINARY) - msvcrt.setmode(sys.stdout.fileno(), os.O_BINARY) - - self._setup_vars_from_std_env(os.environ) - RequestBase.__init__(self, properties) - - except Exception, err: - self.fail(err) - - def open_logs(self): - # create log file for catching stderr output - if not self.opened_logs: - sys.stderr = open(os.path.join(self.cfg.data_dir, 'error.log'), 'at') - self.opened_logs = 1 - - def read(self, n=None): - """ Read from input stream. - """ - if n is None: - return sys.stdin.read() - else: - return sys.stdin.read(n) - - def write(self, *data): - """ Write to output stream. - """ - sys.stdout.write(self.encode(data)) - - def flush(self): - sys.stdout.flush() - - def finish(self): - RequestBase.finish(self) - # flush the output, ignore errors caused by the user closing the socket - try: - sys.stdout.flush() - except IOError, ex: - import errno - if ex.errno != errno.EPIPE: raise - - # Headers ---------------------------------------------------------- - - def http_headers(self, more_headers=[]): - # Send only once - if getattr(self, 'sent_headers', None): - return - - self.sent_headers = 1 - have_ct = 0 - - # send http headers - for header in more_headers + getattr(self, 'user_headers', []): - if header.lower().startswith("content-type:"): - # don't send content-type multiple times! - if have_ct: continue - have_ct = 1 - if type(header) is unicode: - header = header.encode('ascii') - self.write("%s\r\n" % header) - - if not have_ct: - self.write("Content-type: text/html;charset=%s\r\n" % config.charset) - - self.write('\r\n') - - #from pprint import pformat - #sys.stderr.write(pformat(more_headers)) - #sys.stderr.write(pformat(self.user_headers)) - - -# Twisted ----------------------------------------------------------- - -class RequestTwisted(RequestBase): - """ specialized on Twisted requests """ - - def __init__(self, twistedRequest, pagename, reactor, properties={}): - try: - self.twistd = twistedRequest - self.reactor = reactor - - # Copy headers - self.http_accept_language = self.twistd.getHeader('Accept-Language') - self.saved_cookie = self.twistd.getHeader('Cookie') - self.http_user_agent = self.twistd.getHeader('User-Agent') - - # Copy values from twisted request - self.server_protocol = self.twistd.clientproto - self.server_name = self.twistd.getRequestHostname().split(':')[0] - self.server_port = str(self.twistd.getHost()[2]) - self.is_ssl = self.twistd.isSecure() - self.path_info = '/' + '/'.join([pagename] + self.twistd.postpath) - self.request_method = self.twistd.method - self.remote_host = self.twistd.getClient() - self.remote_addr = self.twistd.getClientIP() - self.request_uri = self.twistd.uri - self.script_name = "/" + '/'.join(self.twistd.prepath[:-1]) - - # Values that need more work - self.query_string = self.splitURI(self.twistd.uri)[1] - self.setHttpReferer(self.twistd.getHeader('Referer')) - self.setHost() - self.setURL(self.twistd.getAllHeaders()) - - ##self.debugEnvironment(twistedRequest.getAllHeaders()) - - RequestBase.__init__(self, properties) - - except MoinMoinNoFooter: # might be triggered by http_redirect - self.http_headers() # send headers (important for sending MOIN_ID cookie) - self.finish() - - except Exception, err: - # Wrap err inside an internal error if needed - from MoinMoin import error - if isinstance(err, error.FatalError): - self.delayedError = err - else: - self.delayedError = error.InternalError(str(err)) - - def run(self): - """ Handle delayed errors then invoke base class run """ - if hasattr(self, 'delayedError'): - self.fail(self.delayedError) - return self.finish() - RequestBase.run(self) - - def setup_args(self, form=None): - """ Return args dict - - Twisted already parsed args, including __filename__ hacking, - but did not decoded the values. - """ - return self.decodeArgs(self.twistd.args) - - def read(self, n=None): - """ Read from input stream. - """ - # XXX why is that wrong?: - #rd = self.reactor.callFromThread(self.twistd.read) - - # XXX do we need self.reactor.callFromThread with that? - # XXX if yes, why doesn't it work? - self.twistd.content.seek(0, 0) - if n is None: - rd = self.twistd.content.read() - else: - rd = self.twistd.content.read(n) - #print "request.RequestTwisted.read: data=\n" + str(rd) - return rd - - def write(self, *data): - """ Write to output stream. - """ - #print "request.RequestTwisted.write: data=\n" + wd - self.reactor.callFromThread(self.twistd.write, self.encode(data)) - - def flush(self): - pass # XXX is there a flush in twisted? - - def finish(self): - RequestBase.finish(self) - self.reactor.callFromThread(self.twistd.finish) - - def open_logs(self): - return - # create log file for catching stderr output - if not self.opened_logs: - sys.stderr = open(os.path.join(self.cfg.data_dir, 'error.log'), 'at') - self.opened_logs = 1 - - # Headers ---------------------------------------------------------- - - def __setHttpHeader(self, header): - if type(header) is unicode: - header = header.encode('ascii') - key, value = header.split(':',1) - value = value.lstrip() - if key.lower() == 'set-cookie': - key, value = value.split('=',1) - self.twistd.addCookie(key, value) - else: - self.twistd.setHeader(key, value) - #print "request.RequestTwisted.setHttpHeader: %s" % header - - def http_headers(self, more_headers=[]): - if getattr(self, 'sent_headers', None): - return - self.sent_headers = 1 - have_ct = 0 - - # set http headers - for header in more_headers + getattr(self, 'user_headers', []): - if header.lower().startswith("content-type:"): - # don't send content-type multiple times! - if have_ct: continue - have_ct = 1 - self.__setHttpHeader(header) - - if not have_ct: - self.__setHttpHeader("Content-type: text/html;charset=%s" % config.charset) - - def http_redirect(self, url): - """ Redirect to a fully qualified, or server-rooted URL - - @param url: relative or absolute url, ascii using url encoding. - """ - url = self.getQualifiedURL(url) - self.twistd.redirect(url) - # calling finish here will send the rest of the data to the next - # request. leave the finish call to run() - #self.twistd.finish() - raise MoinMoinNoFooter - - def setResponseCode(self, code, message=None): - self.twistd.setResponseCode(code, message) - -# CLI ------------------------------------------------------------------ - -class RequestCLI(RequestBase): - """ specialized on command line interface and script requests """ - - def __init__(self, url='CLI', pagename='', properties={}): - self.saved_cookie = '' - self.path_info = '/' + pagename - self.query_string = '' - self.remote_addr = '127.0.0.1' - self.is_ssl = 0 - self.http_user_agent = 'CLI/Script' - self.url = url - self.request_method = 'GET' - self.request_uri = '/' + pagename # TODO check - self.http_host = 'localhost' - self.http_referer = '' - self.script_name = '.' - RequestBase.__init__(self, properties) - self.cfg.caching_formats = [] # don't spoil the cache - self.initTheme() # usually request.run() does this, but we don't use it - - def read(self, n=None): - """ Read from input stream. - """ - if n is None: - return sys.stdin.read() - else: - return sys.stdin.read(n) - - def write(self, *data): - """ Write to output stream. - """ - sys.stdout.write(self.encode(data)) - - def flush(self): - sys.stdout.flush() - - def finish(self): - RequestBase.finish(self) - # flush the output, ignore errors caused by the user closing the socket - try: - sys.stdout.flush() - except IOError, ex: - import errno - if ex.errno != errno.EPIPE: raise - - def isForbidden(self): - """ Nothing is forbidden """ - return 0 - - # Accessors -------------------------------------------------------- - - def getQualifiedURL(self, uri=None): - """ Return a full URL starting with schema and host - - TODO: does this create correct pages when you render wiki pages - within a cli request?! - """ - return uri - - # Headers ---------------------------------------------------------- - - def setHttpHeader(self, header): - pass - - def http_headers(self, more_headers=[]): - pass - - def http_redirect(self, url): - """ Redirect to a fully qualified, or server-rooted URL - - TODO: Does this work for rendering redirect pages? - """ - raise Exception("Redirect not supported for command line tools!") - - -# StandAlone Server ---------------------------------------------------- - -class RequestStandAlone(RequestBase): - """ - specialized on StandAlone Server (MoinMoin.server.standalone) requests - """ - script_name = '' - - def __init__(self, sa, properties={}): - """ - @param sa: stand alone server object - @param properties: ... - """ - try: - self.sareq = sa - self.wfile = sa.wfile - self.rfile = sa.rfile - self.headers = sa.headers - self.is_ssl = 0 - - # TODO: remove in 1.5 - #accept = [] - #for line in sa.headers.getallmatchingheaders('accept'): - # if line[:1] in string.whitespace: - # accept.append(line.strip()) - # else: - # accept = accept + line[7:].split(',') - # - #env['HTTP_ACCEPT'] = ','.join(accept) - - # Copy headers - self.http_accept_language = (sa.headers.getheader('accept-language') - or self.http_accept_language) - self.http_user_agent = sa.headers.getheader('user-agent', '') - co = filter(None, sa.headers.getheaders('cookie')) - self.saved_cookie = ', '.join(co) or '' - - # Copy rest from standalone request - self.server_name = sa.server.server_name - self.server_port = str(sa.server.server_port) - self.request_method = sa.command - self.request_uri = sa.path - self.remote_addr = sa.client_address[0] - - # Values that need more work - self.path_info, self.query_string = self.splitURI(sa.path) - self.setHttpReferer(sa.headers.getheader('referer')) - self.setHost(sa.headers.getheader('host')) - self.setURL(sa.headers) - - # TODO: remove in 1.5 - # from standalone script: - # XXX AUTH_TYPE - # XXX REMOTE_USER - # XXX REMOTE_IDENT - #env['PATH_TRANSLATED'] = uqrest #self.translate_path(uqrest) - #host = self.address_string() - #if host != self.client_address[0]: - # env['REMOTE_HOST'] = host - # env['SERVER_PROTOCOL'] = self.protocol_version - - ##self.debugEnvironment(sa.headers) - - RequestBase.__init__(self, properties) - - except Exception, err: - self.fail(err) - - def _setup_args_from_cgi_form(self, form=None): - """ Override to create standlone form """ - form = cgi.FieldStorage(self.rfile, - headers=self.headers, - environ={'REQUEST_METHOD': 'POST'}) - return RequestBase._setup_args_from_cgi_form(self, form) - - def read(self, n=None): - """ Read from input stream - - Since self.rfile.read() will block, content-length will be used - instead. - - TODO: test with n > content length, or when calling several times - with smaller n but total over content length. - """ - if n is None: - try: - n = int(self.headers.get('content-length')) - except (TypeError, ValueError): - import warnings - warnings.warn("calling request.read() when content-length is " - "not available will block") - return self.rfile.read() - return self.rfile.read(n) - - def write(self, *data): - """ Write to output stream. - """ - self.wfile.write(self.encode(data)) - - def flush(self): - self.wfile.flush() - - def finish(self): - RequestBase.finish(self) - self.wfile.flush() - - # Headers ---------------------------------------------------------- - - def http_headers(self, more_headers=[]): - if getattr(self, 'sent_headers', None): - return - - self.sent_headers = 1 - user_headers = getattr(self, 'user_headers', []) - - # check for status header and send it - our_status = 200 - for header in more_headers + user_headers: - if header.lower().startswith("status:"): - try: - our_status = int(header.split(':',1)[1].strip().split(" ", 1)[0]) - except: - pass - # there should be only one! - break - # send response - self.sareq.send_response(our_status) - - # send http headers - have_ct = 0 - for header in more_headers + user_headers: - if type(header) is unicode: - header = header.encode('ascii') - if header.lower().startswith("content-type:"): - # don't send content-type multiple times! - if have_ct: continue - have_ct = 1 - - self.write("%s\r\n" % header) - - if not have_ct: - self.write("Content-type: text/html;charset=%s\r\n" % config.charset) - - self.write('\r\n') - - #from pprint import pformat - #sys.stderr.write(pformat(more_headers)) - #sys.stderr.write(pformat(self.user_headers)) - -# mod_python/Apache ---------------------------------------------------- - -class RequestModPy(RequestBase): - """ specialized on mod_python requests """ - - def __init__(self, req): - """ Saves mod_pythons request and sets basic variables using - the req.subprocess_env, cause this provides a standard - way to access the values we need here. - - @param req: the mod_python request instance - """ - try: - # flags if headers sent out contained content-type or status - self._have_ct = 0 - self._have_status = 0 - - req.add_common_vars() - self.mpyreq = req - # some mod_python 2.7.X has no get method for table objects, - # so we make a real dict out of it first. - if not hasattr(req.subprocess_env,'get'): - env=dict(req.subprocess_env) - else: - env=req.subprocess_env - self._setup_vars_from_std_env(env) - RequestBase.__init__(self) - - except Exception, err: - self.fail(err) - - def fixURI(self, env): - """ Fix problems with script_name and path_info using - PythonOption directive to rewrite URI. - - This is needed when using Apache 1 or other server which does - not support adding custom headers per request. With mod_python we - can use the PythonOption directive: - - - PythonOption X-Moin-Location /url/to/mywiki/ - - - Note that *neither* script_name *nor* path_info can be trusted - when Moin is invoked as a mod_python handler with apache1, so we - must build both using request_uri and the provided PythonOption. - """ - # Be compatible with release 1.3.5 "Location" option - # TODO: Remove in later release, we should have one option only. - old_location = 'Location' - options_table = self.mpyreq.get_options() - if not hasattr(options_table, 'get'): - options = dict(options_table) - else: - options = options_table - location = options.get(self.moin_location) or options.get(old_location) - if location: - env[self.moin_location] = location - # Try to recreate script_name and path_info from request_uri. - import urlparse - scriptAndPath = urlparse.urlparse(self.request_uri)[2] - self.script_name = location.rstrip('/') - path = scriptAndPath.replace(self.script_name, '', 1) - self.path_info = wikiutil.url_unquote(path, want_unicode=False) - - RequestBase.fixURI(self, env) - - def _setup_args_from_cgi_form(self, form=None): - """ Override to use mod_python.util.FieldStorage - - Its little different from cgi.FieldStorage, so we need to - duplicate the conversion code. - """ - from mod_python import util - if form is None: - form = util.FieldStorage(self.mpyreq) - - args = {} - for key in form.keys(): - values = form[key] - if not isinstance(values, list): - values = [values] - fixedResult = [] - - for item in values: - # Remember filenames with a name hack - if hasattr(item, 'filename') and item.filename: - args[key + '__filename__'] = item.filename - # mod_python 2.7 might return strings instead of Field - # objects. - if hasattr(item, 'value'): - item = item.value - fixedResult.append(item) - args[key] = fixedResult - - return self.decodeArgs(args) - - def run(self, req): - """ mod_python calls this with its request object. We don't - need it cause its already passed to __init__. So ignore - it and just return RequestBase.run. - - @param req: the mod_python request instance - """ - return RequestBase.run(self) - - def read(self, n=None): - """ Read from input stream. - """ - if n is None: - return self.mpyreq.read() - else: - return self.mpyreq.read(n) - - def write(self, *data): - """ Write to output stream. - """ - self.mpyreq.write(self.encode(data)) - - def flush(self): - """ We can't flush it, so do nothing. - """ - pass - - def finish(self): - """ Just return apache.OK. Status is set in req.status. - """ - RequestBase.finish(self) - # is it possible that we need to return something else here? - from mod_python import apache - return apache.OK - - # Headers ---------------------------------------------------------- - - def setHttpHeader(self, header): - """ Filters out content-type and status to set them directly - in the mod_python request. Rest is put into the headers_out - member of the mod_python request. - - @param header: string, containing valid HTTP header. - """ - if type(header) is unicode: - header = header.encode('ascii') - key, value = header.split(':',1) - value = value.lstrip() - if key.lower() == 'content-type': - # save content-type for http_headers - if not self._have_ct: - # we only use the first content-type! - self.mpyreq.content_type = value - self._have_ct = 1 - elif key.lower() == 'status': - # save status for finish - try: - self.mpyreq.status = int(value.split(' ',1)[0]) - except: - pass - else: - self._have_status = 1 - else: - # this is a header we sent out - self.mpyreq.headers_out[key]=value - - def http_headers(self, more_headers=[]): - """ Sends out headers and possibly sets default content-type - and status. - - @param more_headers: list of strings, defaults to [] - """ - for header in more_headers + getattr(self, 'user_headers', []): - self.setHttpHeader(header) - # if we don't had an content-type header, set text/html - if self._have_ct == 0: - self.mpyreq.content_type = "text/html;charset=%s" % config.charset - # if we don't had a status header, set 200 - if self._have_status == 0: - self.mpyreq.status = 200 - # this is for mod_python 2.7.X, for 3.X it's a NOP - self.mpyreq.send_http_header() - -# FastCGI ----------------------------------------------------------- - -class RequestFastCGI(RequestBase): - """ specialized on FastCGI requests """ - - def __init__(self, fcgRequest, env, form, properties={}): - """ Initializes variables from FastCGI environment and saves - FastCGI request and form for further use. - - @param fcgRequest: the FastCGI request instance. - @param env: environment passed by FastCGI. - @param form: FieldStorage passed by FastCGI. - """ - try: - self.fcgreq = fcgRequest - self.fcgenv = env - self.fcgform = form - self._setup_vars_from_std_env(env) - RequestBase.__init__(self, properties) - - except Exception, err: - self.fail(err) - - def _setup_args_from_cgi_form(self, form=None): - """ Override to use FastCGI form """ - if form is None: - form = self.fcgform - return RequestBase._setup_args_from_cgi_form(self, form) - - def read(self, n=None): - """ Read from input stream. - """ - if n is None: - return self.fcgreq.stdin.read() - else: - return self.fcgreq.stdin.read(n) - - def write(self, *data): - """ Write to output stream. - """ - self.fcgreq.out.write(self.encode(data)) - - def flush(self): - """ Flush output stream. - """ - self.fcgreq.flush_out() - - def finish(self): - """ Call finish method of FastCGI request to finish handling - of this request. - """ - RequestBase.finish(self) - self.fcgreq.finish() - - # Headers ---------------------------------------------------------- - - def http_headers(self, more_headers=[]): - """ Send out HTTP headers. Possibly set a default content-type. - """ - if getattr(self, 'sent_headers', None): - return - self.sent_headers = 1 - have_ct = 0 - - # send http headers - for header in more_headers + getattr(self, 'user_headers', []): - if type(header) is unicode: - header = header.encode('ascii') - if header.lower().startswith("content-type:"): - # don't send content-type multiple times! - if have_ct: continue - have_ct = 1 - self.write("%s\r\n" % header) - - if not have_ct: - self.write("Content-type: text/html;charset=%s\r\n" % config.charset) - - self.write('\r\n') - - #from pprint import pformat - #sys.stderr.write(pformat(more_headers)) - #sys.stderr.write(pformat(self.user_headers)) - -# WSGI -------------------------------------------------------------- - -class RequestWSGI(RequestBase): - def __init__(self, env): - try: - self.env = env - self.hasContentType = False - - self.stdin = env['wsgi.input'] - self.stdout = StringIO.StringIO() - - self.status = '200 OK' - self.headers = [] - - self._setup_vars_from_std_env(env) - RequestBase.__init__(self, {}) - - except Exception, err: - self.fail(err) - - def setup_args(self, form=None): - if form is None: - form = cgi.FieldStorage(fp=self.stdin, environ=self.env, keep_blank_values=1) - return self._setup_args_from_cgi_form(form) - - def read(self, n=None): - if n is None: - return self.stdin.read() - else: - return self.stdin.read(n) - - def write(self, *data): - self.stdout.write(self.encode(data)) - - def reset_output(self): - self.stdout = StringIO.StringIO() - - def setHttpHeader(self, header): - if type(header) is unicode: - header = header.encode('ascii') - - key, value = header.split(':', 1) - value = value.lstrip() - if key.lower() == 'content-type': - # save content-type for http_headers - if self.hasContentType: - # we only use the first content-type! - return - else: - self.hasContentType = True - - elif key.lower() == 'status': - # save status for finish - self.status = value - return - - self.headers.append((key, value)) - - def http_headers(self, more_headers=[]): - for header in more_headers: - self.setHttpHeader(header) - - if not self.hasContentType: - self.headers.insert(0, ('Content-Type', 'text/html;charset=%s' % config.charset)) - - def flush(self): - pass - - def finish(self): - pass - - def output(self): - return self.stdout.getvalue() - - diff --git a/wiki/static/blackliste/css/blackliste-clean.css b/wiki/static/blackliste/css/blackliste-clean.css deleted file mode 100644 index 52c18efa..00000000 --- a/wiki/static/blackliste/css/blackliste-clean.css +++ /dev/null @@ -1,17 +0,0 @@ -#wrapper { - width: 50em; - margin:0 auto; - padding:1em 2em 1em 5em; - text-align: left;} - #wrapper img#logo { - margin-left: -4em; - margin-bottom: 2em;} - -/**/ -p.creation { - margin-top: 5em; - border-top: 1px solid #6C7680; - font-style: italic; - color: gray; - padding: 10px 30px ; -} diff --git a/wiki/static/common/EventCalendar/EventCalendar.css b/wiki/static/common/EventCalendar/EventCalendar.css deleted file mode 100644 index 3398fe08..00000000 --- a/wiki/static/common/EventCalendar/EventCalendar.css +++ /dev/null @@ -1,452 +0,0 @@ -/* ======= for EventCalendar ========*/ - -TABLE.eventcalendar { - /* margin:auto; */ - background-color: #ffffff; -} - -TD.head_yearmonth { - border-width:0px; - text-align:center; - font-size: large; -} - -TD.head_weekday { - width:14%; - - border-style:solid; - border-width:1px; - border-color:#000000; - background-color: #ffeeee; - - font-weight:normal; - font-size:10pt; - text-align:center; -} - -TD.head_day { - line-height: 20px; - padding:0px; - margin:0px; - border-style:solid; - border-width:1px; - border-color:#000000; - border-bottom-width:0px; - /* background-color: #FFFFEE; */ - vertical-align: top; - font-weight:normal; - font-size:10pt; - text-align:left; -} - -TD.head_day_sunday { - line-height: 20px; - padding:0px; - margin:0px; - border-style:solid; - border-width:1px; - border-color:#000000; - border-bottom-width:0px; - /* background-color: #FFFFEE; */ - vertical-align: top; - font-weight:normal; - font-size:10pt; - color: #FF3300; - text-align:left; -} - -TD.head_day_today { - line-height: 20px; - padding:0px; - margin:0px; - border-style:solid; - border-width:1px; - border-color:#000000; - border-bottom-width:0px; - background-color: #FFFFAA; - vertical-align: top; - font-weight: bold; - font-size:10pt; - text-align:left; -} - -TD.head_day_nbmonth { - line-height: 20px; - padding:0px; - margin:0px; - border-style:solid; - border-width:1px; - border-color:#000000; - border-bottom-width:0px; - background-color: #eeeeee; - vertical-align: top; - font-weight:normal; - font-size:8pt; - text-align:left; - color: #999999; -} - -TD.cal_eventbox { - line-height: 11px; - padding: 1px 3px 1px 3px; - margin: 0px 0px 0px 0px; - - border-style:solid; - border-width:1px; - border-top-width:0px; - border-bottom-width:0px; - border-color:#000000; - - vertical-align: middle; - text-align: center; -} - -TABLE.cal_event { - width:100%; - - padding:0 0 0 0; - margin:0 0 0 0; - - border-width:0px; -} - -TD.cal_event { - border-style:solid; - border-width:1px; - border-color:#cccccc; - padding:3px; - margin:0px; - text-align:center; - color:#3266cd; - font-weight:normal; - font-size: 8pt; - display: block; - vertical-align: middle; -} - -TD.cal_event_append { - border-style:solid; - border-width:1px; - border-color:#cccccc; - border-left-width:0px; - padding:3px; - margin:0px; - text-align:center; - color:#3266cd; - font-weight:normal; - font-size: 8pt; - display: block; - vertical-align: middle; -} - -TD.cal_event_pending { - border-style:solid; - border-width:1px; - border-color:#cccccc; - border-right-width:0px; - padding:3px; - margin:0px; - text-align:center; - color:#3266cd; - font-weight:normal; - font-size: 8pt; - display: block; - vertical-align: middle; -} - -TD.cal_event_append_pending { - border-style:solid; - border-width:1px; - border-color:#cccccc; - border-left-width:0px; - border-right-width:0px; - padding:3px; - margin:0px; - text-align:center; - color:#3266cd; - font-weight:normal; - font-size: 8pt; - display: block; - vertical-align: middle; -} - -TD.cal_nbmonth { - border-top-width:0px; - border-bottom-width:0px; - border-color:#000000; - background-color: #eeeeee; - padding: 2px; - margin: 1px; -} - -TD.cal_noevent { - border-top-width:0px; - border-bottom-width:0px; - border-color:#000000; - padding: 2px; - margin: 1px; -} - -TD.cal_last_nbmonth { - border-top-width:0px; - border-bottom-width:1px; - border-color:#000000; - background-color: #eeeeee; - padding: 2px; - margin: 1px; -} - -TD.cal_last_noevent { - border-top-width:0px; - border-bottom-width:1px; - border-color:#000000; - padding: 2px; - margin: 1px; -} - - -TD.list_head { - border-width: 1px; - border-style: solid; - font-size: 11pt; - font-weight: bold; - background-color: #cccccc; -} - -TD.list_entry { - font-size: 10pt; - font-weight: normal; -} - -TD.head_dummy_nbmonth { - line-height: 5px; - border-top-width:0px; - border-bottom-width:0px; - border-color:#000000; - background-color: #eeeeee; - padding: 0px; - margin: 0px; -} - -TD.head_dummy { - line-height: 5px; - border-top-width:0px; - border-bottom-width:0px; - border-color:#000000; - padding: 0px; - margin: 0px; -} - -TABLE.eventcalendar_menubar { - /* margin:auto; */ -} - -TD.eventcalendar_menubar { - border-width: 0px; - /* text-align: left; */ - font-size: 9pt; -} - -TABLE.eventcalendar_msg { - /* margin:auto; */ -} - -TD.eventcalendar_msg { - background-color: #FFFF66; - border-width: 0px; - font-size: 9pt; - color: #990000; -} - -TABLE.simplecalendar { - /* margin:auto; */ -} - -TD.simple_nb { - line-height: 10px; - padding:0px; - margin:0px; - border-style:solid; - border-width:0px; - border-color:#000000; - vertical-align: middle; - font-weight:normal; - font-size:8pt; - text-align:center; -} - -TD.simple_event { - line-height: 20px; - padding:0px; - margin:0px; - border-style:solid; - border-width:1px; - border-color:#c0c0c0; - background-color: #eeffff; - vertical-align: middle; - font-weight:bold; - font-size:8pt; - text-align:center; -} - -TD.simple_noevent { - line-height: 20px; - padding:0px; - margin:0px; - border-style:solid; - border-width:1px; - border-color:#c0c0c0; - vertical-align: middle; - font-weight:normal; - color: #c0c0c0; - font-size:8pt; - text-align:center; -} - -TD.simple_event_today { - line-height: 20px; - padding:0px; - margin:0px; - border-style:solid; - border-width:2px; - border-color:#ff9999; - background-color: #eeffff; - vertical-align: middle; - font-weight:bold; - font-size:8pt; - text-align:center; -} - -TD.simple_noevent_today { - line-height: 20px; - padding:0px; - margin:0px; - border-style:solid; - border-width:2px; - border-color:#ff9999; - vertical-align: middle; - font-weight:normal; - color: #c0c0c0; - font-size:8pt; - text-align:center; -} - -TD.simple_yearmonth { - border-width:0px; - text-align:center; - font-size: 10pt; -} - -TD.simple_weekday { - width:14%; - - padding: 0 1px 0 1px; - margin: 0 1px 0 1px; - - border-width:0px; - /* background-color: #ffeeee; */ - - font-weight:bold; - font-size:8pt; - text-align:center; -} - -TD.cal_daily_noevent { - padding: 2px; - margin: 1px; - width: 96%; - border-style: dotted solid dotted solid; - border-top-color: #eeeeee; - border-bottom-color: #eeeeee; - border-left-color: #aaaaaa; - border-right-color: #aaaaaa; - border-top-width: 1px; - border-bottom-width: 1px; - line-height: 11px; -} - -TD.cal_eventbox_time { - width: 10px; - border-width: 0px; - padding: 0px; - margin: 0px; - text-align: left; - vertical-align: top; - font-size: 7pt; - color: #000000; -} - -TD.cal_eventbox_time_event { - border-width: 0px; - padding: 0px; - margin: 0px; - text-align: left; - vertical-align: top; - font-size: 8pt; -} - -TD.cal_daily_noevent { - padding: 2px; - margin: 1px; - width: 96%; - border-style: dotted solid dotted solid; - border-top-color: #eeeeee; - border-bottom-color: #eeeeee; - border-left-color: #aaaaaa; - border-right-color: #aaaaaa; - border-top-width: 1px; - border-bottom-width: 1px; - line-height: 11px; -} - -TD.cal_weekly_noevent { - padding: 2px; - margin: 1px; - width: 14%; - border-style: dotted solid dotted solid; - border-top-color: #eeeeee; - border-bottom-color: #eeeeee; - border-left-color: #aaaaaa; - border-right-color: #aaaaaa; - border-top-width: 0px; - border-bottom-width: 0px; - line-height: 11px; - -} - -TD.cal_blankeventbox { - border-style: dotted solid dotted solid; - border-top-color: #eeeeee; - border-bottom-color: #eeeeee; - border-left-color: #aaaaaa; - border-right-color: #aaaaaa; - border-top-width: 1px; - border-bottom-width: 1px; - line-height: 11px; -} - -TD.cal_weekly_eventbox { - border-width: 2px; - border-color: #000000; - vertical-align: top; - font-size: 9pt; -} - -TD.cal_weekly_eventbox2 { - border-style: dotted solid dotted solid; - border-top-color: #eeeeee; - border-bottom-color: #eeeeee; - border-left-color: #aaaaaa; - border-right-color: #aaaaaa; - border-top-width: 0px; - border-bottom-width: 0px; - line-height: 11px; -} - -TD.cal_hourhead { - line-height: 11px; - font-weight:normal; - font-size:10pt; - text-align:right; - vertical-align: top; -} diff --git a/wiki/static/common/boxes/boxes.css b/wiki/static/common/boxes/boxes.css deleted file mode 100644 index ad1968db..00000000 --- a/wiki/static/common/boxes/boxes.css +++ /dev/null @@ -1,103 +0,0 @@ -/************************************************************* - .. - .... ............ ........ - . ....... . .... .. - . ... .. .. .. .. ..... . .. - .. .. ....@@@. .. . ........ . - .. . .. ..@.@@..@@. .@@@@@@@ @@@@@@. .... - .@@@@. .@@@@. .@@@@..@@.@@..@@@..@@@..@@@@.... .... - @@@@... .@@@.. @@ @@ .@..@@..@@...@@@. .@@@@@. .. - .@@@.. . @@@. @@.@@..@@.@@..@@@ @@ .@@@@@@.. ..... - ...@@@.... @@@ .@@.......... ........ ..... .. - . ..@@@@.. . .@@@@. .. ....... . ............. - . .. .... .. .. . ... .... -. . .... ............. .. ... -.. .. ... ........ ... ... - ................................ - -============================================================== -boxes.css - MoinMoin Style - - Style pour les elements {{{#!box ...}}} - -Copyright (c) 2006 by www.crans.org - -**************************************************************/ -/* les boites */ - -/* Show only to IE PC \*/ -* html .boxhead h2 {height: 1%;} /* For IE 5 PC */ - - -.sidebox { - margin: 0 auto; /* center for now */ - padding:0; - font-size: 100%; - float:left; - max-width:600px; -} -.boxhead { - background: url(sbhead-l-orange.png) no-repeat top left; - margin: 0; - padding: 0 0 0 35px; - text-align: center; -} -.boxhead h3 { - background:transparent url(sbhead-r-orange.png) no-repeat top right; - border:none; - margin: 0; - padding: 22px 55px 5px 5px; - color: white; - font-weight: bold; - font-size: 1.2em; - line-height: 1em; - - /* Safari-only, but cool */ - text-shadow: black 0px 2px 5px ;/* valeur originale non valide : rgba(0,0,0,.4) 0px 2px 5px;*/ - - overflow:hidden; -} - -.boxbody1 { - background: url(sbbody-l.png) no-repeat bottom left; - padding: 0 0 0 42px; -} -.boxbody2 { - background: transparent url(sbbody-r.png) no-repeat bottom right; - margin: 0; - padding: 5px 50px 47px 0; - color:black; - -} - -.orange_box .boxhead {background-image: url(sbhead-l-orange.png);} -.orange_box .boxhead h4 {background-image: url(sbhead-r-orange.png);} - -.blue_box .boxhead {background-image: url(sbhead-l-blue.png);} -.blue_box .boxhead h3 {background-image: url(sbhead-r-blue.png);} - - -.black_box .boxhead {background-image: url(sbhead-l-black.png);} -.black_box .boxhead h3 {background-image: url(sbhead-r-black.png);} - - -.green_box .boxhead {background-image: url(sbhead-l-green.png);} -.green_box .boxhead h3 {background-image: url(sbhead-r-green.png);} - - -.red_box .boxhead {background-image: url(sbhead-l-red.png);} -.red_box .boxhead h3 {background-image: url(sbhead-r-red.png);} - - -.gray_box .boxhead {background-image: url(sbhead-l-gray.png);} -.gray_box .boxhead h3 {background-image: url(sbhead-r-gray.png);} - -/* on est oblige de mettre des clear aux titres pour respecter une certaine cohérence */ - -h2, h3, h4, h5, hr {clear:left;} - -hr { width:100%; } - -.visualclear, #bottom, #bottom_preview { - clear:both; -} diff --git a/wiki/static/common/pagesPersos.css b/wiki/static/common/pagesPersos.css deleted file mode 100644 index aad20b4b..00000000 --- a/wiki/static/common/pagesPersos.css +++ /dev/null @@ -1,43 +0,0 @@ -div.vignetteperso { - text-align: center; - height: 13em; - width: 15em; - border: 0px; - float: left; - padding: 10px; - overflow: visible; - font-size: 0.90em; -} - - -div.vignetteperso a { - display: table-cell; - vertical-align: middle; - height:100px; - width:15em; - text-align:center; -} - -/* redimentionnement proportionnel des images */ -div.vignetteperso img { - max-width:100px; - max-height:100px; - margin: auto auto auto auto; -} - -div.vignetteperso a.letter_anchor { - display: table-cell; - vertical-align: bottom; - height:1em; - padding:0; - line-height:1em; - font-size:8em; -} - -.letter_anchor span { - opacity:0.5; -} - -.alphabetic_index a{ - margin:3px; -} diff --git a/wiki/static/common/toc/toc.css b/wiki/static/common/toc/toc.css deleted file mode 100644 index 9aa39635..00000000 --- a/wiki/static/common/toc/toc.css +++ /dev/null @@ -1,60 +0,0 @@ -/************************************************************* - .. - .... ............ ........ - . ....... . .... .. - . ... .. .. .. .. ..... . .. - .. .. ....@@@. .. . ........ . - .. . .. ..@.@@..@@. .@@@@@@@ @@@@@@. .... - .@@@@. .@@@@. .@@@@..@@.@@..@@@..@@@..@@@@.... .... - @@@@... .@@@.. @@ @@ .@..@@..@@...@@@. .@@@@@. .. - .@@@.. . @@@. @@.@@..@@.@@..@@@ @@ .@@@@@@.. ..... - ...@@@.... @@@ .@@.......... ........ ..... .. - . ..@@@@.. . .@@@@. .. ....... . ............. - . .. .... .. .. . ... .... -. . .... ............. .. ... -.. .. ... ........ ... ... - ................................ - -============================================================== -toc.css - MoinMoin Style - - Style pour la table des matieres - -Copyright (c) 2006 by www.crans.org - -**************************************************************/ -/**/ -#tableOfContents, #tableOfContents p { - display:block; - } -#tableOfContents { - display:block; - float:left; - border: 1px solid #aaaaaa; - padding:5px; - background:#e9e9e9; - margin:20px; -} - -#tableOfContents ol { - margin:0; - padding:0 0 0 20px; -} -#tableOfContents ol li { - margin:2px; -} -#tableOfContents h2 { - border:none; - font-size:110%; - font-weight:bold; - padding:0; - margin:5px 0; - text-align:center; -} - -#tableOfContents span.toctoggle { - font-size:x-small; - font-weight:normal; -} - -.visualClear {clear:both;} diff --git a/wiki/static/common/toc/toc.js b/wiki/static/common/toc/toc.js deleted file mode 100644 index 2444cfe0..00000000 --- a/wiki/static/common/toc/toc.js +++ /dev/null @@ -1,62 +0,0 @@ -var TOCState = "visible" - -function replaceChildNodes(node/*, nodes...*/) { - var elem = document.getElementById(node); - elem.firstChild = "ee"; - return -}; - -function showTocToggle() { - if (document.createTextNode) { - // Uses DOM calls to avoid document.write + XHTML issues - - var linkHolder = document.getElementById('toctitle') - if (!linkHolder) - return; - - var outerSpan = document.createElement('span'); - outerSpan.className = 'toctoggle'; - - var toggleLink = document.createElement('a'); - toggleLink.id = 'togglelink'; - toggleLink.className = 'internal'; - toggleLink.href = 'javascript:toggleToc()'; - toggleLink.appendChild(document.createTextNode('masquer')); - - outerSpan.appendChild(document.createTextNode('[')); - outerSpan.appendChild(toggleLink); - outerSpan.appendChild(document.createTextNode(']')); - - linkHolder.appendChild(document.createTextNode(' ')); - linkHolder.appendChild(outerSpan); - - var cookiePos = document.cookie.indexOf("hidetoc="); - if (cookiePos > -1 && document.cookie.charAt(cookiePos + 8) == 1) - toggleToc(); - } -} - -function changeText(el, newText) { - // Safari work around - if (el.innerText) - el.innerText = newText; - else if (el.firstChild && el.firstChild.nodeValue) - el.firstChild.nodeValue = newText; -} - -function toggleToc() { - var toc = document.getElementById('tableOfContentsList'); - var toggleLink = document.getElementById('togglelink') - - if (toc && toggleLink && toc.style.display == 'none') { - changeText(toggleLink, 'masquer'); - toc.style.display = 'block'; - document.cookie = "hidetoc=0"; - } else { - changeText(toggleLink, 'afficher'); - toc.style.display = 'none'; - document.cookie = "hidetoc=1"; - } -} - -showTocToggle(); \ No newline at end of file diff --git a/wiki/static/crans-www/css/common.css b/wiki/static/crans-www/css/common.css deleted file mode 100644 index c04ba371..00000000 --- a/wiki/static/crans-www/css/common.css +++ /dev/null @@ -1,329 +0,0 @@ -/* common.css - MoinMoin Cr@ns style - - Le fichier gere l'affichage de tout ce qui concerne - le contenue wiki des pages. (= ce qui est modifiable - dans le wiki.) - - -*/ - -ul#pagelocation { - list-style-type:none; - padding:5px 10px 10px 10px; - margin:0; - float: left; - border:none; -} - - -ul#pagelocation li { - display:inline; -} - -ul#pagelocation li:before{ - content:"/"; -} - -ul#pagelocation + a { - vertical-align:middle; - height: 25px; - margin: 10px; - padding: 0; -} - -/* content styles */ - -html { - font-family: Arial, Lucida Grande, sans-serif; - font-size: 0.9em; - line-height: 1.25em; -} - -body { - color:#232323; -} -/* Links */ - -a {color: #361a31;} -a:visited {color: #361a31;} -a.nonexistent, a.badinterwiki {color: #484848;} - -/* Headings */ -div#maintitle { - padding: 0; - margin: -1.5em 300px 0 0; - font-size: 2.2em; - font-weight: bold; - line-height: 1.2em; - /* on souligne les titres - (un underline ne souligne que les lettres - alors qu'on veut un grand trait - */ - border:2px solid #232323; - border-style:none none solid none; - /* les titre trop grands : */ - overflow:auto; - -} - -ul#pagelocation a, ul#pagelocation a:visited { - text-decoration:none; - color: #232323; -} - -h1, h2, h3, h4, h5, h6 -{ - margin: 1em 0 0 0; - padding: 0; - line-height: 1.2em; -} - -h1, h2 a, h3 a, h4 a, h5 a, h6 a -{ - text-decoration:none; -} -h1 { - font-size: 1.6em; -} - -h2 {font-size: 1.3em;} -h3 {font-size: 1.1em;} -h4, h5, h6 {font-size: 1em;} - -li p { - margin: .25em 0; -} - -li.gap { - margin-top: 0.5em; -} - -dt { - margin-top: 0.5em; - font-weight: bold; -} - -dd { - margin-top: 0; - margin-bottom: 0; -} - -dd p { - margin: 0.25em 0; -} - -a, img, img.drawing { - border: 0; -} - -pre -{ - border: 1pt solid #AEBDCC; - background-color: #F3F5F7; - padding: 5pt; - font-family: courier, monospace; - white-space: pre; - /* begin css 3 or browser specific rules - do not remove! - see: http://forums.techguy.org/archive/index.php/t-249849.html */ -/* white-space: pre-wrap; - word-wrap: break-word; - white-space: -moz-pre-wrap; - white-space: -pre-wrap; - white-space: -o-pre-wrap; - /* end css 3 or browser specific rules */ -} - -table -{ - margin: 0.5em 0; - border-collapse: collapse; -} - -td -{ - padding: 0.25em; - border: 1pt solid #ADB9CC; -} - -td p { - margin: 0; - padding: 0; -} - -.footnotes div { - width: 5em; - border-top: 1pt solid gray; -} - -.footnotes ul { - padding: 0 2em; - margin: 0 0 1em; - list-style: none; -} - -.footnotes li { -} - -.info { - font-size: 0.85em; - color: gray; -} - -#pageinfo { - margin-top: 2em; -} - -.seperator { - color: gray; -} - -/* standard rule ---- */ -hr { - clear: both; - height: 1pt; - background-color: #232323; - border: 0; -} - -/* custom rules ----- to ---------- */ -.hr1 {height: 2pt;} -.hr2 {height: 3pt;} -.hr3 {height: 4pt;} -.hr4 {height: 5pt;} -.hr5 {height: 6pt;} -.hr6 {height: 7pt;} - -/* Replacement for html 3 u tag */ -.u {text-decoration: underline;} - -/* eye catchers */ -.warning -{ - color: red; -} - -.error -{ - color: red; -} - -strong.highlight -{ - background-color: #CCE0FF; - padding: 1pt; -} - - -/* Recent changes */ - -.rcrss { - float: right; - margin: 0; -} - -.recentchanges[dir="rtl"] .rcrss { - float: left; -} - -.recentchanges table { - clear: both; -} - -.recentchanges td { - vertical-align: top; - border: none; - border-bottom: 1pt solid #E6EAF0; - background: #F2F4F7; -} - -.rcdaybreak td { - background: #B8C5D9; - border: none; -} - -.rcdaybreak td a { - font-size: 0.88em; -} - -.rcicon1, .rcicon2 { - text-align: center; -} - -.rcpagelink { - width: 33%; -} - -.rctime { - font-size: 0.88em; - white-space: nowrap; -} - -.rceditor { - white-space: nowrap; - font-size: 0.88em; -} - -.rccomment { - width: 66%; - color: gray; - font-size: 0.88em; -} - - -/* User Preferences */ - -.userpref table, .userpref td { - border: none; -} - -/* CSS for new code_area markup used by Colorizer and ParserBase */ - -div.codearea { /* the div makes the border */ - margin: 0.5em 0; - padding: 0; - border: 1pt solid #AEBDCC; - background-color: #F3F5F7; - color: black; -} - -div.codearea pre { /* the pre has no border and is inside the div */ - margin: 0; - padding: 10pt; - border: none; -} - -a.codenumbers { /* format of the line numbering link */ - margin: 0 10pt; - font-size: 0.85em; - color: gray; -} - -/* format of certain syntax spans */ -div.codearea pre span.LineNumber {color: gray;} -div.codearea pre span.ID {color: #000000;} -div.codearea pre span.Operator {color: #0000C0;} -div.codearea pre span.Char {color: #004080;} -div.codearea pre span.Comment {color: #008000;} -div.codearea pre span.Number {color: #0080C0;} -div.codearea pre span.String {color: #004080;} -div.codearea pre span.SPChar {color: #0000C0;} -div.codearea pre span.ResWord {color: #A00000;} -div.codearea pre span.ConsWord {color: #008080; font-weight: bold;} -div.codearea pre span.Error {color: #FF8080; border: solid 1.5pt #FF0000;} -div.codearea pre span.ResWord2 {color: #0080ff; font-weight: bold;} -div.codearea pre span.Special {color: #0000ff;} -div.codearea pre span.Preprc {color: #803999;} - - -/* Search results */ - -.searchresults dt { - margin-top: 1em; - font-weight: normal; -} - -.searchresults dd { - font-size: 0.85em; -} - - diff --git a/wiki/static/crans-www/css/layout.css b/wiki/static/crans-www/css/layout.css deleted file mode 100644 index b4acb125..00000000 --- a/wiki/static/crans-www/css/layout.css +++ /dev/null @@ -1,163 +0,0 @@ -/* layout.css - MoinMoin Cr@ns style - - Le fichier gere la mise en page du site (fond, dispositions...) - -*/ - - -/**/ -body -{ - background:black url(../img/mainbg.gif) no-repeat top left; - position:relative; - padding:20px 60px; - margin:0; -} - -#logo { - position:relative; - top:-40px; - left:-70px; -} - -#globalWrapper { - width:100%; - min-width:660px; - max-width:1000px; - background:#ffb849 url(../img/divBg.jpg) no-repeat left top; - margin:5px auto; - padding:0; - position:relative; /* pour que les elements inclus se referent - a lui et pas a body */ -} - -#page { - padding:20px 20px 20px 20px; -} - -/**/ -div#MenuNavigation -{ - color:Black; - font:15px "Trebuchet MS", helvetica, sans-serif ; - z-index:5; - position: absolute; /* positionnement */ - right: 0; - top: 1px; - padding:0; - margin:0; - width:300px; - border-bottom: 1px solid #232323; - border-left: 1px solid #232323; - background: url(../img/translucide.png) repeat; - text-align:left; -} - -div#MenuNavigation ul { - display:block; - margin:0 auto; - padding:7px 0; - list-style-type:none; -} - -div#MenuNavigation ul li { - list-style-type:none; - z-index:5; - margin:5px; -} - -div#MenuNavigation ul li a, div#MenuNavigation form#searchform h5 { - display:inline; - z-index:5; - margin:0; - padding:1px; - border-left:1px solid transparent; - color:black; - font: 15px "Trebuchet MS", helvetica, sans-serif ; - text-decoration:none; - font-weight:bold; -} -div#MenuNavigation ul li a:hover { - border-color:black; -} - -div#MenuNavigation form#searchform { - float:right; - position:absolute; - top:0; - right:7px; - margin:10px; - padding:0; - color:#232323; - width:165px; - display:block; -} - -div#MenuNavigation form#searchform div { - margin-left:15px; -} - -div#MenuNavigation form#searchform input { - max-width:150px; -} - -/* */ -/* style pour les liens de connexion/preferences.... en haut a droite */ -#p-personal { - float:right; - position:absolute; - top:0; - right:0; -} - -#p-personal, #p-personal ul { - padding:0; - margin:0; - height:0.8em; -} - -#p-personal li { - list-style-type:none; - float:right; - margin:0 3px; -} - -#p-personal li a { - display:block; - font-weight:normal; - font-size:0.8em; - color:#aaa; -} - - -/* */ -/* style pour les badges en bas de la page */ - -ul.supportBadges { - list-style-type:none; - padding:0; - max-width:1000px; - margin:10px auto; -} - -ul.supportBadges li { - float:left; -} - - -ul.supportBadges li a { - margin-right:5px; - opacity:0.5; -} - -ul.supportBadges li a:hover { - opacity:1;; -} - -ul.supportBadges li a img { - border:none; -} - -ul#timings { - clear:left; -} diff --git a/wiki/static/crans-www/css/print.css b/wiki/static/crans-www/css/print.css deleted file mode 100644 index 68eae463..00000000 --- a/wiki/static/crans-www/css/print.css +++ /dev/null @@ -1,52 +0,0 @@ -/* print.css - MoinMoin Default Styles - -Copyright (c) 2001, 2002, 2003 by Juergen Hermann -*/ - -/* content styles */ - -html { - font-family: Times, serif; - font-size: 12pt; -} - -body { - /* Give about 3.4cm in Mozilla/Firefox and about 2.2cm in Safari */ - margin: 1.5cm; -} - -a, a:visited, a.nonexistent, a.badinterwiki { - color: black; - text-decoration: none; -} - -a:hover { - text-decoration: underline; -} - -pre { - font-size: 10pt; -} - -a.interwiki:before, a.badinterwiki:before { - content: attr(title) ":"; -} - -a.interwiki img, a.badinterwiki img { - display: none; -} - -.footnotes div { - width: 5em; - border-top: 1pt solid gray; -} - -/* user interface styles */ - -#header, #sidebar, #footer, #timings, #credits { - display: none; -} - -#MenuNavigation, #p-personal, #timings { - display:none; -} diff --git a/wiki/static/crans-www/css/projection.css b/wiki/static/crans-www/css/projection.css deleted file mode 100644 index fa27a3e0..00000000 --- a/wiki/static/crans-www/css/projection.css +++ /dev/null @@ -1,90 +0,0 @@ -/* projection.css - MoinMoin Slide Styles - -Copyright (c) 2003 by Juergen Hermann -*/ -@import url("monobook.css"); -@import url("screen.css"); - -html { line-height: 1.8em; } - -#page { - margin: 0; - padding: 0; - border: none; - z-index: 1; - padding-bottom: 1em; -} - -#content { - padding: 1em; -} - -body, b, em, a, span, div, p, td { font-size: 22pt; } - -h1 { - font-size: 16pt; - margin: 0; - background: #81BBF2; -} - -h2 { - font-size: 32pt; - margin-top: 0.5em; - padding-left: 1em; - padding-right: 1em; - border-bottom: 4px solid blue; -} - -h3 { font-size: 22pt; } -h4 { font-size: 20pt; } -h5 { font-size: 18pt; } -h6 { font-size: 16pt; } -tt,pre { font-size: 18pt; } -sup, sub { font-size: 14pt; } - - -#pageinfo { - display: none; -} - -#timings{ - display: none; -} - -#navigation { - position: fixed; - bottom: 0; - left: 0; - right: 0; - padding: 0; - border-top: 1px dotted #808080; - color: #808080; - font-size: 10pt; - z-index: 2; - background: White; -} - -#navigation ul { - margin: 8pt; - text-align: center; -} - -#navigation a { - text-decoration: none; -} - -#navigation li { - display: inline; - text-align: center; - margin: 0 2pt; - padding: 0; -} - -#navigation li.current { - border: 1pt solid #808080; - padding: 2pt 4pt; -} - -.codenumbers{ - display: None; -} diff --git a/wiki/static/crans-www/css/rtl.css b/wiki/static/crans-www/css/rtl.css deleted file mode 100644 index 314534ca..00000000 --- a/wiki/static/crans-www/css/rtl.css +++ /dev/null @@ -1,202 +0,0 @@ -/* -Right-to-left fixes for MonoBook. -Places sidebar on right, tweaks various alignment issues. - -Works mostly ok nicely on Safari 1.2.1; fine in Mozilla. - -Safari bugs (1.2.1): -* Tabs are still appearing in left-to-right order. (Try after localizing) - -Opera bugs (7.23 linux): -* Some bits of ltr text (sidebar box titles) have forward and backward versions overlapping each other - -IE/mac bugs: -* The thing barfs on Hebrew and Arabic anyway, so no point testing. - -Missing features due to lack of support: -* external link icons, icon next to user name - -To test: -* Opera6 -* IE 5.0 -* etc - -*/ -body, -body * { - direction: rtl; -/* unicode-bidi: bidi-override;*/ - unicode-bidi: embed; -} -#column-content { - margin: 0 -12.2em 0 0; - float: left; -} -#column-content #page{ - margin-left: 0; - margin-right: 12.2em; - border-right: 1px solid #aaaaaa; - border-left: none; -} -html>body .portlet { - float: right; - clear: right; -} -/* recover IEMac (might be fine with the float, but usually it's close to IE */ -*>body .portlet { - float: none; - clear: none; -} -.pBody { - padding-right: 0.8em; - padding-left: 0.5em; -} - -/* Fix alignment */ -.documentByLine, -.portletDetails, -.portletMore, -#p-personal { - text-align: left; -} - -div div.thumbcaption { - text-align: right; -} - -div.magnify, -#div.townBox, -#p-logo { - left: auto; - right: 0; -} -#p-personal { - left: auto; - right: 0; -} - -#p-cactions { - left: auto; - right: 11.5em; - padding-left: 0; - padding-right: 1em; -} -#p-cactions li { - margin-left: 0.3em; - margin-right: 0; - float: right; -} -* html #p-cactions li a { - display: block; - padding-bottom: 0; -} -* html #p-cactions li a:hover { - padding-bottom: 0.2em; -} -/* offsets to distinguish the tab groups */ -li#ca-talk { - margin-right: auto; - margin-left: 1.6em; -} -li#ca-watch,li#ca-unwatch { - margin-right: 1.6em !important; -} - -/* Fix margins */ -/* top right bottom left */ - -ul { - margin-left: 0; - margin-right: 1.5em; -} -ol { - margin-left: 0; - margin-right: 2.4em; -} -dd { - margin-left: 0; - margin-right: 1.6em; -} -#contentSub { - margin-right: 1em; - margin-left: 0; -} -.tocindent { - margin-left: 0; - margin-right: 2em; -} -div.tright { - clear: none; -} -div.tleft { - clear: left; -} -div.floatright, table.floatright { - clear: none; -} -div.floatleft, table.floatleft { - clear: left; -} -div.townBox { - margin-left: 0; - margin-right: 1em; -} -div.townBox dl dd { - margin-left: 0; - margin-right: 1.1em; -} -#p-personal li { - margin-left: 0; - margin-right: 1em; -} - -li#ca-talk, -li#ca-watch { - margin-right: auto; - margin-left: 1.6em; -} - -#p-personal li { - float: left; -} -/* Fix link icons */ -li#pt-userpage, -li#pt-anonuserpage, -li#pt-login { - background: none; - padding-left: 0; -} -.external { - padding: 0 !important; - background: none !important; -} -#footer { - clear: both; -} -* html #footer { - margin-left: 0; - margin-right: 13.6em; - border-left: 0; - border-right: 1px solid #fabd23; -} -* html #column-content { - float: none; - margin-left: 0; - margin-right: 0; -} -* html #column-content #content { - margin-left: 0; - margin-top: 3em; -} -* html #column-one { right: 0; } - -/* js pref toc */ -#preftoc { float: right; } -/* workaround for moz bug, displayed bullets on left side */ -#preftoc li { list-style: none; } -#prefcontrol { float: right; } -fieldset.prefsection, -fieldset.operaprefsection { - margin-left: 0 !important; - margin-right: 15em; -} diff --git a/wiki/static/crans-www/css/screen.css b/wiki/static/crans-www/css/screen.css deleted file mode 100644 index 2570fb8a..00000000 --- a/wiki/static/crans-www/css/screen.css +++ /dev/null @@ -1,112 +0,0 @@ -/* moin overrides to monobook styles */ - -/* moin uses #page rather than #content for the main page content. -setup #page as #content from the monobook.css and remove margins -and paddings from #content */ - -/* IMPORTS - /!\ les imports doivent imperativement se faire avant - toute autre regle css !!! -*/ - -@import url('/wiki/common/toc/toc.css'); -@import url('/wiki/common/boxes/boxes.css'); -@import url('/wiki/common/EventCalendar/EventCalendar.css'); -@import url('/wiki/common/pagesPersos.css'); - -/**/ -/* on ne change que ce qu'on veut - changer -*/ - -#tableOfContents { - background:transparent url(../img/translucide2.png) repeat; - border:1px solid #232323; -} - -pre { - overflow:auto; - background:transparent url(../img/translucide2.png) repeat; -} - -/* */ -/* message set as usermessage from base css */ -#message { - background:transparent url(../img/translucide2.png) repeat; - border:1px solid #232323; - margin:1em auto; - padding:5px; -} - -.buttons { - text-align:right; -} - -/* diff styling copied from modern theme */ -/* -.diff { - width:99%; -} - -.diff-header { - font-weight: bold; -} - -.diff-title { - background-color: #C0C0C0; -} - -.diff-added { - background-color: #E0FFE0; - vertical-align: sub; -} - -.diff-removed { - background-color: #FFFFE0; - vertical-align: sub; -} - -.diff-added span { - background-color: #80FF80; -} - -.diff-removed span { - background-color: #FFFF80; -} - -/* copied from the modern theme */ - -#credits, #version, #timings{ - margin: 5px 10px; - padding: 0; - text-align: center; - font-size: 0.88em; - background-color:transparent; - color: #6C7680; - font-size: 12px; -} - -#credits li, #timings li { - display: inline; - padding: 0 2px; - margin: 0 4px; -} - -/* We use here dumb css1 ids because of IE suckiness */ -#editor-textarea, #editor-comment { - width: 100%; -} - -div.codearea { /* the div makes the border */ - border: 1px dashed #2f6fab; -} - - -/* Search form */ -#searchInput { - padding: 2px 2px 2px 18px; - background: #fff url(../img/q.png) no-repeat 4px center; - font: 0.9em "Trebuchet MS", helvetica, sans-serif; - border:thin gray solid; - margin: 4px 0; -} diff --git a/wiki/static/crans/css/bde.css b/wiki/static/crans/css/bde.css deleted file mode 100644 index 21b956bc..00000000 --- a/wiki/static/crans/css/bde.css +++ /dev/null @@ -1,44 +0,0 @@ -/************************************************************* - .. - .... ............ ........ - . ....... . .... .. - . ... .. .. .. .. ..... . .. - .. .. ....@@@. .. . ........ . - .. . .. ..@.@@..@@. .@@@@@@@ @@@@@@. .... - .@@@@. .@@@@. .@@@@..@@.@@..@@@..@@@..@@@@.... .... - @@@@... .@@@.. @@ @@ .@..@@..@@...@@@. .@@@@@. .. - .@@@.. . @@@. @@.@@..@@.@@..@@@ @@ .@@@@@@.. ..... - ...@@@.... @@@ .@@.......... ........ ..... .. - . ..@@@@.. . .@@@@. .. ....... . ............. - . .. .... .. .. . ... .... -. . .... ............. .. ... -.. .. ... ........ ... ... - ................................ - -============================================================== -bde.css - MoinMoin Style - - Theme bde. - - -Copyright (c) 2006 by www.crans.org - -**************************************************************/ -div#content -{ - background-image: url("../img/fond_bde.png"); -} - -/* ****************************** BARRE DE TITRE ****************************** */ -div#titleBarre { - border-bottom: thin solid blue; - background: blue url(../img/BarreBleue.png) repeat-x; -} -/* on change la couleur des soulignements de titres pour aller avec la barre */ -h1, h2, h3, h4, h5, h6 {border-color: blue} -div#titleBarre *, -div#titleBarre h1#title a { color: white; } -h1#title { background: url(../img/barreLogoBde.png) no-repeat right top;} - - - diff --git a/wiki/static/crans/css/common.css b/wiki/static/crans/css/common.css deleted file mode 100644 index 03b51cfd..00000000 --- a/wiki/static/crans/css/common.css +++ /dev/null @@ -1,347 +0,0 @@ -/************************************************************* - .. - .... ............ ........ - . ....... . .... .. - . ... .. .. .. .. ..... . .. - .. .. ....@@@. .. . ........ . - .. . .. ..@.@@..@@. .@@@@@@@ @@@@@@. .... - .@@@@. .@@@@. .@@@@..@@.@@..@@@..@@@..@@@@.... .... - @@@@... .@@@.. @@ @@ .@..@@..@@...@@@. .@@@@@. .. - .@@@.. . @@@. @@.@@..@@.@@..@@@ @@ .@@@@@@.. ..... - ...@@@.... @@@ .@@.......... ........ ..... .. - . ..@@@@.. . .@@@@. .. ....... . ............. - . .. .... .. .. . ... .... -. . .... ............. .. ... -.. .. ... ........ ... ... - ................................ - -============================================================== -common.css - MoinMoin Style - - Styles communs a tous les medias (screen, print...) - - -Copyright (c) 2006 by www.crans.org - -**************************************************************/ - -/* IMPORTS - /!\ les imports doivent imperativement se faire avant - toute autre regle css !!! -*/ - -@import url('/wiki/common/toc/toc.css'); -@import url('/wiki/common/boxes/boxes.css'); -@import url('/wiki/common/pagesPersos.css'); -@import url('/wiki/common/EventCalendar/EventCalendar.css'); - -html { - background-color: white; - color: black; - font-family: sans-serif; - font-size: 0.85em; - line-height: 1.1em; -} - -#content, #preview { - padding-left:0em; -} - -/* img { max-width:90%; } */ - -.visualclear, #pagebottom { - clear:both; -} - -/* Links */ - -a {color: #0044B3;} -a:visited {color: #597BB3;} -a.nonexistent, a.badinterwiki {color: gray;} - -/* Headings */ - -h1, h1 a, h1 a:visited, -h2, h2 a, h2 a:visited, -h3, h3 a, h3 a:visited, -h4, h4 a, h4 a:visited, -h5, h5 a, h5 a:visited, -h6, h6 a, h6 a:visited { - padding: 0; - color: black; - line-height: 1.2em; - text-decoration:none; -} - -h1 { - margin: 1.5em 0 0 0em; - font-size: 2em; - border-bottom: #f9821d 4px solid; -} -h2 { - margin: 0.9em 0 0 1em; - font-size: 1.6em; - border-bottom: #f9821d 3px solid; -} -h3 { - margin: 0.9em 0 0 2em; - font-size: 1.3em; - border-bottom: #f9821d 1px solid; -} -h4, h5, h6 { - margin: 0.9em 0 0 3em; - font-size: 1.1em; -} - -/* Autres */ - -tt {font-size: 1em;} - -li p { - margin: .25em 0; -} - -li.gap { - margin-top: 0.5em; -} - -dt { - margin-top: 0.5em; - font-weight: bold; -} - -dd { - margin-top: 0; - margin-bottom: 0; -} - -dd p { - margin: 0.25em 0; -} - -a, img, img.drawing { - border: 0; -} - -pre -{ - border: 1pt solid #AEBDCC; - background-image: url(../img/bleutransparent.png); - padding: 5pt; - font-family: courier, monospace; - white-space: pre; - /* begin css 3 or browser specific rules - do not remove! - see: http://forums.techguy.org/archive/index.php/t-249849.html */ - white-space: pre-wrap; - word-wrap: break-word; - white-space: -moz-pre-wrap; - white-space: -pre-wrap; - white-space: -o-pre-wrap; - /* end css 3 or browser specific rules */ -} - -table -{ - margin: 0.5em 0; - border-collapse: collapse; -} - -td -{ - padding: 0.25em; - border: 1pt solid #ADB9CC; -} - -td p { - margin: 0; - padding: 0; -} - -.footnotes div { - width: 5em; - border-top: 1pt solid gray; -} - -.footnotes ul { - padding: 0 2em; - margin: 0 0 1em; - list-style: none; -} - -.footnotes li { -} - -.info { - font-size: 0.85em; - color: gray; -} - -#pageinfo { - margin-top: 2em; - text-align:right; -} - -.seperator { - color: gray; -} - -/* standard rule ---- */ -hr { - clear: both; - height: 1pt; - background-color: #9C9C9C; - border: 0; -} - -/* custom rules ----- to ---------- */ -.hr1 {height: 2pt;} -.hr2 {height: 3pt;} -.hr3 {height: 4pt;} -.hr4 {height: 5pt;} -.hr5 {height: 6pt;} -.hr6 {height: 7pt;} - -/* Replacement for html 3 u tag */ -.u {text-decoration: underline;} - -/* eye catchers */ -.warning -{ - color: orange; -} - -.error -{ - color: red; -} - -strong.highlight -{ - background-color: #CCE0FF; - padding: 1pt; -} - - -/* Recent changes */ - -.rcrss { - float: right; - margin: 0; -} - -.recentchanges[dir="rtl"] .rcrss { - float: left; -} - -.recentchanges table { - clear: both; -} - -.recentchanges td { - vertical-align: top; - border: none; - border-bottom: 1pt solid #E6EAF0; - background: #F2F4F7; -} - -.rcdaybreak td { - background: #B8C5D9; - border: none; -} - -.rcdaybreak td a { - font-size: 0.88em; -} - -.rcicon1, .rcicon2 { - text-align: center; -} - -.rcpagelink { - width: 33%; -} - -.rctime { - font-size: 0.88em; - white-space: nowrap; -} - -.rceditor { - white-space: nowrap; - font-size: 0.88em; -} - -.rccomment { - width: 66%; - color: gray; - font-size: 0.88em; -} - - -/* User Preferences */ - -.userpref table, .userpref td { - border: none; -} - -/* CSS for new code_area markup used by Colorizer and ParserBase */ - -div.codearea { /* the div makes the border */ - margin: 0.5em 0; - padding: 0; - border: 1pt solid #AEBDCC; - background-color: #F3F5F7; - color: black; -} - -div.codearea pre { /* the pre has no border and is inside the div */ - margin: 0; - padding: 10pt; - border: none; -} - -a.codenumbers { /* format of the line numbering link */ - margin: 0 10pt; - font-size: 0.85em; - color: gray; -} - -/* format of certain syntax spans */ -div.codearea pre span.LineNumber {color: gray;} -div.codearea pre span.ID {color: #000000;} -div.codearea pre span.Operator {color: #0000C0;} -div.codearea pre span.Char {color: #004080;} -div.codearea pre span.Comment {color: #008000;} -div.codearea pre span.Number {color: #0080C0;} -div.codearea pre span.String {color: #004080;} -div.codearea pre span.SPChar {color: #0000C0;} -div.codearea pre span.ResWord {color: #A00000;} -div.codearea pre span.ConsWord {color: #008080; font-weight: bold;} -div.codearea pre span.Error {color: #FF8080; border: solid 1.5pt #FF0000;} -div.codearea pre span.ResWord2 {color: #0080ff; font-weight: bold;} -div.codearea pre span.Special {color: #0000ff;} -div.codearea pre span.Preprc {color: #803999;} - - -/* Search results */ - -.searchresults dt { - margin-top: 1em; - font-weight: normal; -} - -.searchresults dd { - font-size: 0.85em; -} - - -/* Liens d'actions */ -.editbar { - display: block; -} - -.editbar li { - float: left; - padding: 0; -} - diff --git a/wiki/static/crans/css/crans.css b/wiki/static/crans/css/crans.css deleted file mode 100644 index a0c6e045..00000000 --- a/wiki/static/crans/css/crans.css +++ /dev/null @@ -1,48 +0,0 @@ -/************************************************************* - .. - .... ............ ........ - . ....... . .... .. - . ... .. .. .. .. ..... . .. - .. .. ....@@@. .. . ........ . - .. . .. ..@.@@..@@. .@@@@@@@ @@@@@@. .... - .@@@@. .@@@@. .@@@@..@@.@@..@@@..@@@..@@@@.... .... - @@@@... .@@@.. @@ @@ .@..@@..@@...@@@. .@@@@@. .. - .@@@.. . @@@. @@.@@..@@.@@..@@@ @@ .@@@@@@.. ..... - ...@@@.... @@@ .@@.......... ........ ..... .. - . ..@@@@.. . .@@@@. .. ....... . ............. - . .. .... .. .. . ... .... -. . .... ............. .. ... -.. .. ... ........ ... ... - ................................ -============================================================== -crans.css - MoinMoin Style - Theme crans (screen) -Copyright (c) 2006 by www.crans.org -**************************************************************/ -div#content -{ - background-image: url("../img/fond.png"); -} -/* ****************************** BARRE DE TITRE ****************************** */ -/* on change la couleur des soulignements de titres pour aller avec la barre */ -h1, h2, h3, h4, h5, h6 {border-color: #f9821d} -div#titleBarre { -// border-bottom: thin solid #f9821d;//orange; - background: #f9821d url(../img/BarreOrange.png) repeat-x; - } - div#titleBarre *, - div#titleBarre h1#title a { - color: white; } - div#titleBarre h1#title { - background: url(../img/BarreLogo.png) no-repeat right top; - } -/* variantes */ -.halloween div#titleBarre h1#title { - background-image: url(../img/barreLogoHalloween.png); -} -.noel div#titleBarre { - background: #fff url(../img/BarreOrangeNeige.png) repeat-x; - } - .noel div#titleBarre h1#title { - background-image: url(../img/BarreLogoNeige.png); - } \ No newline at end of file diff --git a/wiki/static/crans/css/ensanime.css b/wiki/static/crans/css/ensanime.css deleted file mode 100644 index 9b5bdb95..00000000 --- a/wiki/static/crans/css/ensanime.css +++ /dev/null @@ -1,136 +0,0 @@ -/************************************************************* - .. - .... ............ ........ - . ....... . .... .. - . ... .. .. .. .. ..... . .. - .. .. ....@@@. .. . ........ . - .. . .. ..@.@@..@@. .@@@@@@@ @@@@@@. .... - .@@@@. .@@@@. .@@@@..@@.@@..@@@..@@@..@@@@.... .... - @@@@... .@@@.. @@ @@ .@..@@..@@...@@@. .@@@@@. .. - .@@@.. . @@@. @@.@@..@@.@@..@@@ @@ .@@@@@@.. ..... - ...@@@.... @@@ .@@.......... ........ ..... .. - . ..@@@@.. . .@@@@. .. ....... . ............. - . .. .... .. .. . ... .... -. . .... ............. .. ... -.. .. ... ........ ... ... - ................................ - -============================================================== -ensanime.css - MoinMoin Style - - Theme ensanime - - -Copyright (c) 2006 by www.crans.org - -**************************************************************/ -/**/ -body, html -{ - background:black; - color:white; -} - -/**/ -h1#title -{ - border-bottom: thin solid red; - background: url(../img/BarreRouge.png) repeat-x; -} -h1, h2, h3, h4, h5, h6 {border-color: red} - - -/**/ - -div#column-one { - /* couleurs */ - background:#222222; - border-left:thin solid #bbbbbb; -} - -div#column-one li a { - color:#aaaaaa; -} - -div#p-logo { - display:none; -} - - -div#content{ - background-image: url("../img/fond_ensanime.png"); - background-position: center center; - background-attachment: fixed; - padding-left: 15px; - padding-right: 10px; -} - - - -.diff-title, .diff-added, .diff-removed { - background-color: #444444; -} - -.diff-added span { - background-color: #CC0000; - color:black; -} - -.diff-removed span { - background-color: #AAAAAA; - color:black; -} - -#message { - color:black; -} - - - -/* Links */ - -a {color: #FF5C5C;} -a:visited {color: #FF0000;} -a.nonexistent, a.badinterwiki {color: white;} -/* Headings */ - -h1, -h1 a, h1 a:visited, -h2, h3, h4, h5, h6 -{ -color: white; -} - -tt {font-size: 1.5em;} - - -strong.highlight -{ -background-color: #666666; -padding: 1pt; -} - -.rcdaybreak td { -background: #BBBBBB; -} - -.rcicon1, .rcicon2 { -background: #555555; -} - -.rctime, -.rceditor, -.rccomment { -color:black; -} - -#tableOfContents { -border: 1px solid #; -background:#121212; -} - -table{ -background-image: url(../img/blanctransparent.png); -color:black; -} - diff --git a/wiki/static/crans/css/federez.css b/wiki/static/crans/css/federez.css deleted file mode 100644 index 773ccde4..00000000 --- a/wiki/static/crans/css/federez.css +++ /dev/null @@ -1,56 +0,0 @@ -/************************************************************* - .. - .... ............ ........ - . ....... . .... .. - . ... .. .. .. .. ..... . .. - .. .. ....@@@. .. . ........ . - .. . .. ..@.@@..@@. .@@@@@@@ @@@@@@. .... - .@@@@. .@@@@. .@@@@..@@.@@..@@@..@@@..@@@@.... .... - @@@@... .@@@.. @@ @@ .@..@@..@@...@@@. .@@@@@. .. - .@@@.. . @@@. @@.@@..@@.@@..@@@ @@ .@@@@@@.. ..... - ...@@@.... @@@ .@@.......... ........ ..... .. - . ..@@@@.. . .@@@@. .. ....... . ............. - . .. .... .. .. . ... .... -. . .... ............. .. ... -.. .. ... ........ ... ... - ................................ - -============================================================== -bde.css - MoinMoin Style - - Theme bde. - - -Copyright (c) 2006 by www.crans.org - -**************************************************************/ - -/* fond de page */ -div#content{ background-image: url("../img/fond_federez.png"); } - -/* couleur des liens */ -a, a:visited, a:hover {color: #776c4a} -/* ****************************** BARRE DE TITRE ****************************** */ -div#titleBarre { - /* couleur de la barre et du léger trait en dessous */ - border-bottom: thin solid #afafd6; - background-color: #afafd6; - /* image de fond de la barre */ - background-image: url("../img/BarreBleuGris.png"); -} -/* image de la barre, en haut à droite */ -h1#title { background-image: url("../img/barreLogoFederez.png");} -/* on change la couleur des soulignements de titres pour aller avec la barre */ -h1, h2, h3, h4, h5, h6 {border-color: #afafd6} -/* Couleur du texte du titre de la page */ -div#titleBarre *, -div#titleBarre h1#title a { color: #6c6c7a; } -/* Couleur des "/" dans le titre de la page */ -h1#title ul#pagelocation li:before{ color: white; } - -} - - -/* du bleu-gris : #afafd6; */ -/* du maron : #776c4a; */ - diff --git a/wiki/static/crans/css/layout.css b/wiki/static/crans/css/layout.css deleted file mode 100644 index f093101b..00000000 --- a/wiki/static/crans/css/layout.css +++ /dev/null @@ -1,329 +0,0 @@ -/************************************************************* - .. - .... ............ ........ - . ....... . .... .. - . ... .. .. .. .. ..... . .. - .. .. ....@@@. .. . ........ . - .. . .. ..@.@@..@@. .@@@@@@@ @@@@@@. .... - .@@@@. .@@@@. .@@@@..@@.@@..@@@..@@@..@@@@.... .... - @@@@... .@@@.. @@ @@ .@..@@..@@...@@@. .@@@@@. .. - .@@@.. . @@@. @@.@@..@@.@@..@@@ @@ .@@@@@@.. ..... - ...@@@.... @@@ .@@.......... ........ ..... .. - . ..@@@@.. . .@@@@. .. ....... . ............. - . .. .... .. .. . ... .... -. . .... ............. .. ... -.. .. ... ........ ... ... - ................................ - -============================================================== -layout.css - MoinMoin Style - - Theme crans, layout principal (screen) - - -Copyright (c) 2006 by www.crans.org - -**************************************************************/ -/**/ -html{ - padding:0; - margin:0; } - -body { - margin: 40px 0 0 0; - padding :0; } - -div#page { - position:relative; - margin:10px 170px 0 0; - padding:0; -} - -div#content { - position:relative; - padding:0 15px 0 15px; - /*background-image: url("../img/fond.png");*/ - background-color: transparent; - background-repeat: no-repeat; - background-position: center center; - background-attachment: fixed; - min-height:500px; -} - -/* ****************************** BARRE DE TITRE ****************************** */ -div#titleBarre { - float:right; - z-index:5; - position: fixed; - left: 0; - top: 0; - padding:0; - margin:0; - height: 40px; - width:100%; - border-bottom: thin solid #fcedd6; - background: url(../img/barreViole.png) repeat-x; - text-align:left; - color: white; - font: 25px "Trebuchet MS", helvetica, sans-serif ; - text-decoration:none; - } -/* on change la couleur des soulignements de titres pour aller avec la barre */ -h1, h2, h3, h4, h5, h6 {border-color: #fcedd6} - - div#titleBarre h1#title { - /* pour ie */ - position:absolute; - top:0; - /* fin pour ie */ - margin: 0; - display:block; - width:100%; - height:40px; - padding:0; - background: url(../img/logo.png) no-repeat right top; - border:none; - } - - div#titleBarre *, - div#titleBarre h1#title a { - color: white; - font: 25px "Trebuchet MS", helvetica, sans-serif ; - text-decoration:none; - } - - -ul#pagelocation { - list-style-type:none; - height:25px; - padding:5px 10px 10px 10px; - margin:0; - float:left; - } -ul#pagelocation li { - display:inline; - float:left; - } -ul#pagelocation li:before{ - content:"/"; - color:white; - } -h1#title>a{ - margin:10px; - display:block; - height:25px; - padding:0; - vertical-align:middle; - -} - -/* ****************************** MENU DE DROITE ****************************** */ - -div#column-one ul, div#column-one li { - /* utilisation de liste pour le menu */ - list-style-type: none; /* suppression des puces de liste */ - margin:0; - padding:0; -} - -div#column-one { - /* position */ - z-index:2; - position: absolute; - right:0; - top:41px; - /* dimensions */ - padding:5px 10px 10px 10px; - width:150px; - //height:100%; - overflow:hidden; - margin:0px; - /* texte */ - font: 0.9em "Trebuchet MS", helvetica, sans-serif; - text-align:left; - /* couleurs */ - background:#eeeeee; - border-left:thin solid #bbbbbb; - border-bottom:thin solid #bbbbbb; -} - -/* des lignes de separation entre les sections */ -div#column-one form#searchform:after, -div#column-one ul:after { - content:url(../img/Separator.png); - display: block; - text-align: center; - margin:2px auto; -} - -/* sauf pour le dernier */ -div#column-one ul#credits:after { - content: ''; -} - -/* style des liens */ -div#column-one li a, -div#column-one li a:hover { - margin:2px; - text-decoration: none; - color:#777777; -} -div#column-one li a:hover { - text-decoration: underline; -} - -div#column-one li span.disabled { - margin:2px; - color:#999999; -} -div#column-one li span.disabled:before { - content:"/!\\ "; -} - -/* style des menus deroulants */ -div#column-one select { - width:152px; - margin: 5px 0; - border: thin gray solid; - font-size: 0.9em; -} - -/* divers */ -#credits { - margin-bottom:0; - text-align: center; - font-size: 0.88em; -} -#credits li { display: inline;} -div#p-logo { - display:none; -} - -/* titres de sections */ -div#column-one h5 { - margin:2px; - text-decoration:none; - font-size:1em; - font-weight:bold; -} - -/* champ de recherche */ -#searchinput { - padding: 2px 2px 2px 18px; - background: #fff url(../img/q.png) no-repeat 4px center; - width:132px; - font: 0.9em "Trebuchet MS", helvetica, sans-serif; - border:thin gray solid; - margin: 5px 0; - -} - -/* ********************************** DIVERS ********************************** */ -#timings { display: none;} - - - -/* ***************************** EDITEUR DE TEXTE ***************************** */ -textarea { - width: 95%; -} -#preview { - border: 1px solid #6C7680; - padding: .5em; - background: url(../img/draft.png); -} - -/* *********************************** DIFF *********************************** */ -.diff { - width:99%; -} - -.diff-header { - font-weight: bold; -} - -.diff-title { - background-color: #C0C0C0; -} - -.diff-added { - background-color: #E0FFE0; - vertical-align: sub; -} - -.diff-removed { - background-color: #FFFFE0; - vertical-align: sub; -} - -.diff-added span { - background-color: #80FF80; -} - -.diff-removed span { - background-color: #FFFF80; -} - -/* ********************************* MESSAGES ********************************* */ -#message { - clear: both; - margin: 0 170px 0 0; - padding: 5px 0px; - border-bottom: 1px solid #c9c9c9; - background: #E6EAF0; - font-size: 0.9em; -} - -#message p{ - margin: 0; - padding: 0 10px 0 20px; - font-weight: bold; -} - -#message div.buttons { - font-weight: lighter; - padding: 0 0 0 30px; -} - - -/* Collection de hacks à la con pour IE */ -@media screen { -/* - * html { - overflow: hidden; - } -/**/ -/* * html body { - overflow-y: auto; - height: 100%; - //padding: 44px 160px 0 1em; - font-size: 100%; - } -/**/ -/* * html body { - overflow: hidden; - height: 100%; - } - * html body #page { - overflow: auto; - height: 100%; - } - -/**/ - * html div#column-one { - position: absolute; - } -/**/ - * html h1#title - { - position: absolute; - width: expression(document.body.clientWidth); - } - - * html div.portlet, * html #editbar - { - padding-bottom: 1.5em; - } - -} -/**/ diff --git a/wiki/static/crans/css/movieclub.css b/wiki/static/crans/css/movieclub.css deleted file mode 100644 index 11b646f1..00000000 --- a/wiki/static/crans/css/movieclub.css +++ /dev/null @@ -1,116 +0,0 @@ -/************************************************************* - .. - .... ............ ........ - . ....... . .... .. - . ... .. .. .. .. ..... . .. - .. .. ....@@@. .. . ........ . - .. . .. ..@.@@..@@. .@@@@@@@ @@@@@@. .... - .@@@@. .@@@@. .@@@@..@@.@@..@@@..@@@..@@@@.... .... - @@@@... .@@@.. @@ @@ .@..@@..@@...@@@. .@@@@@. .. - .@@@.. . @@@. @@.@@..@@.@@..@@@ @@ .@@@@@@.. ..... - ...@@@.... @@@ .@@.......... ........ ..... .. - . ..@@@@.. . .@@@@. .. ....... . ............. - . .. .... .. .. . ... .... -. . .... ............. .. ... -.. .. ... ........ ... ... - ................................ - -============================================================== -common.css - MoinMoin Style - -Theme movieclub - -Copyright (c) 2006 by www.crans.org - -**************************************************************/ -/**/ -body, html -{ - background-color:black; - color:white; -} - -/**/ -h1#title -{ - border-bottom: thin solid green; - background: url(../img/BarreVerte.png) repeat-x; -} -h1, h2, h3, h4, h5, h6 {border-color: green} - -/**/ - - -div#column-one { - /* couleurs */ - background:#222222; - border-left:thin solid #bbbbbb; -} - -div#column-one li a { - color:#aaaaaa; -} - - -div#content{ - background-image: url("../img/fond_movieclub.png"); - padding-left: 15px; - padding-right: 10px; -} -#message { - color:black; -} - -.diff-title, .diff-added, .diff-removed { - background-color: #444444; -} - -.diff-added span { - background-color: #00CC00; - color:black; -} - -.diff-removed span { - background-color: #AAAAAA; - color:black; -} -/* Links */ - -a {color: #5CFF5C;} -a:visited {color: #00FF00;} -a.nonexistent, a.badinterwiki {color: white;} - -/* Headings */ - -h1, -h1 a, h1 a:visited, -h2, h3, h4, h5, h6 { - color: white; -} - - -/* Divers */ - -tt {font-size: 1.5em;} - -strong.highlight -{ -background-color: #666666; -} - -.rcdaybreak td { -background: #BBBBBB; -} -.rcicon1, .rcicon2 { -background: #555555; -} -.rctime, -.rceditor, -.rccomment { -color:black; -} - -#tableOfContents { - border: 1px solid #; - background:#121212; -} diff --git a/wiki/static/crans/css/print.css b/wiki/static/crans/css/print.css deleted file mode 100644 index 687559f1..00000000 --- a/wiki/static/crans/css/print.css +++ /dev/null @@ -1,54 +0,0 @@ -/* print.css - MoinMoin Default Styles - -Copyright (c) 2001, 2002, 2003 by Juergen Hermann -*/ - -/* content styles */ - -html { - font-family: Times, serif; - font-size: 12pt; -} - -body { - /* Give about 3.4cm in Mozilla/Firefox and about 2.2cm in Safari */ - margin: 1.5cm; -} - -a, a:visited, a.nonexistent, a.badinterwiki { - color: black; - text-decoration: none; -} - -a:hover { - text-decoration: underline; -} - -pre { - font-size: 10pt; -} - -a.interwiki:before, a.badinterwiki:before { - content: attr(title) ":"; -} - -a.interwiki img, a.badinterwiki img { - display: none; -} - -.footnotes div { - width: 5em; - border-top: 1pt solid gray; -} - -/* user interface styles */ - -#header, #sidebar, #footer, #timings, #credits, #column-one { - display: none; -} - -div#titleBarre h1#title { - text-align: center; - border: thin black solid; - padding:3px; -} diff --git a/wiki/static/crans/css/projection.css b/wiki/static/crans/css/projection.css deleted file mode 100644 index d810a504..00000000 --- a/wiki/static/crans/css/projection.css +++ /dev/null @@ -1,90 +0,0 @@ -/* projection.css - MoinMoin Slide Styles - -Copyright (c) 2003 by Juergen Hermann -*/ -@import url("crans.css"); -/* @import url("screen.css"); */ - -html { line-height: 1.8em; } - -#page { - margin: 0; - padding: 0; - border: none; - z-index: 1; - padding-bottom: 1em; -} - -#content { - padding: 1em; -} - -body, b, em, a, span, div, p, td { font-size: 22pt; } - -h1 { - font-size: 16pt; - margin: 0; - background: #81BBF2; -} - -h2 { - font-size: 32pt; - margin-top: 0.5em; - padding-left: 1em; - padding-right: 1em; - border-bottom: 4px solid blue; -} - -h3 { font-size: 22pt; } -h4 { font-size: 20pt; } -h5 { font-size: 18pt; } -h6 { font-size: 16pt; } -tt,pre { font-size: 18pt; } -sup, sub { font-size: 14pt; } - - -#pageinfo { - display: none; -} - -#timings{ - display: none; -} - -#navigation { - position: fixed; - bottom: 0; - left: 0; - right: 0; - padding: 0; - border-top: 1px dotted #808080; - color: #808080; - font-size: 10pt; - z-index: 2; - background: White; -} - -#navigation ul { - margin: 8pt; - text-align: center; -} - -#navigation a { - text-decoration: none; -} - -#navigation li { - display: inline; - text-align: center; - margin: 0 2pt; - padding: 0; -} - -#navigation li.current { - border: 1pt solid #808080; - padding: 2pt 4pt; -} - -.codenumbers{ - display: None; -} diff --git a/wiki/static/crans/css/rtl.css b/wiki/static/crans/css/rtl.css deleted file mode 100644 index 314534ca..00000000 --- a/wiki/static/crans/css/rtl.css +++ /dev/null @@ -1,202 +0,0 @@ -/* -Right-to-left fixes for MonoBook. -Places sidebar on right, tweaks various alignment issues. - -Works mostly ok nicely on Safari 1.2.1; fine in Mozilla. - -Safari bugs (1.2.1): -* Tabs are still appearing in left-to-right order. (Try after localizing) - -Opera bugs (7.23 linux): -* Some bits of ltr text (sidebar box titles) have forward and backward versions overlapping each other - -IE/mac bugs: -* The thing barfs on Hebrew and Arabic anyway, so no point testing. - -Missing features due to lack of support: -* external link icons, icon next to user name - -To test: -* Opera6 -* IE 5.0 -* etc - -*/ -body, -body * { - direction: rtl; -/* unicode-bidi: bidi-override;*/ - unicode-bidi: embed; -} -#column-content { - margin: 0 -12.2em 0 0; - float: left; -} -#column-content #page{ - margin-left: 0; - margin-right: 12.2em; - border-right: 1px solid #aaaaaa; - border-left: none; -} -html>body .portlet { - float: right; - clear: right; -} -/* recover IEMac (might be fine with the float, but usually it's close to IE */ -*>body .portlet { - float: none; - clear: none; -} -.pBody { - padding-right: 0.8em; - padding-left: 0.5em; -} - -/* Fix alignment */ -.documentByLine, -.portletDetails, -.portletMore, -#p-personal { - text-align: left; -} - -div div.thumbcaption { - text-align: right; -} - -div.magnify, -#div.townBox, -#p-logo { - left: auto; - right: 0; -} -#p-personal { - left: auto; - right: 0; -} - -#p-cactions { - left: auto; - right: 11.5em; - padding-left: 0; - padding-right: 1em; -} -#p-cactions li { - margin-left: 0.3em; - margin-right: 0; - float: right; -} -* html #p-cactions li a { - display: block; - padding-bottom: 0; -} -* html #p-cactions li a:hover { - padding-bottom: 0.2em; -} -/* offsets to distinguish the tab groups */ -li#ca-talk { - margin-right: auto; - margin-left: 1.6em; -} -li#ca-watch,li#ca-unwatch { - margin-right: 1.6em !important; -} - -/* Fix margins */ -/* top right bottom left */ - -ul { - margin-left: 0; - margin-right: 1.5em; -} -ol { - margin-left: 0; - margin-right: 2.4em; -} -dd { - margin-left: 0; - margin-right: 1.6em; -} -#contentSub { - margin-right: 1em; - margin-left: 0; -} -.tocindent { - margin-left: 0; - margin-right: 2em; -} -div.tright { - clear: none; -} -div.tleft { - clear: left; -} -div.floatright, table.floatright { - clear: none; -} -div.floatleft, table.floatleft { - clear: left; -} -div.townBox { - margin-left: 0; - margin-right: 1em; -} -div.townBox dl dd { - margin-left: 0; - margin-right: 1.1em; -} -#p-personal li { - margin-left: 0; - margin-right: 1em; -} - -li#ca-talk, -li#ca-watch { - margin-right: auto; - margin-left: 1.6em; -} - -#p-personal li { - float: left; -} -/* Fix link icons */ -li#pt-userpage, -li#pt-anonuserpage, -li#pt-login { - background: none; - padding-left: 0; -} -.external { - padding: 0 !important; - background: none !important; -} -#footer { - clear: both; -} -* html #footer { - margin-left: 0; - margin-right: 13.6em; - border-left: 0; - border-right: 1px solid #fabd23; -} -* html #column-content { - float: none; - margin-left: 0; - margin-right: 0; -} -* html #column-content #content { - margin-left: 0; - margin-top: 3em; -} -* html #column-one { right: 0; } - -/* js pref toc */ -#preftoc { float: right; } -/* workaround for moz bug, displayed bullets on left side */ -#preftoc li { list-style: none; } -#prefcontrol { float: right; } -fieldset.prefsection, -fieldset.operaprefsection { - margin-left: 0 !important; - margin-right: 15em; -} diff --git a/wiki/static/crans/js/scroller.js b/wiki/static/crans/js/scroller.js deleted file mode 100644 index 95e7c60d..00000000 --- a/wiki/static/crans/js/scroller.js +++ /dev/null @@ -1,69 +0,0 @@ -scroller = -{ -} -; - -scroller.element_id = "column-one"; -scroller.min_top = 41; - - - -scroller.setMenuOffset = function() -{ - - - var element = document.getElementById(scroller.element_id); - if (!element) return; - element.style.position = "fixed"; - var currentWindowHeight = document.documentElement.clientHeight; - var currentScroll = document.documentElement.scrollTop || document.body.scrollTop; // body for Safari - var currentElementHeight = element.clientHeight; - - var startPosition = scroller.min_top; - - if (currentWindowHeight > currentElementHeight + startPosition) - { - - element.style.top = startPosition + 'px'; - return; - } - - - var desiredPosition = startPosition - currentScroll ; - if (desiredPosition < currentWindowHeight - currentElementHeight) - desiredPosition = currentWindowHeight - currentElementHeight; - element.style.top = desiredPosition + 'px'; - -} - - -scroller.init = function () -{ - - - /* See if browser supports advanced interface */ - - //var advancedJavaScriptSupport = document.createElement && document.getElementsByTagName && createXMLHTTPObject(); - //if (!advancedJavaScriptSupport) return; - - /* Load advanced interface */ - window.onscroll = document.documentElement.onscroll = scroller.setMenuOffset; - scroller.setMenuOffset(); -} - - -// use this instead of assigning to window.onload directly: - function addLoadEvent(func) { - // alert("addLoadEvent " + func) - var oldonload = window.onload; - if (typeof window.onload != 'function') { - window.onload = func; - } else { - window.onload = function() { - oldonload(); - func(); - } - } - } - -addLoadEvent(scroller.init); diff --git a/wiki/theme/__init__.py b/wiki/theme/__init__.py deleted file mode 100644 index e4ed3b60..00000000 --- a/wiki/theme/__init__.py +++ /dev/null @@ -1,5 +0,0 @@ -# -*- coding: iso-8859-1 -*- - -from MoinMoin.util import pysupport - -modules = pysupport.getPackageModules(__file__) diff --git a/wiki/theme/bde.py b/wiki/theme/bde.py deleted file mode 100644 index b385f1b6..00000000 --- a/wiki/theme/bde.py +++ /dev/null @@ -1,35 +0,0 @@ -# -*- coding: iso-8859-1 -*- -""" - MoinMoin monobook theme. Uses the css sheet from - http://wikipedia.org, adapting the moin output to fit it. - - Adapted by Jim Clark - Adapted for CR@NS by Nicolas Salles - @license: GNU GPL, see COPYING for details. -""" - -from crans import ThemeCrans - -class Theme(ThemeCrans): - - - # Standard set of style sheets - stylesheets = ( - # media basename - ('all', 'common'), - ('screen', 'layout'), - ('screen', 'bde'), - ('print', 'print'), - ('projection', 'projection'), - ) - -def execute(request): - """ - Generate and return a theme object - - @param request: the request object - @rtype: MoinTheme - @return: Theme object - """ - return Theme(request) - diff --git a/wiki/theme/crans-www.py b/wiki/theme/crans-www.py deleted file mode 100644 index 885408fc..00000000 --- a/wiki/theme/crans-www.py +++ /dev/null @@ -1,513 +0,0 @@ -# -*- coding: iso-8859-1 -*- -""" - MoinMoin monobook theme. Uses the css sheet from - http://wikipedia.org, adapting the moin output to fit it. - - Adapted by Jim Clark - @license: GNU GPL, see COPYING for details. -""" - -from MoinMoin.theme import ThemeBase -from MoinMoin import wikiutil, i18n -from MoinMoin.Page import Page -from crans import ThemeCrans - -class Theme(ThemeBase): - icons = ThemeCrans.icons - - name = "crans-www" - - # Liste des feuilles de style - stylesheets = ( - # media basename - ('all', 'common'), - ('screen', 'layout'), - ('screen', 'screen'), - ('print', 'print'), -# ('projection', 'projection'), - ) - - # liste des liens du menu - menu_links = [ - # tire #lien - (u"Accueil", u"http://www.crans.org/"), - (u"Webmail", u"https://webmail.crans.org/"), - (u"Accès SSH", u"http://www.crans.org/VieCrans/OpenSsh"), - (u"Accès Intranet",u"https://intranet.crans.org/"), - (u"Pages persos", u"http://www.crans.org/PagesPerso"), - ] - - # Chemin des badges - badgesPath = u'/wiki/common/badges/' - - # liste des badges - support_badges = [ - # page, # image # alt text - (u'http://www.mozilla-europe.org/fr/products/firefox/', u'badges_80x15_firefox.png', u'Get firefox'), - (u'http://www.debian.org/', u'badges_80x15_debian.png', u'Debian powered'), - (u'http://www.apache.org/', u'badges_80x15_apache.png', u'Apache powered'), - (u'http://www.python.org/', u'badges_80x15_python.png', u'Python powered'), - (u'http://www.federez.org/', u'badges_80x15_federez.png', u'Membre du réseau federeez'), - (u'http://moinmoin.wikiwikiweb.de/', u'badges_80x15_moinmoin.png', u'Moinmoin powered'), - (u'http://jigsaw.w3.org/css-validator/check?uri=referer&profile=css3&warning=no', u'valid_css_80x15.png', u'Valid css3'), -# (u'http://validator.w3.org/check?uri=referer', u'valid_html401_80x15.png', u'Valid html 4.01'), - ] - -# Public functions ##################################################### - - def header(self, d, **kw): - """ Assemble wiki header - Here we don't add any menu bars, search bars, etc - instead wait - until the footer. This keeps the HTML cleaner and more accessible, - making sure the main content arrives first. - """ - parent = d['page'].getParentPage() - title = [ - '
', - self.title(d), - parent and wikiutil.link_tag(self.request, - parent.page_name, - u'Haut') or u'', - '
' - ] - html = [ - u'
', - self.logo(), - u'
', - self.startPage(), - ] - - - if d['page'].page_name != 'VieCrans' : - html += title - html += [self.msg(d)] - return u'\n'.join(html) - - def footer(self, d, **keywords): - """ Assemble wiki footer - """ - html = [ - # End of page - u'
', - self.endPage(), - u'
', - u'
', - self.menu(d), - u'
', - self.username(d), - self.badges(d), - u'', # Campagne "Save A Developer. Upgrade Your Browser." - ] - return u'\n'.join(html) - - def menu(self, d): - """ assemble all the navigation aids for the page - """ - liens = [] - for titre, lien in self.menu_links: - liens.append(u'
  • %s
  • ' % (lien, titre)) - html = [ - u'', - ] - return u''.join(html) - - def badges(self,d ): - badges_html = [] - for page, image, alt_text in self.support_badges: - badges_html.append(u'
  • %(alt)s
  • ' % {'href':page, 'path':self.badgesPath, 'image':image, 'alt':alt_text}) - html = [ - u'
      ', - u'\n'.join(badges_html), - u'
    \n\n', - ] - - return u''.join(html) - - def searchform(self, d): - """ assemble HTML code for the search form - Tweaks from the bass class to wrap in a 'portlet' class, move the - description to a header tag, add an access key of 'f' and - add SearchButton class for the buttons - """ - _ = self.request.getText - form = self.request.form - updates = { - 'search_label' : _('Search:'), - 'search_value': wikiutil.escape(form.get('value', [''])[0], 1), - 'search_full_label' : _('Text', formatted=False), - 'search_title_label' : _('Titles', formatted=False), - } - d.update(updates) - - html = u''' -
    -
    -
    - - -
    - - -
    -
    - ''' % d - return html - - - - def columnone(self, d): - """ assemble all the navigation aids for the page - """ - page = d['page'] - html = [ - u'
    ', - self.editbar(d), - self.username(d), - u'', - self.navibar(d), - self.searchform(d), - self.actionmenu(d), - u'
    ', - u'', - u'
    ' - ] - return u'\n'.join(html) - - def headscript(self, d): - """ Override to not output search/action menu javascript. - (perhaps not a good idea) - """ - return '' - - def extendedAttrs(self, title, accesskey): - """ Helper function for assembling titled access key links - """ - return 'title="%(title)s [alt-%(accesskey)s]" accesskey=%(accesskey)s' % \ - {'accesskey' : accesskey, - 'title' : title} - - def editbar(self, d): - """ Display a list of actions for the page. This list will be turned - into a set of tabbed views on the page by the css. - """ - page = d['page'] - if not self.shouldShowEditbar(page): - return '' - - # Use cached editbar if possible. - cacheKey = 'editbar' - cached = self._cache.get(cacheKey) - if cached: - return cached - - request = self.request - _ = self.request.getText - link = wikiutil.link_tag - quotedname = wikiutil.quoteWikinameURL(page.page_name) - # action, title, description, accesskey - tabs = [('show', 'Article', 'View the page content', 'c'), - ('edit', 'Edit', 'Edit this page', 'e'), - ('diff', 'Show Changes', 'Last page modification', 'd'), - ('info', 'Get Info', 'Page history and information', 'h'), - ('subscribe', 'Subscribe', 'Subscribe to updates to this page', 'w')] - - items = [] - current = self.request.form.get('action', ['show'])[0] - for action, title, description, accesskey in tabs: - if action == current: - cls = 'selected' - else: - cls = 'none' - - if action == 'edit': - if page.isWritable() and request.user.may.write(page.page_name): - pass - else: - action = 'raw' - title = 'View Source' - description = 'This page is protected. You can view its source' - - if action == 'subscribe': - user = self.request.user - if not self.cfg.mail_smarthost or not user.valid: - break - # Email enabled and user valid, get current page status - if user.isSubscribedTo([page.page_name]): - title = 'Unsubscribe' - description = 'Unsubscribe from updates to this page' - - if action == 'show': - url = quotedname - else: - url = quotedname + '?action=' + action - - attrs = self.extendedAttrs(_(description), accesskey) - link = wikiutil.link_tag(self.request, url, _(title), attrs=attrs) - items.append(u'
  • %s
  • ' % (cls, link)) - - html = [ - u'
    ', - u'
      ', - ''.join(items), - u'
    ', - u'
    ' - ] - html = ''.join(html) - # cache for next call - self._cache[cacheKey] = html - - return html - - - def actionmenu(self, d): - """ different implementation of the actionmenu (aka toolbox) - """ - - page = d['page'] - - # Use cached actionmenu if possible. - cacheKey = 'actionmenu' - cached = self._cache.get(cacheKey) - if cached: - return cached - - request = self.request - _ = request.getText - quotedname = wikiutil.quoteWikinameURL(page.page_name) - - menu = [ - 'raw', - 'print', - 'refresh', - 'AttachFile', - 'SpellCheck', - 'LikePages', - 'LocalSiteMap', - 'RenamePage', - 'DeletePage', - ] - - titles = { - 'raw': _('Show Raw Text', formatted=False), - 'print': _('Show Print View', formatted=False), - 'refresh': _('Delete Cache', formatted=False), - 'AttachFile': _('Attach File', formatted=False), - 'SpellCheck': _('Check Spelling', formatted=False), # rename action! - 'RenamePage': _('Rename Page', formatted=False), - 'DeletePage': _('Delete Page', formatted=False), - 'LikePages': _('Show Like Pages', formatted=False), - 'LocalSiteMap': _('Show Local Site Map', formatted=False), - } - - links = [] - - # Format standard actions - available = request.getAvailableActions(page) - for action in menu: - # Enable delete cache only if page can use caching - if action == 'refresh': - if not page.canUseCache(): - break - # Actions which are not available for this wiki, user or page - if action[0].isupper() and not action in available: - break; - - link = wikiutil.link_tag(self.request, \ - quotedname + '?action=' + action, titles[action]) - links.append(link) - - # Add custom actions not in the standard menu - more = [item for item in available if not item in titles] - more.sort() - if more: - # Add more actions (all enabled) - for action in more: - data = {'action': action, 'disabled': ''} - title = Page(request, action).split_title(request, force=1) - # Use translated version if available - title = _(title, formatted=False) - link = wikiutil.link_tag(self.request, \ - quotedname + '?action=' + action, title) - links.append(link) - - html = [ - u'
    ', - u'
    Toolbox
    ', - u'
    ', - u'
      ', - u'
    • %s
    ' % '\n
  • '.join(links), - u'', - u'
  • ', - u'
    ', - ] - html = ''.join(html) - # cache for next call - self._cache[cacheKey] = html - return html - - - def username(self, d): - """ Assemble the username / userprefs link - Copied from the base class, modified to include hotkeys and link titles - """ - from MoinMoin.Page import Page - request = self.request - _ = request.getText - - userlinks = [] - # Add username/homepage link for registered users. We don't care - # if it exists, the user can create it. - if request.user.valid: - homepage = Page(request, request.user.name) - title = homepage.split_title(request) - attrs = self.extendedAttrs(_('User Page'), '.') - homelink = homepage.link_to(request, text=title, attrs=attrs) - userlinks.append(homelink) - - # Set pref page to localized Preferences page - attrs = self.extendedAttrs(_('My Preferences'), 'u') - prefpage = wikiutil.getSysPage(request, 'UserPreferences') - title = prefpage.split_title(request) - userlinks.append(prefpage.link_to(request, text=title, attrs=attrs)) - - # Add a logout link (not sure this is really necessary - attrs = self.extendedAttrs(_('log out'), 'o') - page = d['page'] - url = wikiutil.quoteWikinameURL(page.page_name) + \ - '?action=userform&logout=1' - link = wikiutil.link_tag(self.request, url, 'log out', attrs=attrs) - userlinks.append(link) - - else: - # Add prefpage links with title: Login -# prefpage = wikiutil.getSysPage(request, 'UserPreferences') -# attrs = self.extendedAttrs('Logging in is not required, but brings benefits', 'o') -# userlinks.append(prefpage.link_to(request, text=_("Login"), attrs=attrs)) - url = u'http://wiki.crans.org/%s' % d['page'].page_name - link = u'%s' % ( url, 'Version Wiki') - userlinks.append(link) - - html = [ - u'
    ', - u'
      ', - u'
    • %s
    • ' % '\n
    • '.join(userlinks), - u'
    ', - u'
    ' - ] - return ''.join(html) - - - def shouldShowEditbar(self, page): - """ Override to include the editbar on edit/preview pages. - (at the risk that the user may accidentally cancel an edit) - """ - return False - - - def navibar(self, d): - """ Alterations from the base class to include access keys and - descriptions for FrontPage/RecentChanges - """ - request = self.request - found = {} # pages we found. prevent duplicates - links = [] # navibar items - current = d['page_name'] - - # Process config navi_bar - if request.cfg.navi_bar: - for text in request.cfg.navi_bar: - pagename, link = self.splitNavilink(text) - if pagename == d['page_front_page']: - attrs = self.extendedAttrs('Visit the main page', 'z') - elif pagename == 'RecentChanges': - attrs = self.extendedAttrs('List of recent changes in this wiki', 'r') - else: - attrs = '' - - a = wikiutil.link_tag(request, pagename, attrs=attrs) - links.append(a) - found[pagename] = 1 - - # Add user links to wiki links, eliminating duplicates. - userlinks = request.user.getQuickLinks() - for text in userlinks: - # Split text without localization, user know what she wants - pagename, link = self.splitNavilink(text, localize=0) - if not pagename in found: - a = wikiutil.link_tag(request, pagename, attrs=attrs) - links.append(a) - found[pagename] = 1 - - html = [ - u'', - ] - return ''.join(html) - - def pageinfo(self, page): - """ Simple override from base class. - Remove

    so footer isn't too big - """ - _ = self.request.getText - - if self.shouldShowPageinfo(page): - info = page.lastEditInfo() - if info: - if info['editor']: - info = _("last edited %(time)s by %(editor)s") % info - else: - info = _("last modified %(time)s") % info - return info - return '' - - def rtl_stylesheet(self, d): - """ monobook uses a separate css page for rtl alterations. - Add the rtl stylesheet if the user needs it - """ - link = ('') - html = [] - if i18n.getDirection(self.request.lang) == 'rtl': - prefix = self.cfg.url_prefix - href = '%s/%s/css/%s.css' % (prefix, self.name, 'rtl') - html.append(link % (self.stylesheetsCharset, 'all', href)) - return '\n'.join(html) - - def html_head(self, d): - """ Tweak the sending of the head, to include right-to-left - alterations if necessary - """ - html = [ - u".:: CRANS : Cachan / Réseau @ Normale Sup' ::.", - self.headscript(d), # Should move to separate .js file - self.html_stylesheets(d), - self.rtl_stylesheet(d), - self.rsslink(), - ] - return '\n'.join(html) - -def execute(request): - """ - Generate and return a theme object - - @param request: the request object - @rtype: MoinTheme - @return: Theme object - """ - return Theme(request) diff --git a/wiki/theme/crans.py b/wiki/theme/crans.py deleted file mode 100644 index a6662190..00000000 --- a/wiki/theme/crans.py +++ /dev/null @@ -1,168 +0,0 @@ -# -*- coding: iso-8859-1 -*- -""" - MoinMoin monobook theme. Uses the css sheet from - http://wikipedia.org, adapting the moin output to fit it. - - Adapted by Jim Clark - Adapted for CR@NS by Nicolas Salles - @license: GNU GPL, see COPYING for details. -""" -import datetime -from MoinMoin.theme import ThemeBase -from MoinMoin import wikiutil, i18n -from MoinMoin.Page import Page - -class ThemeCrans(ThemeBase): - - name = "crans" - - # Standard set of style sheets - stylesheets = ( - # media basename - ('all', 'common'), - ('screen', 'crans'), - ('print', 'print'), - ('projection', 'projection'), - ) - - # Standard set of scripts - scripts = ( - 'crans', - ) - - -# Public functions ##################################################### - - def header(self, d, **kw): - """ Assemble wiki header - Here we don't add any menu bars, search bars, etc - instead wait - until the footer. This keeps the HTML cleaner and more accessible, - making sure the main content arrives first. - """ - if datetime.date.today().month == 10: - extra_style = " class=\"halloween\"" - elif (datetime.date.today().month == 12) and (datetime.date.today().day <= 24): - extra_style = " class=\"noel\"" - else: - extra_style = "" - parent = d['page'].getParentPage() - html = [ - u'

    ' % extra_style, - u'
    ', - u'
    ', - '

    ', - self.title(d), - u'

    ', - u'
    ', - self.msg(d), - self.startPage(), - ] - return u'\n'.join(html) - - editorheader = header - def footer(self, d, **keywords): - """ Assemble wiki footer - """ - html = [ - # End of page - self.pageinfo(d['page']), - self.endPage(), - u'
    ', # fin du div main-content - self.rightcolumn(d), - u'
    ', # fin du div globalWrapper - u'', # Campagne "Save A Developer. Upgrade Your Browser." - ] - return u'\n'.join(html) - - def rightcolumn(self, d): - """ assemble all the navigation aids for the page - """ - _ = self.request.getText - page = d['page'] - html = [ - u'
    ', - u"
    Personnel
    ", - self.username(d), - u"
    Navigation
    ", - self.navibar(d), - # hack : c1 and V1 or v2 c'est comme le code C : c1? v1 : V2 - # (si c1 est vrai alors prends la valeur V1 sinon prend la valeur c2 - self.shouldShowEditbar(d['page']) and u"
    %s
    " % _("Page") or u" ", - self.editbar(d), - u"
    %s
    " % _('Search'), - self.searchform(d), - #self.actionmenu(d), - #self.pageinfo(page), - self.credits(d), - ] - return u'\n'.join(html) - - def html_head(self, d): - """ add opensearch description to html head - """ - # common prefix for static content - prefix = self.cfg.url_prefix - open_search_desc = '\n\n' % {'page':d['page'].request.script_name, 'sitename':d['sitename']} - if (d['page'].isWritable() and - self.request.user.may.write(d['page'].page_name)): - edit_link = "/" + wikiutil.quoteWikinameURL(d['page'].page_name) + '?action=edit&editor=text' - wiki_rel = '\n' % edit_link - else: - wiki_rel = "" - - - classic_head = ThemeBase.html_head(self, d) - - return classic_head + open_search_desc + wiki_rel - - def headscript(self, d): - html = [] - # Check mode - if d.get('print_mode'): - link = "" - else: - # Create stylesheets links - link = '' - prefix = self.cfg.url_prefix - csshref = '%s/%s/js' % (prefix, self.name) - html = [] - for basename in self.scripts: - href = '%s/%s.js' % (csshref, basename) - html.append(link % href ) - - return ThemeBase.headscript(self, d) + u"\n".join(html) - - - - -class Theme(ThemeCrans): - - name = "crans" - - # Standard set of style sheets - stylesheets = ( - # media basename - ('all', 'common'), - ('screen', 'layout'), - ('screen', 'crans'), - ('print', 'print'), - ('projection', 'projection'), - ) - - - - - - - -def execute(request): - """ - Generate and return a theme object - - @param request: the request object - @rtype: MoinTheme - @return: Theme object - """ - return Theme(request) diff --git a/wiki/theme/ensanime.py b/wiki/theme/ensanime.py deleted file mode 100644 index 226d8168..00000000 --- a/wiki/theme/ensanime.py +++ /dev/null @@ -1,23 +0,0 @@ -from crans import ThemeCrans - -class Theme(ThemeCrans): - - # Standard set of style sheets - stylesheets = ( - # media basename - ('all', 'common'), - ('screen', 'layout'), - ('screen', 'ensanime'), - ('print', 'print'), - ('projection', 'projection'), - ) - -def execute(request): - """ - Generate and return a theme object - - @param request: the request object - @rtype: MoinTheme - @return: Theme object - """ - return Theme(request) diff --git a/wiki/theme/federez-www.py b/wiki/theme/federez-www.py deleted file mode 100644 index 0c1992f2..00000000 --- a/wiki/theme/federez-www.py +++ /dev/null @@ -1,507 +0,0 @@ -# -*- coding: iso-8859-1 -*- -""" - MoinMoin monobook theme. Uses the css sheet from - http://wikipedia.org, adapting the moin output to fit it. - - Adapted by Jim Clark - @license: GNU GPL, see COPYING for details. -""" - -from MoinMoin.theme import ThemeBase -from MoinMoin import wikiutil, i18n -from MoinMoin.Page import Page -from crans import ThemeCrans - -class Theme(ThemeBase): - icons = ThemeCrans.icons - - name = "crans-www" - - # Liste des feuilles de style - stylesheets = ( - # media basename - ('all', 'common'), - ('screen', 'layout'), - ('screen', 'federez'), - ('print', 'print'), -# ('projection', 'projection'), - ) - - # liste des liens du menu - menu_links = [ - # tire #lien - (u"Accueil", u"http://federez.crans.org/"), - ] - - # Chemin des badges - badgesPath = u'/wiki/common/badges/' - - # liste des badges - support_badges = [ - # page, # image # alt text - (u'http://www.mozilla-europe.org/fr/products/firefox/', u'badges_80x15_firefox.png', u'Get firefox'), - (u'http://www.debian.org/', u'badges_80x15_debian.png', u'Debian powered'), - (u'http://www.apache.org/', u'badges_80x15_apache.png', u'Apache powered'), - (u'http://www.python.org/', u'badges_80x15_python.png', u'Python powered'), - (u'http://www.federez.org/', u'badges_80x15_federez.png', u'Membre du réseau federeez'), - (u'http://moinmoin.wikiwikiweb.de/', u'badges_80x15_moinmoin.png', u'Moinmoin powered'), - (u'http://jigsaw.w3.org/css-validator/check?uri=referer&profile=css3&warning=no', u'valid_css_80x15.png', u'Valid css3'), -# (u'http://validator.w3.org/check?uri=referer', u'valid_html401_80x15.png', u'Valid html 4.01'), - ] - -# Public functions ##################################################### - - def header(self, d, **kw): - """ Assemble wiki header - Here we don't add any menu bars, search bars, etc - instead wait - until the footer. This keeps the HTML cleaner and more accessible, - making sure the main content arrives first. - """ - parent = d['page'].getParentPage() - title = [ - self.title(d)[:-6], # On enlève - parent and wikiutil.link_tag(self.request, - parent.page_name, - u'Haut') or u'', - u'' - ] - html = [ - u'
    ', - self.logo(), - u'
    ', - self.startPage(), - ] - - - if d['page'].page_name != 'VieCrans' : - html += title - html += [self.msg(d)] - return u'\n'.join(html) - - def footer(self, d, **keywords): - """ Assemble wiki footer - """ - html = [ - # End of page - u'
    ', - self.endPage(), - u'
    ', - u'
    ', - self.menu(d), - u'
    ', - self.username(d), - self.badges(d), - ] - return u'\n'.join(html) - - def menu(self, d): - """ assemble all the navigation aids for the page - """ - liens = [] - for titre, lien in self.menu_links: - liens.append(u'
  • %s
  • ' % (lien, titre)) - html = [ - u'', - ] - return u''.join(html) - - def badges(self,d ): - badges_html = [] - for page, image, alt_text in self.support_badges: - badges_html.append(u'
  • %(alt)s
  • ' % {'href':page, 'path':self.badgesPath, 'image':image, 'alt':alt_text}) - html = [ - u'
      ', - u'\n'.join(badges_html), - u'
    \n\n', - ] - - return u''.join(html) - - def searchform(self, d): - """ assemble HTML code for the search form - Tweaks from the bass class to wrap in a 'portlet' class, move the - description to a header tag, add an access key of 'f' and - add SearchButton class for the buttons - """ - _ = self.request.getText - form = self.request.form - updates = { - 'search_label' : _('Search:'), - 'search_value': wikiutil.escape(form.get('value', [''])[0], 1), - 'search_full_label' : _('Text', formatted=False), - 'search_title_label' : _('Titles', formatted=False), - } - d.update(updates) - - html = u''' -
    -
    -
    - - -
    - - -
    -
    - ''' % d - return html - - - - def columnone(self, d): - """ assemble all the navigation aids for the page - """ - page = d['page'] - html = [ - u'
    ', - self.editbar(d), - self.username(d), - u'', - self.navibar(d), - self.searchform(d), - self.actionmenu(d), - u'
    ', - u'', - u'
    ' - ] - return u'\n'.join(html) - - def headscript(self, d): - """ Override to not output search/action menu javascript. - (perhaps not a good idea) - """ - return '' - - def extendedAttrs(self, title, accesskey): - """ Helper function for assembling titled access key links - """ - return 'title="%(title)s [alt-%(accesskey)s]" accesskey=%(accesskey)s' % \ - {'accesskey' : accesskey, - 'title' : title} - - def editbar(self, d): - """ Display a list of actions for the page. This list will be turned - into a set of tabbed views on the page by the css. - """ - page = d['page'] - if not self.shouldShowEditbar(page): - return '' - - # Use cached editbar if possible. - cacheKey = 'editbar' - cached = self._cache.get(cacheKey) - if cached: - return cached - - request = self.request - _ = self.request.getText - link = wikiutil.link_tag - quotedname = wikiutil.quoteWikinameURL(page.page_name) - # action, title, description, accesskey - tabs = [('show', 'Article', 'View the page content', 'c'), - ('edit', 'Edit', 'Edit this page', 'e'), - ('diff', 'Show Changes', 'Last page modification', 'd'), - ('info', 'Get Info', 'Page history and information', 'h'), - ('subscribe', 'Subscribe', 'Subscribe to updates to this page', 'w')] - - items = [] - current = self.request.form.get('action', ['show'])[0] - for action, title, description, accesskey in tabs: - if action == current: - cls = 'selected' - else: - cls = 'none' - - if action == 'edit': - if page.isWritable() and request.user.may.write(page.page_name): - pass - else: - action = 'raw' - title = 'View Source' - description = 'This page is protected. You can view its source' - - if action == 'subscribe': - user = self.request.user - if not self.cfg.mail_smarthost or not user.valid: - break - # Email enabled and user valid, get current page status - if user.isSubscribedTo([page.page_name]): - title = 'Unsubscribe' - description = 'Unsubscribe from updates to this page' - - if action == 'show': - url = quotedname - else: - url = quotedname + '?action=' + action - - attrs = self.extendedAttrs(_(description), accesskey) - link = wikiutil.link_tag(self.request, url, _(title), attrs=attrs) - items.append(u'
  • %s
  • ' % (cls, link)) - - html = [ - u'
    ', - u'
      ', - ''.join(items), - u'
    ', - u'
    ' - ] - html = ''.join(html) - # cache for next call - self._cache[cacheKey] = html - - return html - - - def actionmenu(self, d): - """ different implementation of the actionmenu (aka toolbox) - """ - - page = d['page'] - - # Use cached actionmenu if possible. - cacheKey = 'actionmenu' - cached = self._cache.get(cacheKey) - if cached: - return cached - - request = self.request - _ = request.getText - quotedname = wikiutil.quoteWikinameURL(page.page_name) - - menu = [ - 'raw', - 'print', - 'refresh', - 'AttachFile', - 'SpellCheck', - 'LikePages', - 'LocalSiteMap', - 'RenamePage', - 'DeletePage', - ] - - titles = { - 'raw': _('Show Raw Text', formatted=False), - 'print': _('Show Print View', formatted=False), - 'refresh': _('Delete Cache', formatted=False), - 'AttachFile': _('Attach File', formatted=False), - 'SpellCheck': _('Check Spelling', formatted=False), # rename action! - 'RenamePage': _('Rename Page', formatted=False), - 'DeletePage': _('Delete Page', formatted=False), - 'LikePages': _('Show Like Pages', formatted=False), - 'LocalSiteMap': _('Show Local Site Map', formatted=False), - } - - links = [] - - # Format standard actions - available = request.getAvailableActions(page) - for action in menu: - # Enable delete cache only if page can use caching - if action == 'refresh': - if not page.canUseCache(): - break - # Actions which are not available for this wiki, user or page - if action[0].isupper() and not action in available: - break; - - link = wikiutil.link_tag(self.request, \ - quotedname + '?action=' + action, titles[action]) - links.append(link) - - # Add custom actions not in the standard menu - more = [item for item in available if not item in titles] - more.sort() - if more: - # Add more actions (all enabled) - for action in more: - data = {'action': action, 'disabled': ''} - title = Page(request, action).split_title(request, force=1) - # Use translated version if available - title = _(title, formatted=False) - link = wikiutil.link_tag(self.request, \ - quotedname + '?action=' + action, title) - links.append(link) - - html = [ - u'
    ', - u'
    Toolbox
    ', - u'
    ', - u'
      ', - u'
    • %s
    ' % '\n
  • '.join(links), - u'', - u'
  • ', - u'
    ', - ] - html = ''.join(html) - # cache for next call - self._cache[cacheKey] = html - return html - - - def username(self, d): - """ Assemble the username / userprefs link - Copied from the base class, modified to include hotkeys and link titles - """ - from MoinMoin.Page import Page - request = self.request - _ = request.getText - - userlinks = [] - # Add username/homepage link for registered users. We don't care - # if it exists, the user can create it. - if request.user.valid: - homepage = Page(request, request.user.name) - title = homepage.split_title(request) - attrs = self.extendedAttrs(_('User Page'), '.') - homelink = homepage.link_to(request, text=title, attrs=attrs) - userlinks.append(homelink) - - # Set pref page to localized Preferences page - attrs = self.extendedAttrs(_('My Preferences'), 'u') - prefpage = wikiutil.getSysPage(request, 'UserPreferences') - title = prefpage.split_title(request) - userlinks.append(prefpage.link_to(request, text=title, attrs=attrs)) - - # Add a logout link (not sure this is really necessary - attrs = self.extendedAttrs(_('log out'), 'o') - page = d['page'] - url = wikiutil.quoteWikinameURL(page.page_name) + \ - '?action=userform&logout=1' - link = wikiutil.link_tag(self.request, url, 'log out', attrs=attrs) - userlinks.append(link) - - else: - # Add prefpage links with title: Login -# prefpage = wikiutil.getSysPage(request, 'UserPreferences') -# attrs = self.extendedAttrs('Logging in is not required, but brings benefits', 'o') -# userlinks.append(prefpage.link_to(request, text=_("Login"), attrs=attrs)) - url = u'http://wiki.crans.org/%s' % d['page'].page_name - link = u'%s' % ( url, 'Version Wiki') - userlinks.append(link) - - html = [ - u'
    ', - u'
      ', - u'
    • %s
    • ' % '\n
    • '.join(userlinks), - u'
    ', - u'
    ' - ] - return ''.join(html) - - - def shouldShowEditbar(self, page): - """ Override to include the editbar on edit/preview pages. - (at the risk that the user may accidentally cancel an edit) - """ - return False - - - def navibar(self, d): - """ Alterations from the base class to include access keys and - descriptions for FrontPage/RecentChanges - """ - request = self.request - found = {} # pages we found. prevent duplicates - links = [] # navibar items - current = d['page_name'] - - # Process config navi_bar - if request.cfg.navi_bar: - for text in request.cfg.navi_bar: - pagename, link = self.splitNavilink(text) - if pagename == d['page_front_page']: - attrs = self.extendedAttrs('Visit the main page', 'z') - elif pagename == 'RecentChanges': - attrs = self.extendedAttrs('List of recent changes in this wiki', 'r') - else: - attrs = '' - - a = wikiutil.link_tag(request, pagename, attrs=attrs) - links.append(a) - found[pagename] = 1 - - # Add user links to wiki links, eliminating duplicates. - userlinks = request.user.getQuickLinks() - for text in userlinks: - # Split text without localization, user know what she wants - pagename, link = self.splitNavilink(text, localize=0) - if not pagename in found: - a = wikiutil.link_tag(request, pagename, attrs=attrs) - links.append(a) - found[pagename] = 1 - - html = [ - u'', - ] - return ''.join(html) - - def pageinfo(self, page): - """ Simple override from base class. - Remove

    so footer isn't too big - """ - _ = self.request.getText - - if self.shouldShowPageinfo(page): - info = page.lastEditInfo() - if info: - if info['editor']: - info = _("last edited %(time)s by %(editor)s") % info - else: - info = _("last modified %(time)s") % info - return info - return '' - - def rtl_stylesheet(self, d): - """ monobook uses a separate css page for rtl alterations. - Add the rtl stylesheet if the user needs it - """ - link = ('') - html = [] - if i18n.getDirection(self.request.lang) == 'rtl': - prefix = self.cfg.url_prefix - href = '%s/%s/css/%s.css' % (prefix, self.name, 'rtl') - html.append(link % (self.stylesheetsCharset, 'all', href)) - return '\n'.join(html) - - def html_head(self, d): - """ Tweak the sending of the head, to include right-to-left - alterations if necessary - """ - html = [ - u".:: CRANS : Cachan / Réseau @ Normale Sup' ::.", - self.headscript(d), # Should move to separate .js file - self.html_stylesheets(d), - self.rtl_stylesheet(d), - self.rsslink(), - ] - return '\n'.join(html) - -def execute(request): - """ - Generate and return a theme object - - @param request: the request object - @rtype: MoinTheme - @return: Theme object - """ - return Theme(request) diff --git a/wiki/theme/federez.py b/wiki/theme/federez.py deleted file mode 100644 index bbb6869c..00000000 --- a/wiki/theme/federez.py +++ /dev/null @@ -1,39 +0,0 @@ -# -*- coding: iso-8859-1 -*- -""" - MoinMoin monobook theme. Uses the css sheet from - http://wikipedia.org, adapting the moin output to fit it. - - Adapted by Jim Clark - Adapted for CR@NS by Nicolas Salles - @license: GNU GPL, see COPYING for details. -""" - -from MoinMoin.theme import ThemeBase -from MoinMoin import wikiutil, i18n -from MoinMoin.Page import Page -from crans import ThemeCrans - -class Theme(ThemeCrans): - - name = "crans" - - # Standard set of style sheets - stylesheets = ( - # media basename - ('all', 'common'), - ('screen', 'layout'), - ('screen', 'federez'), - ('print', 'print'), - ('projection', 'projection'), - ) - - -def execute(request): - """ - Generate and return a theme object - - @param request: the request object - @rtype: MoinTheme - @return: Theme object - """ - return Theme(request) diff --git a/wiki/theme/movieclub.py b/wiki/theme/movieclub.py deleted file mode 100644 index bbfc8f02..00000000 --- a/wiki/theme/movieclub.py +++ /dev/null @@ -1,31 +0,0 @@ -# -*- coding: iso-8859-1 -*- -""" - Theme Movieclub, sous classe de Crans. - -""" - - -from crans import ThemeCrans - -class Theme(ThemeCrans): - - - # Standard set of style sheets - stylesheets = ( - # media basename - ('all', 'common'), - ('screen', 'layout'), - ('screen', 'movieclub'), - ('print', 'print'), - ('projection', 'projection'), - ) - -def execute(request): - """ - Generate and return a theme object - - @param request: the request object - @rtype: MoinTheme - @return: Theme object - """ - return Theme(request) diff --git a/wiki/user.py b/wiki/user.py deleted file mode 100644 index 22648403..00000000 --- a/wiki/user.py +++ /dev/null @@ -1,997 +0,0 @@ -# -*- coding: iso-8859-1 -*- -""" - MoinMoin - User Accounts - - @copyright: 2000-2004 by Jürgen Hermann - @license: GNU GPL, see COPYING for details. -""" - -import os, time, sha, codecs, re - -try: - import cPickle as pickle -except ImportError: - import pickle - -# Set pickle protocol, see http://docs.python.org/lib/node64.html -PICKLE_PROTOCOL = pickle.HIGHEST_PROTOCOL - -from MoinMoin import config, caching, wikiutil -from MoinMoin.util import filesys, timefuncs - -USERID_re = re.compile(r'^\d+\.\d+(\.\d+)?$') - -def getUserList(request): - """ Get a list of all (numerical) user IDs. - - @param request: current request - @rtype: list - @return: all user IDs - """ - import dircache - files = dircache.listdir(request.cfg.user_dir) - userlist = [f for f in files if USERID_re.match(f)] - return userlist - - -def getUserId(request, searchName): - """ - Get the user ID for a specific user NAME. - - @param searchName: the user name to look up - @rtype: string - @return: the corresponding user ID or None - """ - if not searchName: - return None - cfg = request.cfg - try: - _name2id = cfg._name2id - except AttributeError: - arena = 'user' - key = 'name2id' - cache = caching.CacheEntry(request, arena, key) - try: - _name2id = pickle.loads(cache.content()) - except (pickle.UnpicklingError, IOError, EOFError, ValueError): - _name2id = {} - cfg._name2id = _name2id - id = _name2id.get(searchName, None) - if id is None: - for userid in getUserList(request): - name = User(request, id=userid).name - _name2id[name] = userid - cfg._name2id = _name2id - arena = 'user' - key = 'name2id' - cache = caching.CacheEntry(request, arena, key) - cache.update(pickle.dumps(_name2id, PICKLE_PROTOCOL)) - id = _name2id.get(searchName, None) - return id - - -def getUserIdentification(request, username=None): - """ - Return user name or IP or '' indicator. - - @param request: the request object - @param username: (optional) user name - @rtype: string - @return: user name or IP or unknown indicator - """ - _ = request.getText - - if username is None: - username = request.user.name - - return username or (request.cfg.show_hosts and request.remote_addr) or _("") - - -def encodePassword(pwd, charset='utf-8'): - """ Encode a cleartext password - - Compatible to Apache htpasswd SHA encoding. - - When using different encoding than 'utf-8', the encoding might fail - and raise UnicodeError. - - @param pwd: the cleartext password, (unicode) - @param charset: charset used to encode password, used only for - compatibility with old passwords generated on moin-1.2. - @rtype: string - @return: the password in apache htpasswd compatible SHA-encoding, - or None - """ - import base64 - - # Might raise UnicodeError, but we can't do anything about it here, - # so let the caller handle it. - pwd = pwd.encode(charset) - - pwd = sha.new(pwd).digest() - pwd = '{SHA}' + base64.encodestring(pwd).rstrip() - return pwd - - -def normalizeName(name): - """ Make normalized user name - - Prevent impersonating another user with names containing leading, - trailing or multiple whitespace, or using invisible unicode - characters. - - Prevent creating user page as sub page, because '/' is not allowed - in user names. - - Prevent using ':' and ',' which are reserved by acl. - - @param name: user name, unicode - @rtype: unicode - @return: user name that can be used in acl lines - """ - name = name.replace('_', ' ') # we treat _ as a blank - username_allowedchars = "'@." # ' for names like O'Brian or email addresses. - # "," and ":" must not be allowed (ACL delimiters). - # Strip non alpha numeric characters (except username_allowedchars), keep white space - name = ''.join([c for c in name if c.isalnum() or c.isspace() or c in username_allowedchars]) - - # Normalize white space. Each name can contain multiple - # words separated with only one space. - name = ' '.join(name.split()) - - return name - - -def isValidName(request, name): - """ Validate user name - - @param name: user name, unicode - """ - normalized = normalizeName(name) - name = name.replace('_', ' ') # we treat _ as a blank - #### HACK CRANS - #return (name == normalized) and not wikiutil.isGroupPage(request, name) - return not name or ((name == normalized) \ - and not wikiutil.isGroupPage(request, name) - and wikiutil.isStrictWikiname(name)) - #### HACK CRANS - - -def encodeList(items): - """ Encode list of items in user data file - - Items are separated by '\t' characters. - - @param items: list unicode strings - @rtype: unicode - @return: list encoded as unicode - """ - line = [] - for item in items: - item = item.strip() - if not item: - continue - line.append(item) - - line = '\t'.join(line) - return line - - -def decodeList(line): - """ Decode list of items from user data file - - @param line: line containing list of items, encoded with encodeList - @rtype: list of unicode strings - @return: list of items in encoded in line - """ - items = [] - for item in line.split('\t'): - item = item.strip() - if not item: - continue - items.append(item) - return items - - -class User: - """A MoinMoin User""" - - def __init__(self, request, id=None, name="", password=None, auth_username="", **kw): - """ Initialize User object - - @param request: the request object - @param id: (optional) user ID - @param name: (optional) user name - @param password: (optional) user password - @param auth_username: (optional) already authenticated user name - (e.g. when using http basic auth) - @keyword auth_method: method that was used for authentication, - default: 'internal' - @keyword auth_attribs: tuple of user object attribute names that are - determined by auth method and should not be - changed by UserPreferences form, default: (). - First tuple element was used for authentication. - """ - self._cfg = request.cfg - self.valid = 0 - self.trusted = 0 - self.id = self.id_sanitycheck(id) - self.auth_username = auth_username - self.auth_method = kw.get('auth_method', 'internal') - self.auth_attribs = kw.get('auth_attribs', ()) - - # create some vars automatically - for tuple in self._cfg.user_form_fields: - key = tuple[0] - default = self._cfg.user_form_defaults.get(key, '') - setattr(self, key, default) - - if name: - self.name = name - elif auth_username: # this is needed for user_autocreate - self.name = auth_username - - # create checkbox fields (with default 0) - for key, label in self._cfg.user_checkbox_fields: - setattr(self, key, self._cfg.user_checkbox_defaults.get(key, 0)) - - self.enc_password = "" - if password: - if password.startswith('{SHA}'): - self.enc_password = password - else: - try: - self.enc_password = encodePassword(password) - except UnicodeError: - pass # Should never happen - - #self.edit_cols = 80 - self.tz_offset = int(float(self._cfg.tz_offset) * 3600) - self.language = "" - self.date_fmt = "" - self.datetime_fmt = "" - self.quicklinks = [] - self.subscribed_pages = [] - self.theme_name = self._cfg.theme_default - self.editor_default = self._cfg.editor_default - self.editor_ui = self._cfg.editor_ui - self.last_saved = str(time.time()) - - # attrs not saved to profile - self._request = request - self._trail = [] - - # we got an already authenticated username: - check_pass = 0 - if not self.id and self.auth_username: - self.id = getUserId(request, self.auth_username) - if not password is None: - check_pass = 1 - if self.id: - self.load_from_id(check_pass) - if self.name == self.auth_username: - self.trusted = 1 - elif self.name: - self.id = getUserId(self._request, self.name) - if self.id: - self.load_from_id(1) - else: - self.id = self.make_id() - else: - self.id = self.make_id() - - # "may" so we can say "if user.may.read(pagename):" - if self._cfg.SecurityPolicy: - self.may = self._cfg.SecurityPolicy(self) - else: - from security import Default - self.may = Default(self) - - from MoinMoin.i18n.meta import languages - if self.language and not languages.has_key(self.language): - self.language = 'en' - - def __repr__(self): - return "<%s.%s at 0x%x name:%r id:%s valid:%r>" % ( - self.__class__.__module__, self.__class__.__name__, - id(self), self.name, self.id, self.valid) - - def make_id(self): - """ make a new unique user id """ - #!!! this should probably be a hash of REMOTE_ADDR, HTTP_USER_AGENT - # and some other things identifying remote users, then we could also - # use it reliably in edit locking - from random import randint - return "%s.%d" % (str(time.time()), randint(0,65535)) - - def id_sanitycheck(self, id): - """ only return valid user IDs, avoid someone faking his cookie to - contain '../../../somefile', breaking out of the data/user/ directory! - """ - if id and USERID_re.match(id): - return id - else: - return None - - def create_or_update(self, changed=False): - """ Create or update a user profile - - @param changed: bool, set this to True if you updated the user profile values - """ - if self._cfg.user_autocreate: - if not self.valid and not self.disabled or changed: # do we need to save/update? - self.save() # yes, create/update user profile - - def __filename(self): - """ Get filename of the user's file on disk - - @rtype: string - @return: full path and filename of user account file - """ - return os.path.join(self._cfg.user_dir, self.id or "...NONE...") - - def __bookmark_filename(self): - if self._cfg.interwikiname: - return (self.__filename() + "." + self._cfg.interwikiname + - ".bookmark") - else: - return self.__filename() + ".bookmark" - - def exists(self): - """ Do we have a user account for this user? - - @rtype: bool - @return: true, if we have a user account - """ - return os.path.exists(self.__filename()) - - def load_from_id(self, check_pass=0): - """ Load user account data from disk. - - Can only load user data if the id number is already known. - - This loads all member variables, except "id" and "valid" and - those starting with an underscore. - - @param check_pass: If 1, then self.enc_password must match the - password in the user account file. - """ - if not self.exists(): - return - - data = codecs.open(self.__filename(), "r", config.charset).readlines() - user_data = {'enc_password': ''} - for line in data: - if line[0] == '#': - continue - - try: - key, val = line.strip().split('=', 1) - if key not in self._cfg.user_transient_fields and key[0] != '_': - # Decode list values - if key in ['quicklinks', 'subscribed_pages']: - val = decodeList(val) - user_data[key] = val - except ValueError: - pass - - # Validate data from user file. In case we need to change some - # values, we set 'changed' flag, and later save the user data. - changed = 0 - - if check_pass: - # If we have no password set, we don't accept login with username - if not user_data['enc_password']: - return - # Check for a valid password, possibly changing encoding - valid, changed = self._validatePassword(user_data) - if not valid: - return - else: - self.trusted = 1 - - # Remove ignored checkbox values from user data - for key, label in self._cfg.user_checkbox_fields: - if user_data.has_key(key) and key in self._cfg.user_checkbox_disable: - del user_data[key] - - # Copy user data into user object - for key, val in user_data.items(): - vars(self)[key] = val - - self.tz_offset = int(self.tz_offset) - - # Remove old unsupported attributes from user data file. - remove_attributes = ['passwd', 'show_emoticons'] - for attr in remove_attributes: - if hasattr(self, attr): - delattr(self, attr) - changed = 1 - - # make sure checkboxes are boolean - for key, label in self._cfg.user_checkbox_fields: - try: - setattr(self, key, int(getattr(self, key))) - except ValueError: - setattr(self, key, 0) - - # convert (old) hourly format to seconds - if -24 <= self.tz_offset and self.tz_offset <= 24: - self.tz_offset = self.tz_offset * 3600 - - # clear trail - self._trail = [] - - if not self.disabled: - self.valid = 1 - - # If user data has been changed, save fixed user data. - if changed: - self.save() - - def _validatePassword(self, data): - """ Try to validate user password - - This is a private method and should not be used by clients. - - In pre 1.3, the wiki used some 8 bit charset. The user password - was entered in this 8 bit password and passed to - encodePassword. So old passwords can use any of the charset - used. - - In 1.3, we use unicode internally, so we encode the password in - encodePassword using utf-8. - - When we compare passwords we must compare with same encoding, or - the passwords will not match. We don't know what encoding the - password on the user file uses. We may ask the wiki admin to put - this into the config, but he may be wrong. - - The way chosen is to try to encode and compare passwords using - all the encoding that were available on 1.2, until we get a - match, which means that the user is valid. - - If we get a match, we replace the user password hash with the - utf-8 encoded version, and next time it will match on first try - as before. The user password did not change, this change is - completely transparent for the user. Only the sha digest will - change. - - @param data: dict with user data - @rtype: 2 tuple (bool, bool) - @return: password is valid, password did change - """ - # First try with default encoded password. Match only non empty - # passwords. (require non empty enc_password) - if self.enc_password and self.enc_password == data['enc_password']: - return True, False - - # Try to match using one of pre 1.3 8 bit charsets - - # Get the clear text password from the form (require non empty - # password) - password = self._request.form.get('password',[None])[0] - if not password: - return False, False - - # First get all available pre13 charsets on this system - pre13 = ['iso-8859-1', 'iso-8859-2', 'euc-jp', 'gb2312', 'big5',] - available = [] - for charset in pre13: - try: - encoder = codecs.getencoder(charset) - available.append(charset) - except LookupError: - pass # missing on this system - - # Now try to match the password - for charset in available: - # Try to encode, failure is expected - try: - enc_password = encodePassword(password, charset=charset) - except UnicodeError: - continue - - # And match (require non empty enc_password) - if enc_password and enc_password == data['enc_password']: - # User password match - replace the user password in the - # file with self.password - data['enc_password'] = self.enc_password - return True, True - - # No encoded password match, this must be wrong password - return False, False - - def save(self): - """ Save user account data to user account file on disk. - - This saves all member variables, except "id" and "valid" and - those starting with an underscore. - """ - if not self.id: - return - - user_dir = self._cfg.user_dir - filesys.makeDirs(user_dir) - - self.last_saved = str(time.time()) - - # !!! should write to a temp file here to avoid race conditions, - # or even better, use locking - - data = codecs.open(self.__filename(), "w", config.charset) - data.write("# Data saved '%s' for id '%s'\n" % ( - time.strftime(self._cfg.datetime_fmt, time.localtime(time.time())), - self.id)) - attrs = vars(self).items() - attrs.sort() - for key, value in attrs: - if key not in self._cfg.user_transient_fields and key[0] != '_': - # Encode list values - if key in ['quicklinks', 'subscribed_pages']: - value = encodeList(value) - line = u"%s=%s\n" % (key, unicode(value)) - data.write(line) - data.close() - - try: - os.chmod(self.__filename(), 0666 & config.umask) - except OSError: - pass - - if not self.disabled: - self.valid = 1 - - # ----------------------------------------------------------------- - # Time and date formatting - - def getTime(self, tm): - """ Get time in user's timezone. - - @param tm: time (UTC UNIX timestamp) - @rtype: int - @return: tm tuple adjusted for user's timezone - """ - return timefuncs.tmtuple(tm + self.tz_offset) - - - def getFormattedDate(self, tm): - """ Get formatted date adjusted for user's timezone. - - @param tm: time (UTC UNIX timestamp) - @rtype: string - @return: formatted date, see cfg.date_fmt - """ - date_fmt = self.date_fmt or self._cfg.date_fmt - return time.strftime(date_fmt, self.getTime(tm)) - - - def getFormattedDateTime(self, tm): - """ Get formatted date and time adjusted for user's timezone. - - @param tm: time (UTC UNIX timestamp) - @rtype: string - @return: formatted date and time, see cfg.datetime_fmt - """ - datetime_fmt = self.datetime_fmt or self._cfg.datetime_fmt - return time.strftime(datetime_fmt, self.getTime(tm)) - - # ----------------------------------------------------------------- - # Bookmark - - def setBookmark(self, tm): - """ Set bookmark timestamp. - - @param tm: timestamp - """ - if self.valid: - bm_fn = self.__bookmark_filename() - bmfile = open(bm_fn, "w") - bmfile.write(str(tm)+"\n") - bmfile.close() - try: - os.chmod(bm_fn, 0666 & config.umask) - except OSError: - pass - - def getBookmark(self): - """ Get bookmark timestamp. - - @rtype: int - @return: bookmark timestamp or None - """ - bm = None - bm_fn = self.__bookmark_filename() - - if self.valid and os.path.exists(bm_fn): - try: - bm = long(open(bm_fn, 'r').readline()) # must be long for py 2.2 - except (OSError, ValueError): - pass - return bm - - def delBookmark(self): - """ Removes bookmark timestamp. - - @rtype: int - @return: 0 on success, 1 on failure - """ - bm_fn = self.__bookmark_filename() - if self.valid: - if os.path.exists(bm_fn): - try: - os.unlink(bm_fn) - except OSError: - return 1 - return 0 - return 1 - - # ----------------------------------------------------------------- - # Subscribe - - def getSubscriptionList(self): - """ Get list of pages this user has subscribed to - - @rtype: list - @return: pages this user has subscribed to - """ - return self.subscribed_pages - - def isSubscribedTo(self, pagelist): - """ Check if user subscription matches any page in pagelist. - - The subscription list may contain page names or interwiki page - names. e.g 'Page Name' or 'WikiName:Page_Name' - - TODO: check if its fast enough when calling with many users - from page.getSubscribersList() - - @param pagelist: list of pages to check for subscription - @rtype: bool - @return: if user is subscribed any page in pagelist - """ - if not self.valid: - return False - - import re - # Create a new list with both names and interwiki names. - pages = pagelist[:] - if self._cfg.interwikiname: - pages += [self._interWikiName(pagename) for pagename in pagelist] - # Create text for regular expression search - text = '\n'.join(pages) - - for pattern in self.getSubscriptionList(): - # Try simple match first - if pattern in pages: - return True - # Try regular expression search, skipping bad patterns - try: - pattern = re.compile(r'^%s$' % pattern, re.M) - except re.error: - continue - if pattern.search(text): - return True - - return False - - def subscribe(self, pagename): - """ Subscribe to a wiki page. - - To enable shared farm users, if the wiki has an interwiki name, - page names are saved as interwiki names. - - @param pagename: name of the page to subscribe - @type pagename: unicode - @rtype: bool - @return: if page was subscribed - """ - if self._cfg.interwikiname: - pagename = self._interWikiName(pagename) - - if pagename not in self.subscribed_pages: - self.subscribed_pages.append(pagename) - self.save() - return True - - return False - - def unsubscribe(self, pagename): - """ Unsubscribe a wiki page. - - Try to unsubscribe by removing non-interwiki name (leftover - from old use files) and interwiki name from the subscription - list. - - Its possible that the user will be subscribed to a page by more - then one pattern. It can be both pagename and interwiki name, - or few patterns that all of them match the page. Therefore, we - must check if the user is still subscribed to the page after we - try to remove names from the list. - - TODO: should we remove non-interwiki subscription? what if the - user want to subscribe to the same page in multiple wikis? - - @param pagename: name of the page to subscribe - @type pagename: unicode - @rtype: bool - @return: if unsubscrieb was successful. If the user has a - regular expression that match, it will always fail. - """ - changed = False - if pagename in self.subscribed_pages: - self.subscribed_pages.remove(pagename) - changed = True - - interWikiName = self._interWikiName(pagename) - if interWikiName and interWikiName in self.subscribed_pages: - self.subscribed_pages.remove(interWikiName) - changed = True - - if changed: - self.save() - return not self.isSubscribedTo([pagename]) - - # ----------------------------------------------------------------- - # Quicklinks - - def getQuickLinks(self): - """ Get list of pages this user wants in the navibar - - @rtype: list - @return: quicklinks from user account - """ - return self.quicklinks - - def isQuickLinkedTo(self, pagelist): - """ Check if user quicklink matches any page in pagelist. - - @param pagelist: list of pages to check for quicklinks - @rtype: bool - @return: if user has quicklinked any page in pagelist - """ - if not self.valid: - return False - - for pagename in pagelist: - if pagename in self.quicklinks: - return True - interWikiName = self._interWikiName(pagename) - if interWikiName and interWikiName in self.quicklinks: - return True - - return False - - def addQuicklink(self, pagename): - """ Adds a page to the user quicklinks - - If the wiki has an interwiki name, all links are saved as - interwiki names. If not, as simple page name. - - @param pagename: page name - @type pagename: unicode - @rtype: bool - @return: if pagename was added - """ - changed = False - interWikiName = self._interWikiName(pagename) - if interWikiName: - if pagename in self.quicklinks: - self.quicklinks.remove(pagename) - changed = True - if interWikiName not in self.quicklinks: - self.quicklinks.append(interWikiName) - changed = True - else: - if pagename not in self.quicklinks: - self.quicklinks.append(pagename) - changed = True - - if changed: - self.save() - return changed - - def removeQuicklink(self, pagename): - """ Remove a page from user quicklinks - - Remove both interwiki and simple name from quicklinks. - - @param pagename: page name - @type pagename: unicode - @rtype: bool - @return: if pagename was removed - """ - changed = False - interWikiName = self._interWikiName(pagename) - if interWikiName and interWikiName in self.quicklinks: - self.quicklinks.remove(interWikiName) - changed = True - if pagename in self.quicklinks: - self.quicklinks.remove(pagename) - changed = True - - if changed: - self.save() - return changed - - def _interWikiName(self, pagename): - """ Return the inter wiki name of a page name - - @param pagename: page name - @type pagename: unicode - """ - if not self._cfg.interwikiname: - return None - - # Interwiki links must use _ e.g Wiki:Main_Page - pagename = pagename.replace(" ", "_") - return "%s:%s" % (self._cfg.interwikiname, pagename) - - # ----------------------------------------------------------------- - # Trail - - def addTrail(self, pagename): - """ Add page to trail. - - @param pagename: the page name to add to the trail - """ - # TODO: acquire lock here, so multiple processes don't clobber - # each one trail. - - if self.valid and (self.show_page_trail or self.remember_last_visit): - # load trail if not known - self.getTrail() - - # Add only existing pages that the user may read - if self._request: - from MoinMoin.Page import Page - page = Page(self._request, pagename) - if not (page.exists() and - self._request.user.may.read(page.page_name)): - return - - # Save interwiki links internally - if self._cfg.interwikiname: - pagename = self._interWikiName(pagename) - - # Don't append tail to trail ;) - if self._trail and self._trail[-1] == pagename: - return - - # Append new page, limiting the length - self._trail = [p for p in self._trail if p != pagename] - self._trail = self._trail[-(self._cfg.trail_size-1):] - self._trail.append(pagename) - self.saveTrail() - - # TODO: release lock here - - def saveTrail(self): - """ Save trail file - - Save using one write call, which should be fine in most cases, - but will fail in rare cases without real file locking. - """ - data = '\n'.join(self._trail) + '\n' - path = self.__filename() + ".trail" - try: - file = codecs.open(path, "w", config.charset) - try: - file.write(data) - finally: - file.close() - - try: - os.chmod(path, 0666 & config.umask) - except OSError, err: - self._request.log("Can't change mode of trail file: %s" % - str(err)) - except (IOError, OSError), err: - self._request.log("Can't save trail file: %s" % str(err)) - - def getTrail(self): - """ Return list of recently visited pages. - - @rtype: list - @return: pages in trail - """ - if self.valid and (self.show_page_trail or self.remember_last_visit) \ - and not self._trail \ - and os.path.exists(self.__filename() + ".trail"): - try: - trail = codecs.open(self.__filename() + ".trail", 'r', config.charset).readlines() - except (OSError, ValueError): - trail = [] - trail = [t.strip() for t in trail] - trail = [t for t in trail if t] - self._trail = trail[-self._cfg.trail_size:] - - return self._trail - - # ----------------------------------------------------------------- - # Other - - def isCurrentUser(self): - return self._request.user.name == self.name - - def isSuperUser(self): - superusers = self._request.cfg.superuser - assert isinstance(superusers, (list, tuple)) - return self.valid and self.name and self.name in superusers - - def host(self): - """ Return user host """ - _ = self._request.getText - host = self.isCurrentUser() and self._cfg.show_hosts and self._request.remote_addr - return host or _("") - - def signature(self): - """ Return user signature using markup - - Users sign with a link to their homepage, or with text if they - don't have one. The text may be parsed as a link if it's using - CamelCase. Visitors return their host address. - - TODO: The signature use wiki format only, for example, it will - not create a link when using rst format. It will also break if - we change wiki syntax. - """ - if not self.name: - return self.host() - - wikiname, pagename = wikiutil.getInterwikiHomePage(self._request, - self.name) - if wikiname == 'Self': - if not wikiutil.isStrictWikiname(self.name): - markup = '["%s"]' % pagename - else: - markup = pagename - else: - markup = '%s:%s' % (wikiname, pagename.replace(" ","_")) - return markup - - def mailAccountData(self, cleartext_passwd=None): - from MoinMoin.util import mail - from MoinMoin.wikiutil import getSysPage - _ = self._request.getText - - if not self.enc_password: # generate pw if there is none yet - from random import randint - import base64 - - charset = 'utf-8' - pwd = "%s%d" % (str(time.time()), randint(0, 65535)) - pwd = pwd.encode(charset) - - pwd = sha.new(pwd).digest() - pwd = '{SHA}%s' % base64.encodestring(pwd).rstrip() - - self.enc_password = pwd - self.save() - - text = '\n' + _("""\ -Login Name: %s - -Login Password: %s - -Login URL: %s/%s -""", formatted=False) % ( - self.name, self.enc_password, self._request.getBaseURL(), getSysPage(self._request, 'UserPreferences').page_name) - - text = _("""\ -Somebody has requested to submit your account data to this email address. - -If you lost your password, please use the data below and just enter the -password AS SHOWN into the wiki's password form field (use copy and paste -for that). - -After successfully logging in, it is of course a good idea to set a new and known password. -""", formatted=False) + text - - - subject = _('[%(sitename)s] Your wiki account data', - formatted=False) % {'sitename': self._cfg.sitename or "Wiki"} - mailok, msg = mail.sendmail(self._request, [self.email], subject, - text, mail_from=self._cfg.mail_from) - return msg - diff --git a/wiki/userform.py b/wiki/userform.py deleted file mode 100644 index 4ba4181a..00000000 --- a/wiki/userform.py +++ /dev/null @@ -1,765 +0,0 @@ -# -*- coding: iso-8859-1 -*- -""" - MoinMoin - UserPreferences Form and User Browser - - @copyright: 2001-2004 by Jürgen Hermann - @license: GNU GPL, see COPYING for details. -""" - -import string, time, re -from MoinMoin import user, util, wikiutil -from MoinMoin.util import web, mail, timefuncs -from MoinMoin.widget import html -from MoinMoin.PageEditor import PageEditor - -_debug = 0 - -############################################################################# -### Form POST Handling -############################################################################# - -def savedata(request): - """ Handle POST request of the user preferences form. - - Return error msg or None. - """ - return UserSettingsHandler(request).handleData() - - -class UserSettingsHandler: - - def __init__(self, request): - """ Initialize user settings form. """ - self.request = request - self._ = request.getText - self.cfg = request.cfg - - def decodePageList(self, key): - """ Decode list of pages from form input - - Each line is a page name, empty lines ignored. - - Items can use '_' as spaces, needed by [name_with_spaces label] - format used in quicklinks. We do not touch those names here, the - underscores are handled later by the theme code. - - @param key: the form key to get - @rtype: list of unicode strings - @return: list of normalized names - """ - text = self.request.form.get(key, [''])[0] - text = text.replace('\r', '') - items = [] - for item in text.split('\n'): - item = item.strip() - if not item: - continue - # Normalize names - except [name_with_spaces label] - # Commented out to allow URLs - #if not (item.startswith('[') and item.endswith(']')): - # item = self.request.normalizePagename(item) - items.append(item) - return items - - def handleData(self): - _ = self._ - form = self.request.form - - if form.has_key('cancel'): - return - - if form.has_key('account_sendmail'): - if not self.cfg.mail_enabled: - return _("""This wiki is not enabled for mail processing. -Contact the owner of the wiki, who can enable email.""") - try: - email = form['email'][0].lower() - except KeyError: - return _("Please provide a valid email address!") - - users = user.getUserList(self.request) - for uid in users: - theuser = user.User(self.request, uid) - if theuser.valid and theuser.email.lower() == email: - msg = theuser.mailAccountData() - return wikiutil.escape(msg) - - return _("Found no account matching the given email address '%(email)s'!") % {'email': wikiutil.escape(email)} - - if (form.has_key('create') or - form.has_key('create_only') or - form.has_key('create_and_mail')): - if self.request.request_method != 'POST': - return _("Use UserPreferences to change your settings or create an account.") - # Create user profile - if form.has_key('create'): - theuser = self.request.get_user_from_form() - else: - theuser = user.User(self.request, auth_method="request:152") - - # Require non-empty name - try: - theuser.name = form['name'][0] - except KeyError: - return _("Empty user name. Please enter a user name.") - - #### HACK CRANS : oblige les utilistaeurs a créer un WikiNom valide - if not wikiutil.isStrictWikiname(theuser.name): - return (u"""Nom d'utilisateur invalide {{{'%s'}}}. -Le login doit être de la forme WikiNom, WikiPseudo, PrenomNom... (voir ci dessous pour plus d'informations).""" % wikiutil.escape(theuser.name)) - #### FIN HACK - - # Don't allow users with invalid names - if not user.isValidName(self.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.""") % wikiutil.escape(theuser.name) - - # Is this an existing user trying to change information or a new user? - # Name required to be unique. Check if name belong to another user. - newuser = 1 - if user.getUserId(self.request, theuser.name): - if theuser.name != self.request.user.name: - return _("This user name already belongs to somebody else.") - else: - newuser = 0 - - #### HACK SAUVAGE - if newuser and not self.cfg.ip_autorised_create_account(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 DU HACK - - # try to get the password and pw repeat - password = form.get('password', [''])[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 and newuser: - return _("Please specify a password!") - # 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 (required) email - email = form.get('email', [''])[0] - theuser.email = email.strip() - if not theuser.email: - 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 self.request.cfg.user_email_unique: - users = user.getUserList(self.request) - for uid in users: - if uid == theuser.id: - continue - thisuser = user.User(self.request, uid) - if thisuser.email == theuser.email and not thisuser.disabled: - 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 - - - # Select user profile (su user) - only works with cookie auth active. - if form.has_key('select_user'): - if (wikiutil.checkTicket(self.request.form['ticket'][0]) and - self.request.request_method == 'POST' and - self.request.user.isSuperUser()): - su_user = form.get('selected_user', [''])[0] - uid = user.getUserId(self.request, su_user) - theuser = user.User(self.request, uid) - theuser.disabled = None - theuser.save() - from MoinMoin import auth - auth.setCookie(self.request, theuser) - self.request.user = theuser - - #### HACK : création de la page WikiNom - try: - p = PageEditor(self.request, theuser.name) - p.saveText( 'Décrire ici %s' % theuser.name, 0) - except: - pass - #### FIN DU HACK - - return _("Use UserPreferences to change settings of the selected user account") - else: - return _("Use UserPreferences to change your settings or create an account.") - - if form.has_key('save'): # Save user profile - if self.request.request_method != 'POST': - return _("Use UserPreferences to change your settings or create an account.") - theuser = self.request.get_user_from_form() - - if not 'name' in theuser.auth_attribs: - # Require non-empty name - theuser.name = form.get('name', [theuser.name])[0] - if not theuser.name: - return _("Empty user name. Please enter a user name.") - - # Don't allow users with invalid names - if not user.isValidName(self.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.""") % wikiutil.escape(theuser.name) - - # Is this an existing user trying to change information or a new user? - # Name required to be unique. Check if name belong to another user. - newuser = 1 - if user.getUserId(self.request, theuser.name): - if theuser.name != self.request.user.name: - return _("This user name already belongs to somebody else.") - else: - newuser = 0 - - if not 'password' in theuser.auth_attribs: - # try to get the password and pw repeat - password = form.get('password', [''])[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 and newuser: - return _("Please specify a password!") - # 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) - - if not 'email' in theuser.auth_attribs: - # try to get the email - email = form.get('email', [theuser.email])[0] - theuser.email = email.strip() - - # Require email - if not theuser.email: - 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 self.request.cfg.user_email_unique: - users = user.getUserList(self.request) - for uid in users: - if uid == theuser.id: - continue - thisuser = user.User(self.request, uid, auth_method='userform:283') - if thisuser.email == theuser.email: - return _("This email already belongs to somebody else.") - - if not 'aliasname' in theuser.auth_attribs: - # aliasname - theuser.aliasname = form.get('aliasname', [''])[0] - - # editor size - theuser.edit_rows = util.web.getIntegerInput(self.request, 'edit_rows', theuser.edit_rows, 10, 60) - - # try to get the editor - theuser.editor_default = form.get('editor_default', [self.cfg.editor_default])[0] - theuser.editor_ui = form.get('editor_ui', [self.cfg.editor_ui])[0] - - # time zone - theuser.tz_offset = util.web.getIntegerInput(self.request, 'tz_offset', theuser.tz_offset, -84600, 84600) - - # datetime format - try: - dt_d_combined = UserSettings._date_formats.get(form['datetime_fmt'][0], '') - theuser.datetime_fmt, theuser.date_fmt = dt_d_combined.split(' & ') - except (KeyError, ValueError): - theuser.datetime_fmt = '' # default - theuser.date_fmt = '' # default - - # try to get the (optional) theme - theme_name = form.get('theme_name', [self.cfg.theme_default])[0] - if theme_name != theuser.theme_name: - # if the theme has changed, load the new theme - # so the user has a direct feedback - # WARNING: this should be refactored (i.e. theme load - # after userform handling), cause currently the - # already loaded theme is just replaced (works cause - # nothing has been emitted yet) - theuser.theme_name = theme_name - if self.request.loadTheme(theuser.theme_name) > 0: - theme_name = wikiutil.escape(theme_name) - return _("The theme '%(theme_name)s' could not be loaded!") % locals() - - # try to get the (optional) preferred language - theuser.language = form.get('language', [''])[0] - - # I want to handle all inputs from user_form_fields, but - # don't want to handle the cases that have already been coded - # above. - # This is a horribly fragile kludge that's begging to break. - # Something that might work better would be to define a - # handler for each form field, instead of stuffing them all in - # one long and inextensible method. That would allow for - # plugins to provide methods to validate their fields as well. - already_handled = ['name', 'password', 'password2', 'email', - 'aliasname', 'edit_rows', 'editor_default', - 'editor_ui', 'tz_offset', 'datetime_fmt', - 'theme_name', 'language'] - for field in self.cfg.user_form_fields: - key = field[0] - if ((key in self.cfg.user_form_disable) - or (key in already_handled)): - continue - default = self.cfg.user_form_defaults[key] - value = form.get(key, [default])[0] - setattr(theuser, key, value) - - # checkbox options - if not newuser: - for key, label in self.cfg.user_checkbox_fields: - if key not in self.cfg.user_checkbox_disable and key not in self.cfg.user_checkbox_remove: - value = form.get(key, ["0"])[0] - try: - value = int(value) - except ValueError: - pass - else: - setattr(theuser, key, value) - - # quicklinks for navibar - theuser.quicklinks = self.decodePageList('quicklinks') - - # subscription for page change notification - theuser.subscribed_pages = self.decodePageList('subscribed_pages') - - # save data - theuser.save() - self.request.user = theuser - - result = _("User preferences saved!") - if _debug: - result = result + util.dumpFormData(form) - return result - - -############################################################################# -### Form Generation -############################################################################# - -class UserSettings: - """ User login and settings management. """ - - _date_formats = { # datetime_fmt & date_fmt - 'iso': '%Y-%m-%d %H:%M:%S & %Y-%m-%d', - 'us': '%m/%d/%Y %I:%M:%S %p & %m/%d/%Y', - 'euro': '%d.%m.%Y %H:%M:%S & %d.%m.%Y', - 'rfc': '%a %b %d %H:%M:%S %Y & %a %b %d %Y', - } - - def __init__(self, request): - """ Initialize user settings form. - """ - self.request = request - self._ = request.getText - self.cfg = request.cfg - - def _tz_select(self): - """ Create time zone selection. """ - tz = 0 - if self.request.user.valid: - tz = int(self.request.user.tz_offset) - - options = [] - now = time.time() - for halfhour in range(-47, 48): - offset = halfhour * 1800 - t = now + offset - - options.append(( - str(offset), - '%s [%s%s:%s]' % ( - time.strftime(self.cfg.datetime_fmt, timefuncs.tmtuple(t)), - "+-"[offset < 0], - string.zfill("%d" % (abs(offset) / 3600), 2), - string.zfill("%d" % (abs(offset) % 3600 / 60), 2), - ), - )) - - return util.web.makeSelection('tz_offset', options, str(tz)) - - - def _dtfmt_select(self): - """ Create date format selection. """ - _ = self._ - try: - dt_d_combined = '%s & %s' % (self.request.user.datetime_fmt, self.request.user.date_fmt) - selected = [ - k for k, v in self._date_formats.items() - if v == dt_d_combined][0] - except IndexError: - selected = '' - options = [('', _('Default'))] + self._date_formats.items() - - return util.web.makeSelection('datetime_fmt', options, selected) - - - def _lang_select(self): - """ Create language selection. """ - from MoinMoin import i18n - from MoinMoin.i18n import NAME - _ = self._ - cur_lang = self.request.user.valid and self.request.user.language or '' - langs = i18n.wikiLanguages().items() - langs.sort(lambda x,y,NAME=NAME: cmp(x[1][NAME], y[1][NAME])) - options = [('', _('', formatted=False))] - for lang in langs: - name = lang[1][NAME] - options.append((lang[0], name)) - - return util.web.makeSelection('language', options, cur_lang) - - def _user_select(self): - options = [] - users = user.getUserList(self.request) - for uid in users: - name = user.User(self.request, id=uid).name # + '_' + uid # for debugging - options.append((name, name)) - options.sort() - - size = min(5, len(options)) - current_user = self.request.user.name - return util.web.makeSelection('selected_user', options, current_user, size=size) - - def _theme_select(self): - """ Create theme selection. """ - cur_theme = self.request.user.valid and self.request.user.theme_name or self.cfg.theme_default - options = [("", "<%s>" % self._("Default"))] - for theme in wikiutil.getPlugins('theme', self.request.cfg): - options.append((theme, theme)) - - return util.web.makeSelection('theme_name', options, cur_theme) - - def _editor_default_select(self): - """ Create editor selection. """ - editor_default = self.request.user.valid and self.request.user.editor_default or self.cfg.editor_default - options = [("", "<%s>" % self._("Default"))] - for editor in ['text','gui',]: - options.append((editor, editor)) - return util.web.makeSelection('editor_default', options, editor_default) - - def _editor_ui_select(self): - """ Create editor selection. """ - editor_ui = self.request.user.valid and self.request.user.editor_ui or self.cfg.editor_ui - options = [("", "<%s>" % self._("Default")), - ("theonepreferred", self._("the one preferred")), - ("freechoice", self._("free choice")), - ] - return util.web.makeSelection('editor_ui', options, editor_ui) - - def make_form(self): - """ Create the FORM, and the TABLE with the input fields - """ - sn = self.request.getScriptname() - pi = self.request.getPathinfo() - action = u"%s%s" % (sn, pi) - self._form = html.FORM(action=action) - self._table = html.TABLE(border="0") - - # Use the user interface language and direction - lang_attr = self.request.theme.ui_lang_attr() - self._form.append(html.Raw('

    ' % lang_attr)) - - self._form.append(html.INPUT(type="hidden", name="action", value="userform")) - self._form.append(self._table) - self._form.append(html.Raw("
    ")) - - - def make_row(self, label, cell, **kw): - """ Create a row in the form table. - """ - self._table.append(html.TR().extend([ - html.TD(**kw).extend([html.B().append(label), ' ']), - html.TD().extend(cell), - ])) - - - def asHTML(self, create_only=False): - """ Create the complete HTML form code. """ - _ = self._ - self.make_form() - - if self.request.user.isSuperUser(): - ticket = wikiutil.createTicket() - self.make_row(_('Select User'), [self._user_select()]) - self._form.append(html.INPUT(type="hidden", name="ticket", value="%s" % ticket)) - buttons = [("select_user", _('Select User'))] - button_cell = [] - for name, label in buttons: - button_cell.extend([ - html.INPUT(type="submit", name=name, value=label), - ' ', - ]) - self.make_row('', button_cell) - - if self.request.user.valid and not create_only: - buttons = [('save', _('Save')), ('cancel', _('Cancel')), ] - uf_remove = self.cfg.user_form_remove - uf_disable = self.cfg.user_form_disable - for attr in self.request.user.auth_attribs: - if attr == 'password': - uf_remove.append(attr) - uf_remove.append('password2') - else: - uf_disable.append(attr) - for key, label, type, length, textafter in self.cfg.user_form_fields: - default = self.cfg.user_form_defaults[key] - if not key in uf_remove: - if key in uf_disable: - self.make_row(_(label), - [ html.INPUT(type=type, size=length, name=key, disabled="disabled", - value=getattr(self.request.user, key)), ' ', _(textafter), ]) - else: - self.make_row(_(label), - [ html.INPUT(type=type, size=length, name=key, value=getattr(self.request.user, key)), ' ', _(textafter), ]) - - if not self.cfg.theme_force and not "theme_name" in self.cfg.user_form_remove: - self.make_row(_('Preferred theme'), [self._theme_select()]) - - if not self.cfg.editor_force: - if not "editor_default" in self.cfg.user_form_remove: - self.make_row(_('Editor Preference'), [self._editor_default_select()]) - if not "editor_ui" in self.cfg.user_form_remove: - self.make_row(_('Editor shown on UI'), [self._editor_ui_select()]) - - if not "tz_offset" in self.cfg.user_form_remove: - self.make_row(_('Time zone'), [ - _('Your time is'), ' ', - self._tz_select(), - html.BR(), - _('Server time is'), ' ', - time.strftime(self.cfg.datetime_fmt, timefuncs.tmtuple()), - ' (UTC)', - ]) - - if not "datetime_fmt" in self.cfg.user_form_remove: - self.make_row(_('Date format'), [self._dtfmt_select()]) - - if not "language" in self.cfg.user_form_remove: - self.make_row(_('Preferred language'), [self._lang_select()]) - - # boolean user options - bool_options = [] - checkbox_fields = self.cfg.user_checkbox_fields - _ = self.request.getText - checkbox_fields.sort(lambda a, b: cmp(a[1](_), b[1](_))) - for key, label in checkbox_fields: - if not key in self.cfg.user_checkbox_remove: - bool_options.extend([ - html.INPUT(type="checkbox", name=key, value="1", - checked=getattr(self.request.user, key, 0), - disabled=key in self.cfg.user_checkbox_disable and True or None), - ' ', label(_), html.BR(), - ]) - self.make_row(_('General options'), bool_options, valign="top") - - self.make_row(_('Quick links'), [ - html.TEXTAREA(name="quicklinks", rows="6", cols="50") - .append('\n'.join(self.request.user.getQuickLinks())), - ], valign="top") - - # subscribed pages - if self.cfg.mail_enabled: - # Get list of subscribe pages, DO NOT sort! it should - # stay in the order the user entered it in his input - # box. - notifylist = self.request.user.getSubscriptionList() - - warning = [] - if not self.request.user.email: - warning = [ - html.BR(), - html.SMALL(Class="warning").append( - _("This list does not work, unless you have" - " entered a valid email address!") - )] - - self.make_row( - html.Raw(_('Subscribed wiki pages (one regex per line)')), - [html.TEXTAREA(name="subscribed_pages", rows="6", cols="50").append( - '\n'.join(notifylist)), - ] + warning, - valign="top" - ) - else: # not logged in - # Login / register interface - buttons = [ - # IMPORTANT: login should be first to be the default - # button when a user hits ENTER. - #('login', _('Login')), # we now have a Login macro - ('create', _('Create Profile')), - ('cancel', _('Cancel')), - ] - for key, label, type, length, textafter in self.cfg.user_form_fields: - if key in ('name', 'password', 'password2', 'email'): - self.make_row(_(label), - [ html.INPUT(type=type, size=length, name=key, - value=''), - ' ', _(textafter), ]) - - if self.cfg.mail_enabled: - buttons.append(("account_sendmail", _('Mail me my account data'))) - - if create_only: - buttons = [("create_only", _('Create Profile'))] - if self.cfg.mail_enabled: - buttons.append(("create_and_mail", "%s + %s" % - (_('Create Profile'), _('Email')))) - - # Add buttons - button_cell = [] - for name, label in buttons: - if not name in self.cfg.user_form_remove: - button_cell.extend([ - html.INPUT(type="submit", name=name, value=label), - ' ', - ]) - self.make_row('', button_cell) - - return unicode(self._form) - - -def getUserForm(request, create_only=False): - """ Return HTML code for the user settings. """ - return UserSettings(request).asHTML(create_only=create_only) - - -class Login: - """ User login. """ - - def __init__(self, request): - """ Initialize user settings form. - """ - self.request = request - self._ = request.getText - self.cfg = request.cfg - - def make_row(self, label, cell, **kw): - """ Create a row in the form table. - """ - self._table.append(html.TR().extend([ - html.TD(**kw).extend([html.B().append(label), ' ']), - html.TD().extend(cell), - ])) - - - def asHTML(self): - """ Create the complete HTML form code. """ - _ = self._ - request = self.request - sn = request.getScriptname() - pi = request.getPathinfo() - action = u"%s%s" % (sn, pi) - userprefslink = wikiutil.getSysPage(request, "UserPreferences").link_to(request) - hint = _("To create an account or recover a lost password, see the %(userprefslink)s page.") % { - 'userprefslink': userprefslink} - self._form = html.FORM(action=action) - self._table = html.TABLE(border="0") - - # Use the user interface language and direction - lang_attr = request.theme.ui_lang_attr() - self._form.append(html.Raw('
    ' % lang_attr)) - - self._form.append(html.INPUT(type="hidden", name="action", value="login")) - self._form.append(self._table) - self._form.append(html.P().append(hint)) - self._form.append(html.Raw("
    ")) - - self.make_row(_('Name'), [ - html.INPUT( - type="text", size="32", name="name", - ), - ]) - - self.make_row(_('Password'), [ - html.INPUT( - type="password", size="32", name="password", - ), - ]) - - self.make_row('', [ - html.INPUT( - type="submit", name='login', value=_('Login') - ), - ]) - - return unicode(self._form) - -def getLogin(request): - """ Return HTML code for the login. """ - return Login(request).asHTML() - -############################################################################# -### User account administration -############################################################################# - -def do_user_browser(request): - """ Browser for SystemAdmin macro. """ - from MoinMoin.util.dataset import TupleDataset, Column - from MoinMoin.Page import Page - _ = request.getText - - data = TupleDataset() - data.columns = [ - #Column('id', label=('ID'), align='right'), - Column('name', label=('Username')), - Column('email', label=('Email')), - Column('action', label=_('Action')), - ] - - # Iterate over users - for uid in user.getUserList(request): - account = user.User(request, uid) - - userhomepage = Page(request, account.name) - if userhomepage.exists(): - namelink = userhomepage.link_to(request) - else: - namelink = account.name - - data.addRow(( - #request.formatter.code(1) + uid + request.formatter.code(0), - request.formatter.rawHTML(namelink), - (request.formatter.url(1, 'mailto:' + account.email, css='mailto', do_escape=0) + - request.formatter.text(account.email) + - request.formatter.url(0)), - request.page.link_to(request, text=_('Mail me my account data'), - querystr= {"action":"userform", - "email": account.email, - "account_sendmail": "1", - "sysadm": "users",}) - )) - - if data: - from MoinMoin.widget.browser import DataBrowserWidget - - browser = DataBrowserWidget(request) - browser.setData(data) - return browser.toHTML() - - # No data - return '' - diff --git a/wiki/wikiacl.py b/wiki/wikiacl.py deleted file mode 100644 index b27b50e8..00000000 --- a/wiki/wikiacl.py +++ /dev/null @@ -1,378 +0,0 @@ -# -*- coding: iso-8859-1 -*- -""" - MoinMoin Access Control Lists - - @copyright: 2003 by Thomas Waldmann, http://linuxwiki.de/ThomasWaldmann - @copyright: 2003 by Gustavo Niemeyer, http://moin.conectiva.com.br/GustavoNiemeyer - @license: GNU GPL, see COPYING for details. -""" - -import re -from MoinMoin import user, search - -#### HACK SAUVAGE 1/4 -import sys -sys.path.append('/usr/scripts/gestion/') -from iptools import is_crans -#### FIN DU HACK 1/4 - -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/4 - special_users = ["All", "Known", "Trusted", "Conf"] - #### FIN DU HACK 2/4 - - def __init__(self, request, lines=[]): - """Initialize an ACL, starting from . - """ - self.setLines(request.cfg, lines) - - def setLines(self, cfg, lines=[]): - self.clean() - self.addBefore(cfg) - if not lines: - self.addDefault(cfg) - else: - for line in lines: - self.addLine(cfg, line) - self.addAfter(cfg) - - def clean(self): - self.acl = [] # [ ('User', {"read": 0, ...}), ... ] - self.acl_lines = [] - self._is_group = {} - - def addBefore(self, cfg): - self.addLine(cfg, cfg.acl_rights_before, remember=0) - def addDefault(self, cfg): - self.addLine(cfg, cfg.acl_rights_default, remember=0) - def addAfter(self, cfg): - self.addLine(cfg, cfg.acl_rights_after, remember=0) - - 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 - """ - group_re = re.compile(cfg.page_group_regex) - - # 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.addDefault(cfg) - continue - - for entry in entries: - if group_re.search(entry): - self._is_group[entry] = 1 - 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 ? - Returns boolean answer. - """ - is_group_member = request.dicts.has_member - - allowed = None - for entry, rightsdict in self.acl: - if entry in self.special_users: - handler = getattr(self, "_special_"+entry, None) - allowed = handler(request, name, dowhat, rightsdict) - elif self._is_group.get(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 0 - - def getString(self, b='#acl ', e='\n'): - """print the acl strings we were fed with""" - return ''.join(["%s%s%s" % (b,l,e) for l in self.acl_lines]) - - def _special_All(self, request, name, dowhat, rightsdict): - if dowhat == "read" and self.is_page_public(request): - return True - return rightsdict.get(dowhat) - - def _special_Known(self, request, name, dowhat, rightsdict): - """ check if user 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 - - #### HACK SAUVAGE 3/4 - def _special_Conf(self, request, name, dowhat, rightsdict): - return request.cfg.acl_request(self, request, name, dowhat, rightsdict) - #### FIN DU HACK 3/4 - - def _special_Trusted(self, request, name, dowhat, rightsdict): - """ check if user is known AND even has logged in using a password. - does not work for subsription emails that should be sent to , - as he is not logged in in that case. - """ - if request.user.trusted and name == request.user.name: - 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 - - #### HACK SAUVAGE 4/4 - def is_page_public(self,request): - ## On recherche si la page est publique - if not request.page: - return False - this_page = request.page.page_name - query = search.QueryParser().parse_query(u'CatégoriePagePublique') - page = search.Page(request, this_page) - result = query.search(page) - if result: - return True - else: - return False - #### FIN DU HACK 4/4 - - -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, body): - """ Parse acl lines on page and return ACL object - - Use ACL object may(request, dowhat) to get acl rights. - """ - acl_lines = [] - while body and body[0] == '#': - # extract first line - try: - line, body = body.split('\n', 1) - except ValueError: - line = body - body = '' - - # end parsing on empty (invalid) PI - if line == "#": - break - - # skip comments (lines with two hash marks) - if line[1] == '#': - continue - - tokens = line.split(None, 1) - if tokens[0].lower() == "#acl": - if len(tokens) == 2: - args = tokens[1].rstrip() - else: - args = "" - acl_lines.append(args) - return AccessControlList(request, acl_lines) -