X-Git-Url: https://codewiz.org/gitweb?a=blobdiff_plain;ds=sidebyside;f=geekigeeki.py;h=a6158a3122b41b184930bf0255664a428851858d;hb=fef72da7c35a10fc92c098a9287683e9d71bea1d;hp=57992d288b93eb1774a2a82ce051dba49cfea5ab;hpb=10a9870db7d40c7375470061274902fc9f38f3a6;p=geekigeeki.git
diff --git a/geekigeeki.py b/geekigeeki.py
index 57992d2..a6158a3 100755
--- a/geekigeeki.py
+++ b/geekigeeki.py
@@ -1,10 +1,9 @@
-#! /usr/bin/env python
-"""Quick-quick implementation of WikiWikiWeb in Python
-"""
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
#
-# Copyright (C) 1999, 2000 Martin Pool
-# This version includes additional changes by Gerardo Poggiali (2002)
-# This version includes additional changes by Bernardo Innocenti (2007)
+# Copyright 1999, 2000 Martin Pool
+# Copyright 2002 Gerardo Poggiali
+# Copyright 2007, 2008 Bernardo Innocenti
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -19,15 +18,19 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
-__version__ = '$Revision: 1.63+gerry+bernie $'[11:-2]
+__version__ = '$Id$'[4:12]
-import cgi, sys, string, os, re, errno, time, stat
+from time import clock
+start_time = clock()
+
+import cgi, sys, os, re, errno, stat
from os import path, environ
# Regular expression defining a WikiWord
# (but this definition is also assumed in other places)
-file_re = re.compile(r"^\b([A-Za-z0-9_\.\-]+)\b$")
-word_re = re.compile(r"^\b([A-Z][a-z]+){2,}\b$")
+word_re = re.compile(r"^\b((([A-Z][a-z]+){2,}/)*([A-Z][a-z]+){2,})\b$")
+# FIXME: we accept stuff like foo/../bar and we shouldn't
+file_re = re.compile(r"^\b([A-Za-z0-9_\-][A-Za-z0-9_\.\-/]*)\b$")
img_re = re.compile(r"^.*\.(png|gif|jpg|jpeg)$", re.IGNORECASE)
url_re = re.compile(r"^[a-z]{3,8}://[^\s'\"]+\S$")
@@ -55,25 +58,33 @@ def get_hostname(addr):
try:
from socket import gethostbyaddr
return gethostbyaddr(addr)[0] + ' (' + addr + ')'
- except:
+ except Exception, er:
return addr
+def relative_url(pathname, privileged=False):
+ if not (url_re.match(pathname) or pathname.startswith('/')):
+ if privileged:
+ url = privileged_path()
+ else:
+ url = script_name()
+ pathname = url + '/' + pathname
+ return pathname
+
# Formatting stuff --------------------------------------------------
-def emit_header(type="text/html"):
- print "Content-type: " + type + "; charset=utf-8"
- print
+def emit_header(mime_type="text/html"):
+ print "Content-type: " + mime_type + "; charset=utf-8\n"
-def send_guru(msg, msg_type):
- if msg is None or msg == '': return
+def send_guru(msg_text, msg_type):
+ if not msg_text: return
print '
'
if msg_type == 'error':
print ' Software Failure. Press left mouse button to continue.\n'
- print msg
+ print msg_text
if msg_type == 'error':
print ' Guru Meditation #DEADBEEF.ABADC0DE'
print '
'
- # FIXME: This simple JS snippet is harder to pass than ACID 3.0
+ # FIXME: This little JS snippet is harder to pass than ACID 3.0
print """
"""
-def send_title(name, text="Limbo", msg=None, msg_type='error'):
+def send_title(name, text="Limbo", msg_text=None, msg_type='error'):
global title_done
if title_done: return
# Head
emit_header()
- print """
-
-"""
+ print ''
+ print ''
+
+ site_name = globals().get('site_name', 'Unconfigured Site')
print "%s: %s" % (site_name, text)
print ' '
if not name:
print ' '
- if css_url:
- print ' ' % css_url
+ for css in css_url:
+ print ' ' % relative_url(css)
print ''
# Body
@@ -121,24 +133,26 @@ def send_title(name, text="Limbo", msg=None, msg_type='error'):
print ''
title_done = True
- send_guru(msg, msg_type)
+ send_guru(msg_text, msg_type)
# Navbar
print '
' % (letter, letter)
last_letter = letter
@@ -310,19 +310,19 @@ def _macro_WordIndex():
return s
-def _macro_TitleIndex():
+def _macro_TitleIndex(*vargs):
s = make_index_key()
pages = list(page_list())
pages.sort()
current_letter = None
for name in pages:
- letter = string.lower(name[0])
- if letter <> current_letter:
- s = s + '
\s*\}\}\})"
+ + r"|(?P[<>&])"
+ r")")
blank_re = re.compile(r"^\s*$")
indent_re = re.compile(r"^\s*")
tr_re = re.compile(r"^\s*\|\|")
eol_re = re.compile(r"\r?\n")
- raw = string.expandtabs(self.raw)
- for line in eol_re.split(raw):
+ for line in eol_re.split(self.raw.expandtabs()):
# Skip ACLs
if self.in_header:
if line.startswith('#'):
- continue
+ continue
self.in_header = False
if self.in_pre:
@@ -557,61 +548,55 @@ class PageFormatter:
if self.in_pre: print '
'
if self.in_table: print '
'
print self._undent()
- print "
"
+ print ''
# ----------------------------------------------------------
class Page:
def __init__(self, page_name):
self.page_name = page_name
- self.msg = ''
+ self.msg_text = ''
self.msg_type = 'error'
- self.attrs = {}
def split_title(self):
- # look for the end of words and the start of a new word,
- # and insert a space there
+ # look for the end of words and the start of a new word and insert a space there
return re.sub('([a-z])([A-Z])', r'\1 \2', self.page_name)
def _text_filename(self):
- return path.join(text_dir, self.page_name)
+ return path.join(data_dir, self.page_name)
def _tmp_filename(self):
- return path.join(text_dir, ('#' + self.page_name + '.' + `os.getpid()` + '#'))
+ return path.join(data_dir, ('#' + self.page_name.replace('/','_') + '.' + `os.getpid()` + '#'))
def exists(self):
try:
os.stat(self._text_filename())
- return 1
+ return True
except OSError, er:
if er.errno == errno.ENOENT:
- return 0
- else:
- raise er
+ return False
+ raise er
def link_to(self):
word = self.page_name
if self.exists():
return link_tag(word, word, 'wikilink')
else:
- if nonexist_qm:
- return link_tag(word, '?', 'nonexistent') + word
- else:
- return link_tag(word, word, 'nonexistent')
-
+ return link_tag(word, nonexist_pfx + word, 'nonexistent')
def get_raw_body(self):
try:
- return open(self._text_filename(), 'rt').read()
+ return open(self._text_filename(), 'rb').read()
except IOError, er:
if er.errno == errno.ENOENT:
- # just doesn't exist, use default
- return 'Describe %s here.' % self.page_name
- else:
- raise er
+ return '' # just doesn't exist, use default
+ if er.errno == errno.EISDIR:
+ return 'DIR'
+ raise er
def get_attrs(self):
- if self.attrs:
+ if 'attrs' in self.__dict__:
return self.attrs
+ self.attrs = {}
try:
file = open(self._text_filename(), 'rt')
attr_re = re.compile(r"^#(\S*)(.*)$")
@@ -626,46 +611,73 @@ class Page:
raise er
return self.attrs
- def can_edit(self):
- attrs = self.get_attrs()
+ def get_attr(self, name, default):
+ return self.get_attrs().get(name, default)
+
+ def can(self, action, default=True):
try:
- # SomeUser:read,write All:read
- acl = attrs["acl"]
+ #acl SomeUser:read,write All:read
+ acl = self.get_attr("acl", None)
for rule in acl.split():
- (user,perms) = acl.split(':')
+ (user, perms) = rule.split(':')
if user == remote_user() or user == "All":
- if 'write' in perms.split(','):
- return True
+ return action in perms.split(',')
return False
- except:
- pass
- return True
+ except Exception, er:
+ if acl:
+ self.msg_text = 'Illegal acl line: ' + acl
+ return default
+
+ def can_write(self):
+ return self.can("write", True)
+
+ def can_read(self):
+ return self.can("read", True)
def send_page(self):
page_name = None
- if self.can_edit():
+ if self.can_write():
page_name = self.page_name
- send_title(page_name, self.split_title(), msg=self.msg, msg_type=self.msg_type)
- PageFormatter(self.get_raw_body()).print_html()
+
+ #css foo.css bar.css
+ global css_url
+ css_url = self.get_attr("css", "").split() + css_url
+
+ send_title(page_name, self.split_title(), msg_text=self.msg_text, msg_type=self.msg_type)
+ if self.can_read():
+ PageFormatter(self.get_raw_body()).print_html()
+ else:
+ send_guru("Read access denied by ACLs", "notice")
send_footer(page_name, self._last_modified())
def _last_modified(self):
- if not self.exists():
+ try:
+ from time import localtime, strftime
+ modtime = localtime(os.stat(self._text_filename())[stat.ST_MTIME])
+ except OSError, er:
+ if er.errno != errno.ENOENT:
+ raise er
return None
- from time import localtime, strftime
- modtime = localtime(os.stat(self._text_filename())[stat.ST_MTIME])
return strftime(datetime_fmt, modtime)
def send_editor(self, preview=None):
- send_title(None, 'Edit ' + self.split_title(), msg=self.msg, msg_type=self.msg_type)
+ send_title(None, 'Edit ' + self.split_title(), msg_text=self.msg_text, msg_type=self.msg_type)
+ if not self.can_write():
+ send_guru("Write access denied by ACLs", "error")
+ return
+
+ file = ''
+ if 'file' in form:
+ file = form['file'].value
print ('
Editing ' + self.page_name
+ ' for ' + cgi.escape(remote_user())
+ ' from ' + cgi.escape(get_hostname(remote_host()))
+ '