leonardo-0.4.1/0040755000076500007650000000000010167570055013215 5ustar jtauberjtauberleonardo-0.4.1/bin/0040755000076500007650000000000010167570055013765 5ustar jtauberjtauberleonardo-0.4.1/bin/create_user.py0100755000076500007650000000271010167570124016635 0ustar jtauberjtauber#!/usr/bin/env python # # Copyright (C) 2003-2004 James Tauber # # 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 # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # """ This script is used for creating or modifying users in the user database. """ USER_DB = "../data/user_db" def create_user(name, email, password): """ Creates (or overwrites) a new user entry in the user database. """ import anydbm, sha user_db = anydbm.open(USER_DB, "c") user_db[email] = "%s|%s|%s" % (email, name, sha.sha(password).hexdigest()) if __name__ == "__main__": name = raw_input("User's Full Name: ") email = raw_input("User's Email Address (used as user id): ") password = raw_input("User's Password (will be echoed): ") print "Creating account...", create_user(name, email, password) print "done." leonardo-0.4.1/bin/leonconv-04.py0100644000076500007650000000216110167570124016375 0ustar jtauberjtauber#! /usr/bin/env python # -*- coding: UTF-8 -*- # # Contributed by Min Sik Kim # import codecs import os import stat import sys def usage(): print 'Usage:', sys.argv[0], ' ' sys.exit(0) if len(sys.argv) != 3: usage() src_root, dst_root = sys.argv[1], sys.argv[2] if not os.path.exists(src_root): sys.stderr.write('Error: cannot find %s\n' % srcdir) sys.exit(1) for root, dirs, files in os.walk(src_root): for name in files: src = os.path.join(root, name) dst = os.path.join(root.replace(src_root, dst_root), name.replace('.txt', '.ldv'), '__content__.wiki04') dstdir = os.path.dirname(dst) if not os.path.exists(dstdir): os.makedirs(dstdir) srcfile = codecs.getreader('UTF-8')(file(src, 'r')) dstfile = codecs.getwriter('UTF-8')(file(dst, 'w')) for line in srcfile.readlines(): dstfile.write(line) dstfile.close() srcfile.close() s = os.stat(src) times = (s[stat.ST_ATIME], s[stat.ST_MTIME]) os.utime(dst, times) leonardo-0.4.1/cgi-bin/0040755000076500007650000000000010167570055014525 5ustar jtauberjtauberleonardo-0.4.1/cgi-bin/leonardo.py0100755000076500007650000000204610167570124016701 0ustar jtauberjtauber#!/usr/bin/env python # # Copyright (C) 2003-2004 James Tauber # # 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 # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # ## Leonardo main CGI script import cgitb; cgitb.enable() import sys # location of leonardo modules (full path to leonardo lib directory) sys.path.append("/Users/jtauber/leonardo/lib") import leonardo_config import core core.dispatcher(leonardo_config) leonardo-0.4.1/cgi-bin/leonardo_config.py0100644000076500007650000000247610167570124020232 0ustar jtauberjtauber# Configuration file for Leonardo data_dir = "/Users/jtauber/leonardo/data/" lfs_root = data_dir + "lfs/" # static specific static_dir = data_dir + "static/" # css specific css_id = "css" css_href = "/" + css_id # page specific site_title = "Leonardo" site_sub_title = "sample site" home_href = "/" home_key = "__home__" copyright_holder = "James Tauber" # menu specific menu_key = "__MENU__" main_menu_key = "__menu__" # login_logout specific login_path = "login" logout_path = "logout" login_href = "/" + login_path logout_href = "/" + logout_path # editform specific edit_path = "edit" edit_href = "/" + edit_path edit_prefix = "/" edit_resource_field = "resource" # put specific put_path = "put" put_href = "/" + put_path put_resource_field = "resource" put_content_field = "page_content" # blog specific blog_prefix = "blog" blog_title = "Leonardo Sample Blog" site_url = "http://localhost:8000/" # atom specific atom_path = "atom" full_atom_path = "atom/full" blog_author = "James Tauber" # draft specific draft_prefix = "draft" draft_href = "/" + draft_prefixleonardo-0.4.1/CREDITS0100644000076500007650000000014610167570124014230 0ustar jtauberjtauberPrincipal Developer James Tauber Contributors Bryan Lawrence Peter Sefton Min Sik Kimleonardo-0.4.1/data/0040755000076500007650000000000010167570055014126 5ustar jtauberjtauberleonardo-0.4.1/data/lfs/0040755000076500007650000000000010167570055014712 5ustar jtauberjtauberleonardo-0.4.1/data/lfs/__home__.ldv/0040755000076500007650000000000010167570055017222 5ustar jtauberjtauberleonardo-0.4.1/data/lfs/__home__.ldv/__content__.wiki040100644000076500007650000000427410167570124022522 0ustar jtauberjtauber==Welcome to Leonardo!== It is recommended you read this page to get started. ===Users and Login=== To be able to edit pages or create new ones, you will need to first of all create a user account by running create_user.py in the Leonardo bin directory. You will then be able to log in via the Login link at the bottom of the menu to the left. ===Editing Existing Pages=== To edit an existing page, click on the Edit Page link at the bottom of the menu. You can find out more about the wiki formatting used in the [Wiki Formatting Guide]. ===Creating a New Page=== A page may be created one of two ways. If you go to a non-existent page while logged in, you can click on Edit Page to create the page directly. Alternatively, you can use the draft facility. Click on Drafts at the bottom of the menu (while logged in) and you can create a draft page. Once you have created a draft page, you can promote it to a real page, either at the top-level or as a blog entry. ===Blog Entries=== A blog entry is simply a page under blog////. Entries here will show up in daily, monthly, yearly and overall blog lists as well as in the Atom feed. ===Atom Feeds=== A titles-only atom feed is available at /atom and a full-entry atom feed at /atom/full. Note that these paths can be easily changed in cgi-bin/leonardo-config.py ===Static Files=== Static files may be served up by placing them under the static directory of your leonardo data directory. By default, static files have paths beginning with a year. This is to encourage the best practice of giving permanent date-based URIs to resources that do not change. An example is accessible at [:/2004/sample.txt] ===Customization=== Customisation can be done in a number of places: * the leonardo_config.py file in cgi-bin * the menu (see below) * the css stylesheet (see below) * individual templates under the lib/templates in the Leonardo directory ===Editing the Menu=== To change the menu to the left, go to [:edit?resource=__menu__ /edit?resource=__menu__] while logged. ===Editing the CSS=== To make a change to the CSS stylesheet, go to [:edit?resource=css /edit?resource=css] while logged in.������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������leonardo-0.4.1/data/lfs/__menu__.ldv/���������������������������������������������������������������0040755�0000765�0000765�00000000000�10167570055�017236� 5����������������������������������������������������������������������������������������������������ustar �jtauber�������������������������jtauber����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������leonardo-0.4.1/data/lfs/__menu__.ldv/__content__.wiki04���������������������������������������������0100644�0000765�0000765�00000000462�10167570124�022531� 0����������������������������������������������������������������������������������������������������ustar �jtauber�������������������������jtauber����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������===General=== [http://jtauber.com/leonardo Leonardo Home Page] [Wiki Formatting Guide] [:/2004/sample.txt sample static file] ===Blog=== [:/blog blog] [:/blog/2004/ just 2004 blog] [:/blog/2004/12/ december 2004] [:/atom/ title-only atom feed] [:/atom/full/ full-entry atom feed]��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������leonardo-0.4.1/data/lfs/blog/�����������������������������������������������������������������������0040755�0000765�0000765�00000000000�10167570055�015635� 5����������������������������������������������������������������������������������������������������ustar �jtauber�������������������������jtauber����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������leonardo-0.4.1/data/lfs/blog/2004/������������������������������������������������������������������0040755�0000765�0000765�00000000000�10167570055�016222� 5����������������������������������������������������������������������������������������������������ustar �jtauber�������������������������jtauber����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������leonardo-0.4.1/data/lfs/blog/2004/12/���������������������������������������������������������������0040755�0000765�0000765�00000000000�10167570055�016444� 5����������������������������������������������������������������������������������������������������ustar �jtauber�������������������������jtauber����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������leonardo-0.4.1/data/lfs/blog/2004/12/16/������������������������������������������������������������0040755�0000765�0000765�00000000000�10167570055�016672� 5����������������������������������������������������������������������������������������������������ustar �jtauber�������������������������jtauber����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������leonardo-0.4.1/data/lfs/blog/2004/12/16/my_first_blog_entry.ldv/������������������������������������0040755�0000765�0000765�00000000000�10167570055�023536� 5����������������������������������������������������������������������������������������������������ustar �jtauber�������������������������jtauber����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������leonardo-0.4.1/data/lfs/blog/2004/12/16/my_first_blog_entry.ldv/__content__.wiki04������������������0100644�0000765�0000765�00000000067�10167570124�027032� 0����������������������������������������������������������������������������������������������������ustar �jtauber�������������������������jtauber����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������==My First Blog Entry== This is my first blog entry.�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������leonardo-0.4.1/data/lfs/css.ldv/��������������������������������������������������������������������0040755�0000765�0000765�00000000000�10167570055�016266� 5����������������������������������������������������������������������������������������������������ustar �jtauber�������������������������jtauber����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������leonardo-0.4.1/data/lfs/css.ldv/__content__.css�����������������������������������������������������0100644�0000765�0000765�00000005521�10167570124�021243� 0����������������������������������������������������������������������������������������������������ustar �jtauber�������������������������jtauber����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������body { color : #333; background-color : #FFF; font-family : verdana, arial, helvetica, sans-serif; font-size : 0.8em; margin : 0px; } div#top { margin : 0px; padding-top : 5px; padding-bottom : 5px; background-color : #454; color : #996; } div#top h1 { font : 2.56em "trebuchet ms", verdana, arial, helvetica, sans-serif; padding-left : 15px; margin-top : 8px; margin-bottom : 8px; } div#top h2 { font : 1.6em "trebuchet ms", verdana, arial, helvetica, sans-serif; padding-left : 20px; margin-bottom : 8px; margin-top : 0px; font-style : italic; } div#main { margin-left : 22%; margin-right : 10%; margin-top : 0px; padding-top : 20px; padding-left : 10px; padding-bottom : 20px; } div#main h2 { margin-top : 0px; margin-bottom : 5px; padding : 0px; font : 1.92em "trebuchet ms", verdana, arial, helvetica, sans-serif; } div#main h3 { margin-top : 0px; margin-bottom : 5px; padding : 0px; font : 1.5em arial, helvetica, sans-serif; } div#main h4 { margin-top : 20px; margin-bottom : 0px; padding : 0px; border-bottom : 1px solid #444; font : bold 1.2em arial, helvetica, sans-serif; } div#main p { margin-top : 0px; margin-bottom : 10px; padding : 0px; } div#menu { float : left; width : 20%; margin-top : 0px; margin-right : 0px; padding-left : 15px; padding-top : 20px; padding-right : 10px; padding-bottom : 20px; border-right : 1px solid #ddd; } div#menu h3 { margin-bottom : 3px; padding-top : 0px; margin-top : 5px; border-bottom : 1px solid #ccc; font : bold 1em verdana, arial, helvetica, sans-serif; } div#menu p { margin-top : 0px; margin-bottom : 0px; font : 0.9em "trebuchet ms", verdana, arial, helvetica, sans-serif; line-height : 1.1em; } a:link, a:visited, a:active { color : #996; text-decoration : none; background-color : transparent; } a:hover { text-decoration : underline; background-color : transparent; } div#bottom { clear : left; font-size : 0.8em; border-top : 1px solid #DDD; margin-top : 0px; padding-bottom : 5px; text-align : right; padding-right : 15px; color : #AAA; } .debug { font-size : 0.8em; color : #AAA; } tt { font-size : 1.21em; } p.blog_date { font-size : 0.8em; color : #666; }�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������leonardo-0.4.1/data/lfs/draft/����������������������������������������������������������������������0040755�0000765�0000765�00000000000�10167570055�016012� 5����������������������������������������������������������������������������������������������������ustar �jtauber�������������������������jtauber����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������leonardo-0.4.1/data/lfs/draft/my_first_blog_entry.ldv/����������������������������������������������0040755�0000765�0000765�00000000000�10167570055�022656� 5����������������������������������������������������������������������������������������������������ustar �jtauber�������������������������jtauber����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������leonardo-0.4.1/data/lfs/draft/my_first_blog_entry.ldv/__content__.wiki04����������������������������0100644�0000765�0000765�00000000102�10167570124�026140� 0����������������������������������������������������������������������������������������������������ustar �jtauber�������������������������jtauber����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������==My First Blog Entry== This is a draft of my first blog entry.��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������leonardo-0.4.1/data/lfs/wiki_formatting_guide.ldv/��������������������������������������������������0040755�0000765�0000765�00000000000�10167570055�022050� 5����������������������������������������������������������������������������������������������������ustar �jtauber�������������������������jtauber����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������leonardo-0.4.1/data/lfs/wiki_formatting_guide.ldv/__content__.wiki04��������������������������������0100644�0000765�0000765�00000002443�10167570124�025344� 0����������������������������������������������������������������������������������������������������ustar �jtauber�������������������������jtauber����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������==Wiki Formatting Guide== ===Headings=== ==Second Level Heading== ===Third Level Heading=== ====Fourth Level Heading==== ===Lists=== asterix at the start of a line give you * this ===Blocks=== Five spaces at start of line to blockquote Four spaces at start of line for pre Empty lines mark paragraph boundaries ===Character Formatting=== Surround with asterixes for *blog* and two single quotes for ''italic'' Three dashes --- for emdash. ===Links=== Internal wiki links are surround by square brackets, e.g. [wiki formatting guide]. External links are surrounded by squared brackets and begin with the URI followed by a space followed by a title, e.g. [http://jtauber.com/leonardo Leonardo Home Page]. Internal links that involve / or need to be titled differently are surround by [: and ] with the path followed by a space followed by the title to use, e.g. [:blog/2004 the 2004 blog]. Books can be linked via ISBN to amazon using [amazon:<isbn>]. ===Insertions=== Images can be inserted using [image: and ] surrounding the image path followed by a space followed by the alt text. Other wiki pages can be inserted by using prefixing the wiki link with insert: as demonstrated below: [insert:blog/2004/12/16/my_first_blog_entry]�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������leonardo-0.4.1/data/static/�������������������������������������������������������������������������0040755�0000765�0000765�00000000000�10167570055�015415� 5����������������������������������������������������������������������������������������������������ustar �jtauber�������������������������jtauber����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������leonardo-0.4.1/data/static/2004/��������������������������������������������������������������������0040755�0000765�0000765�00000000000�10167570055�016002� 5����������������������������������������������������������������������������������������������������ustar �jtauber�������������������������jtauber����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������leonardo-0.4.1/data/static/2004/sample.txt����������������������������������������������������������0100644�0000765�0000765�00000000060�10167570124�020012� 0����������������������������������������������������������������������������������������������������ustar �jtauber�������������������������jtauber����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������This is an example of a statically served file. ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������leonardo-0.4.1/GPL����������������������������������������������������������������������������������0100644�0000765�0000765�00000043131�10167570124�013556� 0����������������������������������������������������������������������������������������������������ustar �jtauber�������������������������jtauber���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������� GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. <one line to give the program's name and a brief idea of what it does.> Copyright (C) <year> <name of author> 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 the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. <signature of Ty Coon>, 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Library General Public License instead of this License. ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������leonardo-0.4.1/lib/���������������������������������������������������������������������������������0040755�0000765�0000765�00000000000�10167570055�013763� 5����������������������������������������������������������������������������������������������������ustar �jtauber�������������������������jtauber����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������leonardo-0.4.1/lib/auth.py��������������������������������������������������������������������������0100755�0000765�0000765�00000011420�10167570124�015271� 0����������������������������������������������������������������������������������������������������ustar �jtauber�������������������������jtauber����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������# # Copyright (C) 2003-2004 James Tauber # # 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 # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # """ This module deals with session and user management. """ # session status codes OK = "ok" WRONG_IP = "different ip address" UNKNOWN_SID = "unknown sid" NO_SID = "no sid in cookie" NO_COOKIE = "no cookie" class SessionManager: def __init__(self, request, data_dir): self.request = request self.data_dir = data_dir self.session_db = None def check_session(self): """Returns the current session status as triple: code, user_id, session_id""" if self.request.cookie: import Cookie ip_address = self.request.remote_address cookie = Cookie.SimpleCookie(self.request.cookie) if "session_id" in cookie: sid = cookie["session_id"].value if self.has_session(sid): session_uid, session_ip_address = self.get_session(sid) if ip_address == session_ip_address: return OK, session_uid, sid else: # spoof return WRONG_IP, None, sid else: # unknown session ID return UNKNOWN_SID, None, sid else: # no session ID in cookie return NO_SID, None, None else: # no cookie return NO_COOKIE, None, None def get_sessions(self): """Get the session database, loading from disk if necessary""" if not self.session_db: import anydbm self.session_db = anydbm.open(self.data_dir + "sessions_db", "c") return self.session_db def create_session(self, uid, ip_address): """Create a new session for the given user at the given IP address""" sid = generate_id(uid, ip_address) self.get_sessions()[sid] = " ".join((uid, ip_address)) if hasattr(self.get_sessions(), "sync"): self.get_sessions().sync() return sid def get_session(self, sid): """Get the session info for the given session ID. Returned as pair: user_id, ip_address""" return self.get_sessions()[sid].split(" ") def has_session(self, sid): """Does the given session ID exist?""" return self.get_sessions().has_key(sid) def delete_session(self, sid): """Delete the session with the given ID. Has effect of logging user out""" del self.get_sessions()[sid] if hasattr(self.get_sessions(), "sync"): self.get_sessions().sync() def generate_id(uid, ip_address): """Generate a new session ID""" import md5, time, base64 m = md5.new() m.update('this is just a fun little sentence to get things started') m.update(str(time.time())) m.update(uid) m.update(ip_address) return base64.encodestring(m.digest())[:-3].replace("/", "$") class UserManager: def __init__(self, request, data_dir): self.request = request self.user_db = None self.data_dir = data_dir def get_users(self): """Get the user database, loading from disk if necessary""" if not self.user_db: import anydbm self.user_db = anydbm.open(self.data_dir + "user_db", "c") return self.user_db def known_user(self, user_id): """Is the given user known?""" return self.get_users().has_key(user_id) def get_password(self, user_id): """Get the (hashed) password for given user""" return self.get_userinfo(user_id)[2] def get_userinfo(self, user_id): """Get info for the given user. Returned as triple: user_id, name, (hashed) password""" return self.get_users()[user_id].split("|") def correct_password(self, user_id, passwd): """Is the given password correct for the given user?""" import sha return (self.known_user(user_id) and self.get_password(user_id) == sha.sha(passwd).hexdigest()) ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������leonardo-0.4.1/lib/core.py��������������������������������������������������������������������������0100755�0000765�0000765�00000006203�10167570124�015263� 0����������������������������������������������������������������������������������������������������ustar �jtauber�������������������������jtauber����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������# # Copyright (C) 2003-2004 James Tauber # # 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 # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # import request_response import filesystem import providers.manager import providers.static import providers.css import providers.login_logout import providers.editform import providers.put import providers.blog import providers.atom import providers.draft import providers.menu import providers.page def dispatcher(config): request = request_response.Request(config) lfs = filesystem.LeonardoFileSystem(config.lfs_root) # RESOURCE PROVIDERS resource_manager = providers.manager.ProviderManager() # menu provider menu_provider = providers.menu.MenuProvider(resource_manager, lfs, config) # register resource providers resource_manager.register_provider(providers.static.StaticFileProvider(config)) resource_manager.register_provider(providers.css.CSSProvider(lfs, config)) resource_manager.register_provider(providers.login_logout.LoginLogoutProvider(resource_manager, lfs, config)) resource_manager.register_provider(providers.editform.EditFormProvider(resource_manager, lfs, config)) resource_manager.register_provider(providers.put.PutProvider(resource_manager, lfs, config)) resource_manager.register_provider(providers.blog.BlogProvider(resource_manager, lfs, config)) resource_manager.register_provider(providers.atom.AtomProvider(resource_manager, lfs, config)) resource_manager.register_provider(providers.draft.DraftProvider(resource_manager, lfs, config)) resource_manager.register_provider(menu_provider) resource_manager.register_provider(providers.page.PageProvider(resource_manager, lfs, config)) menu_provider.register_provider(providers.login_logout.menu_part) menu_provider.register_provider(providers.editform.edit_menu_part) menu_provider.register_provider(providers.draft.draft_menu_part) resource_id = request.relative_path resource = resource_manager.get(resource_id, request, None) # @@@ we could just pass the resource into the constructor response = request_response.Response() response.set_content_type(resource.get_mime_type()) response.set_content(resource.get_content()) # @@@ bit of a hack if hasattr(resource, "status"): response.set_status(resource.status) if hasattr(resource, "cookie"): response.set_cookie(resource.cookie) if hasattr(resource, "expiry"): response.set_header("Expires", 0) response.send() ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������leonardo-0.4.1/lib/filesystem.py��������������������������������������������������������������������0100644�0000765�0000765�00000010261�10167570124�016513� 0����������������������������������������������������������������������������������������������������ustar �jtauber�������������������������jtauber����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������# # Copyright (C) 2003-2004 James Tauber # # 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 # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # """ This module abstracts the access to file contents and file attributes. Alternative backend data stores such as databases or version control systems could be implemented by implementing an identical interface. This implementation works by storing each "file" as a directory with the extension ".ldv". The directory may then contain not only the content (potentially in multiple forms) but additional metadata, annotations, etc. """ import os class LeonardoFileSystem: def __init__(self, root): self.root = root # check access to filesystem root if not os.access(self.root, os.R_OK): # @@@ improve response to user raise "can't access filesystem root" # @@@ at present you are required to specify the content type to # @@@ determine the extension to use for the content file. # @@@ it would be nice if this were optional but it's not clear # @@@ how ambiguities should be handled. def get(self, key, content_type): return LeonardoFile(self, key, content_type) def get_children(self, key): """ Returns a tuple of: - list of directories that are children of the key - list of leonardo pages that are children of the key """ directories = [] files = [] # @@@ factor out commonalities with LeonardoFile d = self.root + key.strip("/") if os.path.isdir(d) and not d.endswith(".ldv"): for f in os.listdir(d): # @@@ factor out ignore list if os.path.isdir(d + "/" + f) and f not in [".svn"]: if f.endswith(".ldv"): files.append(f[:-4]) else: directories.append(f) directories.sort() directories.reverse() files.sort() files.reverse() return directories, files class LeonardoFile: def __init__(self, filesystem, key, content_type): self.filesystem = filesystem self.key = key self.content_type = content_type self.content = None # @@@ refactor to filesystem? def __get_directory(self): return self.filesystem.root + self.key.strip("/") + ".ldv/" # @@@ refactor to filesystem? def __get_content_filename(self): return self.__get_directory() + "__content__." + self.content_type def exists(self): try: f = file(self.__get_content_filename()) f.close() return True except IOError: return False # @@@ make private? def load_content(self): f = file(self.__get_content_filename()) s = f.read() f.close() self.content = s def get_content(self): if not self.content: self.load_content() return self.content def get_lastmod(self): import os ST_MTIME = 8 return os.stat(self.__get_content_filename())[ST_MTIME] def set_content(self, content): path = self.__get_content_filename() directory = path[:path.rfind("/")] try: d = file(directory) d.close() except: import os try: os.makedirs(directory) except: pass f = file(path, "w") f.write(content) f.close() �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������leonardo-0.4.1/lib/providers/�����������������������������������������������������������������������0040755�0000765�0000765�00000000000�10167570055�016000� 5����������������������������������������������������������������������������������������������������ustar �jtauber�������������������������jtauber����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������leonardo-0.4.1/lib/providers/__init__.py������������������������������������������������������������0100644�0000765�0000765�00000001477�10167570124�020114� 0����������������������������������������������������������������������������������������������������ustar �jtauber�������������������������jtauber����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������# # Copyright (C) 2003-2004 James Tauber # # 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 # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # """ Package for Leonardo resource providers. """�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������leonardo-0.4.1/lib/providers/atom.py����������������������������������������������������������������0100755�0000765�0000765�00000010651�10167570124�017312� 0����������������������������������������������������������������������������������������������������ustar �jtauber�������������������������jtauber����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������# # Copyright (C) 2003-2004 James Tauber # # 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 # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # import time import templates.atom as template from blog import Walker from web_resource import TopLevelResource class AtomProvider: def __init__(self, resource_manager, lfs, config): self.resource_manager = resource_manager self.lfs = lfs self.config = config self.atom_path = config.atom_path self.full_atom_path = config.full_atom_path def get(self, resource_id, request, main_resource): if resource_id == self.atom_path: return AtomResource(resource_id, self.resource_manager, self.lfs, request, self.config, full=False) elif resource_id == self.full_atom_path: return AtomResource(resource_id, self.resource_manager, self.lfs, request, self.config, full=True) else: return None class AtomResource(TopLevelResource): def __init__(self, resource_id, resource_manager, lfs, request, config, full): TopLevelResource.__init__(self, resource_id, 'text/xml; charset="utf-8"') if full: formatter = FullAtomFormatter(resource_manager, config) else: formatter = AtomFormatter(resource_manager, config) walker = Walker(formatter, config.blog_prefix, lfs) self.content = walker.all(request, self) def get_content(self): return self.content class AtomFormatter: def __init__(self, resource_manager, config): self.resource_manager = resource_manager self.atom_path = config.atom_path self.site_url = config.site_url self.blog_title = config.blog_title self.blog_prefix = config.blog_prefix self.blog_author = config.blog_author self.shown_modified = False def header(self): blog_title = self.blog_title blog_url = self.site_url + self.blog_prefix blog_author = self.blog_author return template.atom_header % locals() def footer(self): return template.atom_footer % locals() def no_entries(self): return template.atom_no_entries % locals() def entry(self, year, month, day, entry, request, main_resource): page_key = "%s/%s/%s/%s/%s" % (self.blog_prefix, year, month, day, entry) page = self.resource_manager.get(page_key, request, main_resource) iso_time = time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime(page.get_lastmod())) title = page.get_title() html_link = self.site_url + page_key if not self.shown_modified: self.shown_modified = True s = template.atom_modified % locals() else: s = "" modified = iso_time issued = iso_time s += template.atom_entry % locals() return s class FullAtomFormatter(AtomFormatter): def entry(self, year, month, day, entry, request, main_resource): page_key = "%s/%s/%s/%s/%s" % (self.blog_prefix, year, month, day, entry) page = self.resource_manager.get(page_key, request, main_resource) iso_time = time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime(page.get_lastmod())) title = page.get_title() html_link = self.site_url + page_key if not self.shown_modified: self.shown_modified = True s = template.atom_modified % locals() else: s = "" modified = iso_time issued = iso_time content = page.get_html() s += template.atom_full_entry % locals() return s ���������������������������������������������������������������������������������������leonardo-0.4.1/lib/providers/blog.py����������������������������������������������������������������0100755�0000765�0000765�00000014444�10167570124�017301� 0����������������������������������������������������������������������������������������������������ustar �jtauber�������������������������jtauber����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������# # Copyright (C) 2003-2004 James Tauber # # 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 # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # import templates.blog as template import wiki from web_resource import PagePart from page import HTMLPage, HTMLPage404 YEARS = ["2004", "2005"] MONTHS = ["01", "02", "03", "04", "05", "06", "07", "08", "09", "10", "11", "12"] DAYS = [ "01", "02", "03", "04", "05", "06", "07", "08", "09", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "20", "21", "22", "23", "24", "25", "26", "27", "28", "29", "30", "31"] class BlogProvider: def __init__(self, resource_manager, lfs, config): self.resource_manager = resource_manager self.lfs = lfs self.config = config self.blog_prefix = config.blog_prefix self.site_url = config.site_url def get(self, resource_id, request, main_resource): if not resource_id.startswith(self.blog_prefix): return None blog_path = resource_id[len(self.blog_prefix):] year, month, day, entry = None, None, None, None path_components = blog_path.split("/") if len(path_components) == 1: pass elif len(path_components) == 2: year = path_components[1] elif len(path_components) == 3: year, month = path_components[1:] elif len(path_components) == 4: year, month, day = path_components[1:] elif len(path_components) == 5: year, month, day, entry = path_components[1:] else: return HTMLPage404(resource_id, self.resource_manager, request, self.config) if year and year not in YEARS: return HTMLPage404(resource_id, self.resource_manager, request, self.config) if month and month not in MONTHS: return HTMLPage404(resource_id, self.resource_manager, request, self.config) if day and day not in DAYS: return HTMLPage404(resource_id, self.resource_manager, request, self.config) if entry: return None # we don't need to handle it @@@ although we could to add date/permalink else: page_part = BlogPagePart(resource_id, self.resource_manager, request, self.lfs, self.config, year, month, day) return HTMLPage(resource_id, page_part, self.resource_manager, request, self.config) class BlogPagePart(PagePart): def __init__(self, resource_id, resource_manager, request, lfs, config, year, month, day): PagePart.__init__(self, resource_id) formatter = HTMLFormatter(resource_manager, config) walker = Walker(formatter, config.blog_prefix, lfs) blog_title = config.blog_title if day: title = template.blog_title_day % locals() content = walker.day(year, month, day, request, self) elif month: title = template.blog_title_month % locals() content = walker.month(year, month, request, self) elif year: title = template.blog_title_year % locals() content = walker.year(year, request, self) else: title = template.blog_title_all % locals() content = walker.all(request, self) self.title = title self.html = content class HTMLFormatter: def __init__(self, resource_manager, config): self.resource_manager = resource_manager self.site_url = config.site_url self.blog_prefix = config.blog_prefix def header(self): return "" def footer(self): return "" def no_entries(self): return template.blog_no_entries % locals() def entry(self, year, month, day, entry, request, main_resource): page_key = "%s/%s/%s/%s/%s" % (self.blog_prefix, year, month, day, entry) page = self.resource_manager.get(page_key, request, main_resource) body = page.get_html() date = "%s/%s/%s" % (year, month, day) html_link = self.site_url + page_key return template.blog_entry % locals() class Walker: def __init__(self, formatter, blog_prefix, lfs): self.formatter = formatter self.blog_prefix = blog_prefix self.lfs = lfs def all(self, request, main_resource): return \ self.formatter.header() + \ self.descend(self.blog_prefix, lambda year: self.year(year, request, main_resource)) + \ self.formatter.footer() def year(self, year, request, main_resource): return self.descend(self.blog_prefix + "/" + year, lambda month: self.month(year, month, request, main_resource)) def month(self, year, month, request, main_resource): return self.descend("%s/%s/%s" % (self.blog_prefix, year, month), lambda day: self.day(year, month, day, request, main_resource)) def day(self, year, month, day, request, main_resource): return self.descend("%s/%s/%s/%s" % (self.blog_prefix, year, month, day), lambda entry: self.entry(year, month, day, entry, request, main_resource)) def entry(self, year, month, day, entry, request, main_resource): return self.formatter.entry(year, month, day, entry, request, main_resource) def descend(self, key, func): directories, files = self.lfs.get_children(key) children = directories + files content = "" if children: for child in children: content += func(child) else: content = self.formatter.no_entries() return content ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������leonardo-0.4.1/lib/providers/css.py�����������������������������������������������������������������0100755�0000765�0000765�00000003006�10167570124�017136� 0����������������������������������������������������������������������������������������������������ustar �jtauber�������������������������jtauber����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������# # Copyright (C) 2003-2004 James Tauber # # 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 # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # from web_resource import TopLevelResource, FileObjectResource class CSSProvider: def __init__(self, lfs, config): self.lfs = lfs self.config = config self.css_id = config.css_id def get(self, resource_id, request, main_resource): if resource_id == self.css_id: return CSSResource(self.lfs, self.config) else: return None class CSSResource(FileObjectResource, TopLevelResource): def __init__(self, lfs, config): css_id = config.css_id TopLevelResource.__init__(self, css_id, "text/css") FileObjectResource.__init__(self, lfs.get(css_id, "css")) def is_read_only(self): return False # allow editing ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������leonardo-0.4.1/lib/providers/draft.py���������������������������������������������������������������0100755�0000765�0000765�00000013050�10167570124�017446� 0����������������������������������������������������������������������������������������������������ustar �jtauber�������������������������jtauber����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������# # Copyright (C) 2003-2004 James Tauber # # 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 # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # import re import time import templates.draft as template from providers.page import HTMLPage, ForbiddenPage from web_resource import PagePart def draft_menu_part(request, resource, config): if request.logged_in(): draft_href = config.draft_href menu_part = template.draft_menu % locals() else: menu_part = "" return menu_part # form field names page_title_name = "page_title" page_content_name = "page_content" # requires 'blog' and 'put' modules class DraftProvider: def __init__(self, resource_manager, lfs, config): self.resource_manager = resource_manager self.lfs = lfs self.config = config self.draft_prefix = config.draft_prefix def get(self, resource_id, request, main_resource): if not resource_id.startswith(self.draft_prefix): return None if not request.logged_in(): return ForbiddenPage(resource_id, self.resource_manager, request, self.config) draft_path = resource_id[len(self.draft_prefix):].strip("/") if draft_path == "": # top level page_part = DraftListPagePart(resource_id, self.resource_manager, request, self.lfs, self.config) return HTMLPage(resource_id, page_part, self.resource_manager, request, self.config) else: # individual draft page if main_resource != None: # if not a top-level request, return None # don't handle it here outer_page_part = DraftPagePart(resource_id, self.resource_manager, request, self.config) return HTMLPage(resource_id, outer_page_part, self.resource_manager, request, self.config) class DraftListPagePart(PagePart): def __init__(self, resource_id, resource_manager, request, lfs, config): status = "" # @@@ how can this be avoided? page_title_name = globals()["page_title_name"] page_content_name = globals()["page_content_name"] form_content = template.draft_initial_form_content % locals() # @@@ posting should really be done as a separate method if request.method == "POST": page_title = request.fields.getvalue(page_title_name, "") page_content = request.fields.getvalue(page_content_name, "") if page_title: draft_resource_id = config.draft_prefix + "/" + re.sub(' ', '_', page_title.lower()) page = resource_manager.get(draft_resource_id, request, self) if page.exists(): status = template.draft_existing_title % locals() form_content = page_content else: page.set_content(page_content) status = template.draft_success % locals() else: status = template.draft_no_title % locals() form_content = page_content title = template.draft_title # get list of drafts drafts = lfs.get_children(config.draft_prefix)[1] if drafts: draft_items = "" for draft_title in drafts: draft_link = config.draft_href + "/" + draft_title draft_items += template.draft_item % locals() draft_list = template.draft_list % locals() else: draft_list = template.empty_draft_list % locals() action = config.draft_href content = template.draft_page % locals() self.title = title self.html = content class DraftPagePart(PagePart): def __init__(self, resource_id, resource_manager, request, config): PagePart.__init__(self, resource_id) page_part = resource_manager.get(resource_id, request, self) title = page_part.get_title() content = page_part.get_html() page_content = page_part.get_content() page_content = re.sub(r'&', '&', page_content) page_content = re.sub(r'<', '<', page_content) page_content = re.sub(r'>', '>', page_content) page_content = re.sub(r'"', '"', page_content) draft_path = resource_id[len(config.draft_prefix):].strip("/") post_action = config.put_href resource_name = config.put_resource_field page_content_name = config.put_content_field resource_id_to_put = draft_path content = template.draft_post_to_wiki_form % locals() + content resource_id_to_put = config.blog_prefix + "/%04d/%02d/%02d/" % tuple(time.localtime()[:3]) + draft_path content = template.draft_post_to_blog_form % locals() + content self.title = title self.html = content def is_read_only(self): return False ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������leonardo-0.4.1/lib/providers/editform.py������������������������������������������������������������0100755�0000765�0000765�00000007113�10167570124�020162� 0����������������������������������������������������������������������������������������������������ustar �jtauber�������������������������jtauber����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������# # Copyright (C) 2003-2004 James Tauber # # 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 # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # import templates.editform as template from providers.page import HTMLPage, ForbiddenPage from web_resource import PagePart def edit_menu_part(request, resource, config): if request.logged_in() and not resource.is_read_only(): edit_page_href = config.edit_href + "?" + config.edit_resource_field + "=" + resource.get_id() menu_part = template.edit_menu % locals() else: menu_part = "" return menu_part class EditFormProvider: def __init__(self, resource_manager, lfs, config): self.resource_manager = resource_manager self.lfs = lfs self.config = config self.edit_path = config.edit_path self.resource_name = config.edit_resource_field def get(self, resource_id, request, main_resource): if resource_id != self.edit_path: return None if not request.logged_in(): return ForbiddenPage(resource_id, self.resource_manager, request, self.config) resource_to_edit = request.fields.getvalue(self.resource_name) outer_page_part = EditFormPagePart(resource_id, resource_to_edit, self.resource_manager, request, self.config) html_page = HTMLPage(resource_id, outer_page_part, self.resource_manager, request, self.config) html_page.expiry = 0 return html_page class EditFormPagePart(PagePart): def __init__(self, resource_id, resource_to_edit, resource_manager, request, config): post_action = config.put_href page_content_name = config.put_content_field resource_name = config.put_resource_field cancel_action = resource_to_edit if resource_to_edit: page = resource_manager.get(resource_to_edit, request, self) if page.is_read_only(): self.title = template.edit_read_only_title % locals() self.html = template.edit_read_only_title % locals() else: time = None site_title = config.site_title if page.exists(): page_title = page.get_title() title = template.page_title % locals() page_content = page.get_content() time = page.get_lastmod() else: # new wiki word title = template.new_page_title % locals() page_content = template.new_page_content % locals() content = template.edit_form % locals() self.title = title self.html = content else: self.title = template.edit_missing_id_title % locals() self.html = template.edit_missing_id_content % locals() �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������leonardo-0.4.1/lib/providers/login_logout.py��������������������������������������������������������0100755�0000765�0000765�00000011501�10167570124�021046� 0����������������������������������������������������������������������������������������������������ustar �jtauber�������������������������jtauber����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������# # Copyright (C) 2003-2004 James Tauber # # 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 # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # from auth import OK from providers.page import HTMLPage import templates.login_logout as template from web_resource import PagePart def menu_part(request, resource, config): if request.logged_in(): user_id = request.get_user() logout_href = config.logout_href menu_part = template.logged_in_menu % locals() else: login_href = config.login_href menu_part = template.logged_out_menu % locals() return menu_part class LoginLogoutProvider: def __init__(self, resource_manager, lfs, config): self.resource_manager = resource_manager self.lfs = lfs self.config = config self.login_path = config.login_path self.logout_path = config.logout_path def get(self, resource_id, request, main_resource): if resource_id == self.login_path: page_part = LoginPagePart(resource_id, request, self.config) elif resource_id == self.logout_path: page_part = LogoutPagePart(resource_id, request, self.config) else: return None html_page = HTMLPage(resource_id, page_part, self.resource_manager, request, self.config) html_page.expiry = 0 # @@@ put on HTMLPage itself if hasattr(page_part, "cookie"): html_page.cookie = page_part.cookie return html_page class LoginPagePart(PagePart): def __init__(self, resource_id, request, config): PagePart.__init__(self, resource_id) # form fields email_name = "email" password_name = "passwd" session_status = request.check_session() action = config.login_href if request.method == "GET": status_code = session_status[0] if session_status[0] == OK: user_id = session_status[1] content = template.already_logged_in % locals() else: content = template.login_form % locals() else: # POST # log out if someone else session_status = request.check_session() if session_status[0] == OK: request.delete_session(session_status[2]) email = request.fields.getvalue(email_name, "") passwd = request.fields.getvalue(password_name, "") status_code = session_status[0] if request.correct_password(email, passwd): # @@@ should consider putting cookie creation code on # response object import Cookie ip_address = request.remote_address self.cookie = Cookie.SimpleCookie() self.cookie["session_id"] = request.create_session(email, ip_address) self.cookie["session_id"]["expires"] = 86400 # @@@ parameterize out self.cookie["session_id"]["path"] = "/" # @@@ should be home_href # bit of a hack, inserting the cookie after the fact request.cookie = self.cookie content = template.successful_login % locals() else: content = template.incorrect_password % locals() self.title = template.login_title self.html = content class LogoutPagePart(PagePart): def __init__(self, resource_id, request, config): PagePart.__init__(self, resource_id) action = config.logout_href if request.method == "GET": content = template.confirm_logout % locals() else: # POST session_status = request.check_session() if session_status[0] == OK: request.delete_session(session_status[2]) user_id = session_status[1] content = template.successful_logout % locals() else: status_code = session_status[0] content = template.not_logged_in % locals() self.title = template.logout_title self.html = content �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������leonardo-0.4.1/lib/providers/manager.py�������������������������������������������������������������0100755�0000765�0000765�00000003362�10167570124�017765� 0����������������������������������������������������������������������������������������������������ustar �jtauber�������������������������jtauber����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������# # Copyright (C) 2003-2004 James Tauber # # 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 # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # class ProviderManager: def __init__(self): self.providers = [] def register_provider(self, provider): self.providers.append(provider) def get(self, resource_id, request, main_resource): """ Attempts to retrieve the resource with the given resource_id. request is also passed in to provide authentication information and HTTP parameters. @@@ This could be improved. main_resource is None if the requested resource is what the client directly requested. Otherwise it is the actual resource object requested by the client (and the resource in resource_id is just a component being retrieved to contribute to the the main_resource). """ for provider in self.providers: resource = provider.get(resource_id, request, main_resource) if resource: return resource return None������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������leonardo-0.4.1/lib/providers/menu.py����������������������������������������������������������������0100644�0000765�0000765�00000005050�10167570124�017310� 0����������������������������������������������������������������������������������������������������ustar �jtauber�������������������������jtauber����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������# # Copyright (C) 2003-2004 James Tauber # # 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 # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # import templates.page as template from web_resource import PagePart class MenuProvider: def __init__(self, resource_manager, file_system, config): self.resource_manager = resource_manager self.file_system = file_system self.config = config self.menu_key = config.menu_key self.menu_providers = [] def register_provider(self, part_provider): self.menu_providers.append(part_provider) def get(self, resource_id, request, main_resource): if resource_id == self.menu_key: return MenuPagePart(self.resource_manager, self.menu_providers, request, main_resource, self.config) else: return None class MenuPagePart(PagePart): """ The page part representing the full menu, including the content provided by menu providers. This resource is never requested directly, only as part of a page. The main (or inner) menu, which forms part of the content of this resource, is a resource in its own right with id config.main_menu_key. The main menu can be requested directly and edited like a normal page part resource. """ def __init__(self, resource_manager, menu_providers, request, main_resource, config): self.main_menu = resource_manager.get(config.main_menu_key, request, self) self.menu_providers = menu_providers self.request = request self.main_resource = main_resource self.config = config def get_html(self): html = self.main_menu.get_html() html += template.menu_separator % locals() for provider in self.menu_providers: html += provider(self.request, self.main_resource, self.config) return html ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������leonardo-0.4.1/lib/providers/page.py����������������������������������������������������������������0100755�0000765�0000765�00000015501�10167570124�017265� 0����������������������������������������������������������������������������������������������������ustar �jtauber�������������������������jtauber����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������# # Copyright (C) 2003-2004 James Tauber # # 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 # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # from wiki import WikiFormatter import templates.page as template from web_resource import PagePart, TopLevelResource, FileObjectResource class PageProvider: def __init__(self, resource_manager, lfs, config): self.resource_manager = resource_manager self.lfs = lfs self.config = config self.home_key = config.home_key self.formatter = WikiFormatter(config.home_href, lambda x: self.wiki_page(x).get_html()) def get(self, resource_id, request, main_resource): if resource_id == "": resource_id = self.home_key page_part = self.wiki_page(resource_id) if main_resource: # if there's a parent resource, we're done return page_part if page_part.exists(): return HTMLPage(resource_id, page_part, self.resource_manager, request, self.config) else: # new page if request.logged_in(): return PageDoesNotExist(resource_id, self.resource_manager, request, self.config) else: return HTMLPage404(resource_id, self.resource_manager, request, self.config) def wiki_page(self, key): # note that the content type "wiki04" is used to allow concurrent use # of alternative wiki formats. other engines may look for other # content types. return WikiPagePart(key, self.lfs.get(key, "wiki04"), self.formatter) class HTMLPage(TopLevelResource): def __init__(self, resource_id, page_part, resource_manager, request, config): TopLevelResource.__init__(self, resource_id, "text/html") self.resource_manager = resource_manager self.site_title = config.site_title self.site_sub_title = config.site_sub_title self.css_href = config.css_href self.home_href = config.home_href self.copyright_holder = config.copyright_holder self.home_key = config.home_key self.menu_key = config.menu_key self.make_html(page_part, request) def exists(self): return True def get_content(self): return self.html def is_read_only(self): return True def make_html(self, page_part, request): title = page_part.get_title() if title: title = "%s : %s" % (self.site_title, title) else: title = self.site_title content = page_part.get_html() time = page_part.get_lastmod() menu = self.resource_manager.get(self.menu_key, request, page_part).get_html() self.html = self.page_template(title, menu, content, time) def page_template(self, title, menu, content, lastmod): if lastmod: import time lastmod = time.strftime(template.time_format, time.gmtime(lastmod)) lastmod_display = template.lastmod_display % locals() else: lastmod_display = "" if self.site_sub_title: site_sub_title = self.site_sub_title sub_title = template.sub_title % locals() else: sub_title = "" site_title = self.site_title home_page = self.home_href copyright_holder = self.copyright_holder # @@@ this makes page module dependent on css module css_href = self.css_href return template.page_template % locals() class ForbiddenPage(HTMLPage): def __init__(self, resource_id, resource_manager, request, config): HTMLPage.__init__(self, resource_id, None, resource_manager, request, config) self.status = "403 Forbidden" def make_html(self, page_part, request): site_title = self.site_title title = template.operation_not_allowed_title % locals() content = template.operation_not_allowed % locals() time = None menu = self.resource_manager.get(self.menu_key, request, self).get_html() self.html = self.page_template(title, menu, content, time) class PageDoesNotExist(HTMLPage): def __init__(self, resource_id, resource_manager, request, config): HTMLPage.__init__(self, resource_id, None, resource_manager, request, config) self.status = "404 Not Found" def make_html(self, page_part, request): site_title = self.site_title title = template.page_does_not_exist_title % locals() content = template.page_does_not_exist % locals() time = None menu = self.resource_manager.get(self.menu_key, request, self).get_html() self.html = self.page_template(title, menu, content, time) def is_read_only(self): return False class HTMLPage404(HTMLPage): def __init__(self, resource_id, resource_manager, request, config): HTMLPage.__init__(self, resource_id, None, resource_manager, request, config) self.status = "404 Not Found" def make_html(self, page_part, request): site_title = self.site_title title = template.title_404 % locals() content = template.content_404 % locals() time = None menu = self.resource_manager.get(self.menu_key, request, self).get_html() self.html = self.page_template(title, menu, content, time) def is_read_only(self): return True class WikiPagePart(FileObjectResource, PagePart): def __init__(self, resource_id, file_object, formatter): PagePart.__init__(self, resource_id) FileObjectResource.__init__(self, file_object) self.formatter = formatter self.title = None def get_html(self): return self.formatter.format(self.get_content()) def get_title(self): if not self.title: self.__update_title() return self.title def is_read_only(self): return False def __update_title(self): self.title = self.formatter.extract_title(self.file_object.get_content()) �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������leonardo-0.4.1/lib/providers/put.py�����������������������������������������������������������������0100755�0000765�0000765�00000006563�10167570124�017171� 0����������������������������������������������������������������������������������������������������ustar �jtauber�������������������������jtauber����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������# # Copyright (C) 2003-2004 James Tauber # # 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 # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # """ POSTing to the 'put' resource is intended as an alternative to PUTing a resource in cases like HTML forms where you can't directly PUT. """ import templates.put as template from providers.page import HTMLPage, ForbiddenPage from web_resource import PagePart class PutProvider: def __init__(self, resource_manager, lfs, config): self.resource_manager = resource_manager self.lfs = lfs self.config = config self.put_path = config.put_path def get(self, resource_id, request, main_resource): if resource_id != self.put_path: return None if request.method == "GET": return ForbiddenPage(resource_id, self.resource_manager, request, self.config) if not request.logged_in(): return ForbiddenPage(resource_id, self.resource_manager, request, self.config) page_part = PutPagePart(resource_id, self.resource_manager, request, self.config) return HTMLPage(resource_id, page_part, self.resource_manager, request, self.config) class PutPagePart(PagePart): def __init__(self, resource_id, resource_manager, request, config): PagePart.__init__(self, resource_id) resource_to_put = request.fields.getvalue(config.put_resource_field) if resource_to_put: page = resource_manager.get(resource_to_put, request, self) if page.is_read_only(): title = template.put_read_only_title % locals() content = template.put_read_only_content % locals() else: new_content = request.fields.getvalue(config.put_content_field) if page.exists(): replace = True else: replace = False page.set_content(new_content) resource_link = config.home_href + resource_to_put resource_label = resource_to_put if replace: title = template.put_replace_title % locals() content = template.put_replace_content % locals() else: title = template.put_create_title % locals() content = template.put_create_content % locals() else: # no resource_id provided title = template.put_missing_id_title % locals() content = template.put_missing_id_content % locals() self.title = title self.html = content ���������������������������������������������������������������������������������������������������������������������������������������������leonardo-0.4.1/lib/providers/static.py��������������������������������������������������������������0100755�0000765�0000765�00000005113�10167570124�017636� 0����������������������������������������������������������������������������������������������������ustar �jtauber�������������������������jtauber����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������# # Copyright (C) 2003-2004 James Tauber # # 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 # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # from web_resource import TopLevelResource class StaticFileProvider: def __init__(self, config): self.static_dir = config.static_dir def get(self, resource_id, request, main_resource): if resource_id[:4] not in ["1996", "1997", "1998", "1999", "2000", "2001", "2002", "2003", "2004", "2005"]: return None path = resource_id if path[-1] == "/": path += "index.html" # @@@ should extend this to other filenames path = path.strip("/") ext = path[path.rfind("."):] if ext in [".htm", ".html"]: mime_type = "text/html" elif ext in [".jpg", ".jpeg"]: mime_type = "image/jpeg" elif ext in [".css"]: mime_type = "text/css" else: mime_type = "text/plain" try: f = file(self.static_dir + path, "rb") x = f.read() f.close() return StaticFile(path, x, mime_type) except: return StaticFile404(path) class StaticFile(TopLevelResource): def __init__(self, resource_id, content, mime_type): TopLevelResource.__init__(self, resource_id, mime_type) self.content = content def exists(self): return True def get_content(self): return self.content def get_lastmod(self): # @@@ return 0 def is_read_only(self): return True # @@@ for now class StaticFile404(StaticFile): def __init__(self, resource_id): StaticFile.__init__(self, resource_id, "File Not Found.", "text/plain") self.status = "404 Not Found" def exists(self): return False �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������leonardo-0.4.1/lib/request_response.py��������������������������������������������������������������0100644�0000765�0000765�00000006554�10167570124�017747� 0����������������������������������������������������������������������������������������������������ustar �jtauber�������������������������jtauber����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������# # Copyright (C) 2003-2004 James Tauber # # 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 # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # """ This module defines request and response objects for handling communication from and to the client (e.g. web browser). """ import os import cgi import sys import auth from auth import OK class Request: def __init__(self, config): self.env = os.environ self.fields = cgi.FieldStorage() self.path_info = self.env.get("PATH_INFO", "/") self.relative_path = self.path_info.strip("/") self.method = self.env.get("REQUEST_METHOD", "") self.query = self.env.get("QUERY_STRING", "") self.remote_address = self.env.get("REMOTE_ADDR", "") self.cookie = self.env.get("HTTP_COOKIE", None) self.session_mgr = auth.SessionManager(self, config.data_dir) self.user_mgr = auth.UserManager(self, config.data_dir) def logged_in(self): """Is the user logged in?""" return (self.session_mgr.check_session()[0] == OK) def get_user(self): """Get the current user""" return self.session_mgr.check_session()[1] def correct_password(self, user_id, passwd): """Is the given user id, password combination correct?""" return self.user_mgr.correct_password(user_id, passwd) def check_session(self): return self.session_mgr.check_session() def create_session(self, uid, ip_address): return self.session_mgr.create_session(uid, ip_address) def delete_session(self, sid): return self.session_mgr.delete_session(sid) class Response: def __init__(self): self.status = None self.cookie = None self.content_type = None self.content = None self.headers = {} def set_content_type(self, content_type): self.content_type = content_type def set_status(self, status): self.status = status def set_content(self, content): self.content = content def set_header(self, name, value): self.headers[name] = value def set_cookie(self, cookie): self.cookie = cookie def send(self): if self.status: sys.stdout.write("Status: %s\n" % self.status) for name, value in self.headers.items(): sys.stdout.write("%s: %s\n" % (name, value)) if self.cookie: sys.stdout.write("%s\n" % self.cookie) if self.content_type: sys.stdout.write("Content-type: %s\n" % self.content_type) if self.content: sys.stdout.write("\n") sys.stdout.write(self.content) ����������������������������������������������������������������������������������������������������������������������������������������������������leonardo-0.4.1/lib/templates/�����������������������������������������������������������������������0040755�0000765�0000765�00000000000�10167570055�015761� 5����������������������������������������������������������������������������������������������������ustar �jtauber�������������������������jtauber����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������leonardo-0.4.1/lib/templates/__init__.py������������������������������������������������������������0100644�0000765�0000765�00000001466�10167570124�020073� 0����������������������������������������������������������������������������������������������������ustar �jtauber�������������������������jtauber����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������# # Copyright (C) 2003-2004 James Tauber # # 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 # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # """ Package for Leonardo templates. """����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������leonardo-0.4.1/lib/templates/atom.py����������������������������������������������������������������0100644�0000765�0000765�00000003200�10167570124�017260� 0����������������������������������������������������������������������������������������������������ustar �jtauber�������������������������jtauber����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������# # Copyright (C) 2003-2004 James Tauber # # 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 # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # atom_header = """\ <?xml version="1.0" encoding="utf-8"?> <feed version="0.3" xmlns="http://purl.org/atom/ns#" xml:lang="en"> <title>%(blog_title)s %(blog_author)s """ atom_footer = """ """ atom_no_entries = "" atom_modified = """ %(iso_time)s """ atom_entry = """ %(title)s %(modified)s %(issued)s %(html_link)s """ atom_full_entry = """ %(title)s %(modified)s %(issued)s %(html_link)s """ leonardo-0.4.1/lib/templates/blog.py0100644000076500007650000000215310167570124017251 0ustar jtauberjtauber# # Copyright (C) 2003-2004 James Tauber # # 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 # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # blog_title_day = "%(blog_title)s %(year)s/%(month)s/%(day)s" blog_title_month = "%(blog_title)s %(year)s/%(month)s" blog_title_year = "%(blog_title)s %(year)s" blog_title_all = "%(blog_title)s" blog_no_entries = """

No Entries.

""" blog_entry = """ %(body)s

%(date)s (permalink)

""" leonardo-0.4.1/lib/templates/draft.py0100644000076500007650000000450510167570124017431 0ustar jtauberjtauber# # Copyright (C) 2003-2004 James Tauber # # 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 # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # draft_initial_form_content = "Enter content of new page here." draft_existing_title = "Page with that title already exists in drafts." draft_no_title = "Please provide a title." draft_success = "Successfully created '%(draft_resource_id)s'." draft_title = "Drafts" draft_item = """
  • %(draft_title)s
  • """ draft_list = """
      %(draft_items)s
    """ empty_draft_list = """

    No drafts.

    """ draft_page = """

    %(status)s

    Drafts

    Existing

    %(draft_list)s

    New Draft Page

    Page Title:

    Cancel """ draft_menu = """

    Drafts

    """ draft_post_to_wiki_form = """

    to %(resource_id_to_put)s

    """ draft_post_to_blog_form = """

    to %(resource_id_to_put)s

    """leonardo-0.4.1/lib/templates/editform.py0100644000076500007650000000303710167570124020141 0ustar jtauberjtauber# # Copyright (C) 2003-2004 James Tauber # # 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 # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # page_title = "%(site_title)s : EDIT %(page_title)s" new_page_title = "%(site_title)s: NEW PAGE" new_page_content = "==%(resource_to_edit)s==\n\nType content here." edit_form = """

    Cancel """ edit_menu = """

    Edit Page

    """ edit_missing_id_title = "Missing Resource ID" edit_missing_id_content = "Missing Resource ID." edit_read_only_title = "Can't edit read-only resource" edit_read_only_content = "Can't edit read-only resource."leonardo-0.4.1/lib/templates/login_logout.py0100644000076500007650000000407010167570124021027 0ustar jtauberjtauber# # Copyright (C) 2003-2004 James Tauber # # 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 # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # login_title = "Login" logout_title = "Logout" already_logged_in = """

    You are already logged in as %(user_id)s

    """ login_form = """
    Email Address
    Password
     

    %(status_code)s

    """ successful_login = """

    Successful login, %(email)s from %(ip_address)s

    """ incorrect_password = """

    Incorrect Email/Password.

    """ + login_form confirm_logout = """

    To confirm logout, press the button below.

    """ successful_logout = """

    You are now logged out, %(user_id)s

    """ not_logged_in = """

    You are not currently logged in.

    %(status_code)s

    """ logged_in_menu = """

    Logged in as: %(user_id)s

    Logout

    """ logged_out_menu = """

    Login

    """ leonardo-0.4.1/lib/templates/page.py0100644000076500007650000000373610167570124017252 0ustar jtauberjtauber# # Copyright (C) 2003-2004 James Tauber # # 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 # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # page_does_not_exist = """

    Page does not exist. Create it with Edit Page if you like.

    """ page_does_not_exist_title = "%(site_title)s: PAGE DOES NOT EXIST" operation_not_allowed = """

    Operation not allowed.

    """ operation_not_allowed_title = "%(site_title)s: OPERATION NOT ALLOWED" title_404 = "%(site_title)s: FILE NOT FOUND" content_404 = """

    File not found.

    """ time_format = "%A %d %B, %Y" lastmod_display = """This page last modified %(lastmod)s""" sub_title = "

    %(site_sub_title)s

    " page_template = """ %(title)s

    %(site_title)s

    %(sub_title)s
    %(content)s
    %(lastmod_display)s Copyright 2003-2004 %(copyright_holder)s
    """ menu_separator = """

     

    """ leonardo-0.4.1/lib/templates/put.py0100644000076500007650000000234310167570124017137 0ustar jtauberjtauber# # Copyright (C) 2003-2004 James Tauber # # 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 # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # put_replace_title = "Resource replaced" put_replace_content = 'Resource %(resource_label)s replaced.' put_create_title = "Resource created" put_create_content = 'Resource %(resource_label)s created.' put_missing_id_title = "Missing Resource ID" put_missing_id_content = "Missing Resource ID." put_read_only_title = "Can't PUT read-only resource" put_read_only_content = "Can't PUT read-only resource."leonardo-0.4.1/lib/web_resource.py0100755000076500007650000000633410167570124017024 0ustar jtauberjtauber# # Copyright (C) 2003-2004 James Tauber # # 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 # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # class Resource: """ A resource is content object that can be returned to the client / browser in one or more forms either as the entire response or as a part of the response. Typically sublcassed, a resource object wraps a data source (such as a leonardo "file") and may provide format translation (such as from a wiki format to HTML). Examples of resources include wiki pages, blog entries, menus, etc. """ def __init__(self, resource_id): self.resource_id = resource_id def get_id(self): return self.resource_id class PagePart(Resource): """ A resource that is part of a page. The key method that PagePart adds is get_html(). If the page part is editable, then get_content() will return the underlying content that can be edited. """ def __init__(self, resource_id, title=None, html=None): Resource.__init__(self, resource_id) self.title = title self.html = html def get_title(self): return self.title def get_html(self): return self.html def get_lastmod(self): return 0 def is_read_only(self): return True # default class TopLevelResource(Resource): """ A resource that is returned directly to the client / browser rather than as part of an enclosing resource. """ def __init__(self, resource_id, mime_type): Resource.__init__(self, resource_id) self.mime_type = mime_type def get_mime_type(self): return self.mime_type class FileObjectResource: """ A mix-in for resources that wrap an LFS file object. """ # @@@ this should potentially abstract multiple forms of the same resource. # @@@ at the moment, this assumes, as does the LeonardoFileSystem, that # @@@ a file object (although not necessarily a "file") is only of one type. def __init__(self, file_object): self.file_object = file_object def exists(self): return self.file_object.exists() def get_title(self): return self.resource_id def get_lastmod(self): return self.file_object.get_lastmod() def get_content(self): return self.file_object.get_content() def set_content(self, content): self.file_object.set_content(content) def is_read_only(self): return True # default leonardo-0.4.1/lib/wiki.py0100755000076500007650000001107510167570124015301 0ustar jtauberjtauber# # Copyright (C) 2003-2004 James Tauber # # 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 # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # import re class WikiFormatter: def __init__(self, link_prefix, content_getter): self.link_prefix = link_prefix self.content_getter = content_getter def sub_link(self, matchobj): wiki_word = matchobj.group(1) link = self.link_prefix + re.sub(' ', '_', wiki_word).lower() return """%s""" % (link, wiki_word) def insert(self, matchobj): wiki_word = matchobj.group(1) link = re.sub(' ', '_', wiki_word).lower() return self.content_getter(link) def extract_title(self, page_content): m = re.match(r'(?m)^==([^=]+)==', page_content) if m: return m.group(1) else: return None def format(self, page_content): s = page_content s = re.sub(r'&', '&', s) s = re.sub(r'<', '<', s) s = re.sub(r'>', '>', s) # ==...== to h2 s = re.sub(r'(?m)^==([^=]+)==', '

    \\1

    ', s) # ===...=== to h3 s = re.sub(r'(?m)^===([^=]+)===', '

    \\1

    ', s) # ====...==== to h4 s = re.sub(r'(?m)^====([^=]+)====', '

    \\1

    ', s) # * ... to list s = re.sub(r'(?m)^\* (.+)$', '
  • \\1
  • ', s) # five spaces at start of line to blockquote s = re.sub(r'(?m)^ (.+)$', '
    \\1
    ', s) s = re.sub(r'(\s*)
    ', '\\1', s) # four spaces at start of line to pre s = re.sub(r'(?m)^ (.+)$', '
    \\1
    ', s) s = re.sub(r'(\s*)
    ', '\\1', s)
        
            # *...* bold
            s = re.sub(r'\*([^\*]+)\*', '\\1', s)
        
            # ''...'' italic
            s = re.sub(r"''([^']+)''", '\\1', s)
        
            # --- to emdash
            s = re.sub(r'---', '—', s)
        
            # empty lines -> paragraph boundaries
            s = re.sub(r'(?m)^\s*$', '

    \n

    ', s) s = "

    " + s + "

    " s = re.sub(r'

    \s*

  • ', '
    • ', s) s = re.sub(r'
    • \s*

      ', '
    ', s) s = re.sub(r'

    \s*

    ', '

    ', s) s = re.sub(r'

    \s*

    ', '', s) s = re.sub(r'

    \s*

    ', '

    ', s) s = re.sub(r'

    \s*

    ', '', s) s = re.sub(r'

    \s*

    ', '

    ', s) s = re.sub(r'

    \s*

    ', '', s) s = re.sub(r'

    ', '', s) # [..] to wiki link s = re.sub(r'\[([ \.A-Za-z0-9]+)\]', self.sub_link, s) URL = r'((?:ftp|http):[^ \]]+)' # [http:..] to external link s = re.sub(r'\['+URL+r'\]', '\\1', s) # [http:... ...] to titled and entitled external link s = re.sub(r'\['+URL+r' "([^"]+)" ([^\]]+)\]', '\\3', s) # [http:... ...] to titled external link s = re.sub(r'\['+URL+r' ([^\]]+)\]', '\\2', s) # [:... ...] to titled local link s = re.sub(r'\[:/([^ \]]+) ([^\]]+)\]', '\\2' % self.link_prefix, s) s = re.sub(r'\[:([^ \]]+) ([^\]]+)\]', '\\2', s) # [image:... ...] to local image s = re.sub('\[image:/([^ \]]+) ([^\]]+)\]', '\\2' % self.link_prefix, s) s = re.sub('\[image:([^ \]]+) ([^\]]+)\]', '\\2', s) # [insert:...] to insert the contents of a wiki page s = re.sub(r'\[insert:([^\]]+)\]', self.insert, s) # [amazon:... ...] to link to Amazon using ISBN and link title s = re.sub(r'\[amazon:(\d+) ([^\]]+)\]', '\\2', s) return s leonardo-0.4.1/README0100644000076500007650000000102410167570124014064 0ustar jtauberjtauberLeonardo 0.4.1 http://jtauber.com/leonardo Leonardo is a personal wiki and blog server written in Python. QUICKSTART * Edit cgi-bin/leonardo_config.py and change data_dir to the correct path * Edit cgi-bin/leonardo.py and change the sys.append to include the correct path to the Leonardo lib directory * Run python test_server.py * To create a user, cd into bin and run create_user.py (bin must be parallel to data otherwise edit USER_DB) * Further customize by editing cgi-bin/leonardo_config.py leonardo-0.4.1/test_server.py0100755000076500007650000000360510167570124016135 0ustar jtauberjtauber#!/usr/bin/env python # # Copyright (C) 2003-2004 James Tauber # # 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 # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # # Simulates Apache with the following directive: # # ScriptAlias / /cgi-bin/leonardo.py/ # # Useful for getting going before you deploy on an actual webserver import CGIHTTPServer from BaseHTTPServer import HTTPServer import sys sys.path.append("cgi-bin") if sys.argv[1:]: port = int(sys.argv[1]) else: port = 8000 import os class Handler(CGIHTTPServer.CGIHTTPRequestHandler): def do_POST(self): # for some reason the query string from the last request hangs # around without this. os.environ['QUERY_STRING'] = "" self.cgi_info = "/cgi-bin", "leonardo.py/" + self.path self.run_cgi() def do_GET(self): # for some reason the query string from the last request hangs # around without this. os.environ['QUERY_STRING'] = "" self.cgi_info = "/cgi-bin", "leonardo.py/" + self.path self.run_cgi() server_address = ("", port) httpd = HTTPServer(server_address, Handler) import webbrowser webbrowser.open("http://localhost:%s/" % port, 1) print "Serving HTTP on port", port, "..." httpd.serve_forever()