diff --git a/Tools/faqwiz/faqmain.py b/Tools/faqwiz/faqmain.py deleted file mode 100644 index 7550bd002e3..00000000000 --- a/Tools/faqwiz/faqmain.py +++ /dev/null @@ -1,858 +0,0 @@ -"""Interactive FAQ project. - -Note that this is not an executable script; it's an importable module. -The actual CGI script can be kept minimal; it's appended at the end of -this file as a string constant. - -XXX TO DO - -XXX User Features TO DO - -- next/prev/index links in do_show??? -- explanation of editing somewhere -- embellishments, GIFs, hints, etc. -- support adding annotations, too -- restrict recent changes to last week (or make it an option) -- extended search capabilities - -XXX Management Features TO DO - -- username/password for authors -- create new sections -- rearrange entries -- delete entries -- freeze entries -- send email on changes? -- send email on ERRORS! -- optional staging of entries until reviewed? - (could be done using rcs branches!) -- prevent race conditions on nearly simultaneous commits - -XXX Performance - -- could cache generated HTML -- could speed up searches with a separate index file - -XXX Code organization TO DO - -- read section titles from a file (could be a Python file: import faqcustom) -- customize rcs command pathnames (and everything else) -- make it more generic (so you can create your own FAQ) -- more OO structure, e.g. add a class representing one FAQ entry - -""" - -# NB for timing purposes, the imports are at the end of this file - -PASSWORD = "Spam" - -NAMEPAT = "faq??.???.htp" -NAMEREG = "^faq\([0-9][0-9]\)\.\([0-9][0-9][0-9]\)\.htp$" - -SECTIONS = { - "1": "General information and availability", - "2": "Python in the real world", - "3": "Building Python and Other Known Bugs", - "4": "Programming in Python", - "5": "Extending Python", - "6": "Python's design", - "7": "Using Python on non-UNIX platforms", -} - -class FAQServer: - - def __init__(self): - pass - - def main(self): - self.form = cgi.FieldStorage() - req = self.req or 'frontpage' - try: - method = getattr(self, 'do_%s' % req) - except AttributeError: - print "Unrecognized request type", req - else: - method() - self.epilogue() - - KEYS = ['req', 'query', 'name', 'text', 'commit', 'title', - 'author', 'email', 'log', 'section', 'number', 'add', - 'version', 'edit', 'password'] - - def __getattr__(self, key): - if key not in self.KEYS: - raise AttributeError - try: - form = self.form - try: - item = form[key] - except TypeError, msg: - raise KeyError, msg, sys.exc_traceback - except KeyError: - return '' - value = self.form[key].value - value = string.strip(value) - setattr(self, key, value) - return value - - def do_frontpage(self): - self.prologue("Python FAQ Wizard (beta test)") - print """ -
- Disclaimer: these pages are intended to be edited by anyone. - Please exercise discretion when editing, don't be rude, etc. - """ - - def do_index(self): - self.prologue("Python FAQ Index") - names = os.listdir(os.curdir) - names.sort() - section = None - for name in names: - headers, text = self.read(name) - if headers: - title = headers['title'] - i = string.find(title, '.') - nsec = title[:i] - if nsec != section: - if section: - print """ -
-
-
-
Use `Reload' to show another one." - break - else: - names.remove(name) - else: - print "No FAQ entries?!?!" - - def do_recent(self): - import fnmatch, stat - names = os.listdir(os.curdir) - now = time.time() - list = [] - for name in names: - if not fnmatch.fnmatch(name, NAMEPAT): - continue - try: - st = os.stat(name) - except os.error: - continue - tuple = (st[stat.ST_MTIME], name) - list.append(tuple) - list.sort() - list.reverse() - self.prologue("Python FAQ, Most Recently Modified First") - print "
- If you really think an entry needs to be deleted, - change the title to "(deleted)" and make the body - empty (keep the entry number in the title though). - """ - - def do_edit(self): - name = self.name - headers, text = self.read(name) - if not headers: - self.error("Invalid file name", name) - return - self.prologue("Python FAQ Edit Wizard - Edit Form") - print 'Click for Help' - title = headers['title'] - version = self.getversion(name) - print "
-' - p = os.popen("/depot/gnu/plat/bin/rlog -r %s &1" % - self.name) - output = p.read() - p.close() - print cgi.escape(output) - print '' - print 'View full rcs log' % name - - def do_rlog(self): - name = self.name - headers, text = self.read(name) - if not headers: - self.error("Invalid file name", name) - return - self.prologue("RCS log for %s" % name) - print '
' - p = os.popen("/depot/gnu/plat/bin/rlog %s &1" % self.name) - output = p.read() - p.close() - print cgi.escape(output) - print '' - - def checkin(self): - import regsub, time, tempfile - name = self.name - password = self.password - if password != PASSWORD: - self.error("Invalid password.") - return - if not (self.log and self.author and '@' in self.email): - self.error("No log message, no author, or invalid email.") - return - headers, oldtext = self.read(name) - if not headers: - self.error("Invalid file name", name) - return - version = self.version - curversion = self.getversion(name) - if version != curversion: - self.error( - "Version conflict.", - "You edited version %s but current version is %s." % ( - version, curversion), - """ -
- The two most common causes of this problem are: -
- """, - 'Click here to reload the entry and try again.') - return - text = self.text - title = self.title - author = self.author - email = self.email - log = self.log - text = regsub.gsub("\r\n", "\n", text) - log = regsub.gsub("\r\n", "\n", log) - author = string.join(string.split(author)) - email = string.join(string.split(email)) - title = string.join(string.split(title)) - oldtitle = headers['title'] - oldtitle = string.join(string.split(oldtitle)) - text = string.strip(text) - oldtext = string.strip(oldtext) - if text == oldtext and title == oldtitle: - self.error("No changes.") - return - # Check that the FAQ entry number didn't change - if string.split(title)[:1] != string.split(oldtitle)[:1]: - self.error("Don't change the FAQ entry number please.") - return - remhost = os.environ["REMOTE_HOST"] - remaddr = os.environ["REMOTE_ADDR"] - try: - os.unlink(name + "~") - except os.error: - pass - try: - os.rename(name, name + "~") - except os.error: - pass - try: - os.unlink(name) - except os.error: - pass - try: - f = open(name, "w") - except IOError, msg: - self.error("Can't open", name, "for writing:", cgi.escape(str(msg))) - return - now = time.ctime(time.time()) - f.write("Title: %s\n" % title) - f.write("Last-Changed-Date: %s\n" % now) - f.write("Last-Changed-Author: %s\n" % author) - f.write("Last-Changed-Email: %s\n" % email) - f.write("Last-Changed-Remote-Host: %s\n" % remhost) - f.write("Last-Changed-Remote-Address: %s\n" % remaddr) - keys = headers.keys() - keys.sort() - keys.remove('title') - for key in keys: - if key[:13] != 'last-changed-': - f.write("%s: %s\n" % (string.capwords(key, '-'), - headers[key])) - f.write("\n") - f.write(text) - f.write("\n") - f.close() - - tfn = tempfile.mktemp() - f = open(tfn, "w") - f.write("Last-Changed-Date: %s\n" % now) - f.write("Last-Changed-Author: %s\n" % author) - f.write("Last-Changed-Email: %s\n" % email) - f.write("Last-Changed-Remote-Host: %s\n" % remhost) - f.write("Last-Changed-Remote-Address: %s\n" % remaddr) - f.write("\n") - f.write(log) - f.write("\n") - f.close() - - # Do this for show() below - self.headers = { - 'title': title, - 'last-changed-date': now, - 'last-changed-author': author, - 'last-changed-email': email, - 'last-changed-remote-host': remhost, - 'last-changed-remote-address': remaddr, - } - - p = os.popen(""" - /depot/gnu/plat/bin/rcs -l %s &1 - /depot/gnu/plat/bin/ci -u %s <%s 2>&1 - rm -f %s - """ % (name, name, tfn, tfn)) - output = p.read() - sts = p.close() - if not sts: - self.set_cookie(author, email, password) - self.prologue("Python FAQ Entry Edited") - print "
%s" % cgi.escape(output) - else: - self.error("Python FAQ Entry Commit Failed", - "Exit status 0x%04x" % sts) - if output: - print "
%s" % cgi.escape(output) - - def set_cookie(self, author, email, password): - name = "Python-FAQ-Wizard" - value = "%s/%s/%s" % (author, email, password) - import urllib - value = urllib.quote(value) - print "Set-Cookie: %s=%s; path=/cgi-bin/;" % (name, value), - import time - now = time.time() - then = now + 28 * 24 * 3600 - gmt = time.gmtime(then) - print time.strftime("expires=%a, %d-%b-%x %X GMT", gmt) - - def get_cookie(self): - if not os.environ.has_key('HTTP_COOKIE'): - return "", "", "" - raw = os.environ['HTTP_COOKIE'] - words = map(string.strip, string.split(raw, ';')) - cookies = {} - for word in words: - i = string.find(word, '=') - if i >= 0: - key, value = word[:i], word[i+1:] - cookies[key] = value - if not cookies.has_key('Python-FAQ-Wizard'): - return "", "", "" - value = cookies['Python-FAQ-Wizard'] - import urllib - value = urllib.unquote(value) - words = string.split(value, '/') - while len(words) < 3: - words.append('') - author = string.join(words[:-2], '/') - email = words[-2] - password = words[-1] - return author, email, password - - def showedit(self, name, title, text): - author = self.author - email = self.email - password = self.password - if not author or not email or not password: - a, e, p = self.get_cookie() - author = author or a - email = email or e - password = password or p - print """ - Title:
Name: - | - |
Email: - | - |
Password: - | - |
' - else: - if line[0] not in string.whitespace: - if pre: - print '' - pre = 0 - else: - if not pre: - print '
' - pre = 1 - if '/' in line or '@' in line: - line = self.translate(line) - elif '<' in line or '&' in line: - line = cgi.escape(line) - if not pre and '*' in line: - line = self.emphasize(line) - print line - if pre: - print '' - pre = 0 - print '
' - if edit: - print """ - Edit this entry / - Log info - """ % (name, name) - if self.headers: - try: - date = self.headers['last-changed-date'] - author = self.headers['last-changed-author'] - email = self.headers['last-changed-email'] - except KeyError: - pass - else: - s = '/ Last changed on %s by %s' - print s % (date, email, author) - print '
' - print "
-