#!/usr/bin/env python2.2 # Copyright (C) 2004 Paul Harrison # 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 """ Aether - web/blog script Aether is a script for managing blogs and web pages entirely from the web. Design goals: The script should readable. All operations should be trivial, and part of the usual interface: * Editing pages * Creating pages and deleting pages * Renaming pages * Attaching files and deleting files The interface itself should be minimal and functional. "Features" are to be minimized: * No login, no cookies * All admin functions on the page itself (elegantly and discretely) * No secret interfaces, no codes to remember The script should handle anything that is thrown at it: * Unicode in pages * Unicode page names * Page and file names containing < > & " and whitespace Aether is based around an extensible markup language (not XML), which is translated to HTML on the fly. Features such as blogging are implemented as markup functions. Change log: 1.1 - 19 March 2004 Initial release. 1.2 - 29 March 2004 Support for ErrorDocument, based on a patch by Neil Brown. Simplified security model (old model unnecessary given ErrorDocument, just use multiple copies of script) _code.py now evalfile'd not imported More comments. Note: remove "import script" line from _code.py when upgrading from 1.1 1.3 - Locking added. Page content sent before sidebars (using CSS tomfoolery). [left] [right] tags behave differently, [top] [bottom] tags added. "standard_header" page no longer used, instead use page called "default" (header may now be set using the [top] tag). Allow use of variables before they are set (eg [_insert_later] tag). [toc] table of contents. Style-sheet may be modified using the [style] tag (eg in "default" page). 1.4 - Basic revision tracking. Attachments form converted to ') else: bottom = u'' return make_http_page(u"""\ Editing [link [_insert _base]/[bold [_insert _old_name]] [page [_insert _old_name]]] [_insert_html _form] """ + text + u""" [right [prepend] [rule] [small [sans [link History of this page [url [_insert _revision_url]]]] [sans [link Aether reference manual [url [_insert _reference_url]]]]] [rule] ] [bottom [append] [_insert_html _add_bottom]] """, { '_editing' : 1, '_form' : form, '_revision_url' : host_url + script_base + u'?action=history;' + u'name=' + quote_paranoid(new_name) + u';password=' + quote_paranoid(password), '_reference_url' : host_url + script_base + u'?action=manual', '_base' : host_url + page_base, '_add_bottom' : bottom, '_old_name' : name, 'name' : new_name}) def _check_password(password_given): if password and password != password_given: Error('Incorrect password') def _attachments_check_security(query): if not allow_attachments: raise Error('File attachment disabled') _check_password(unquote_paranoid(query.get('password',u''))) def handle_attach(_ignore_, query): """ Attach a file to a page (from within the attachments iframe). """ _attachments_check_security(query) name = unquote_paranoid(query.get('name',u'')) data = query['file'] filename = query['filename'] filename = path.basename(filename) check_for_filename_hack(filename) ensure_dir_exists(path.join(file_dir,name)) file = utf8_open(path.join(file_dir,name,filename), 'wb') file.write(data) file.close() return handle_attachments(None, query) def handle_delete(_ignore_, query): """ Delete an attached file (from within the attachments iframe). """ _attachments_check_security(query) name = unquote_paranoid(query.get('name',u'')) for key in query: if query[key] != u'on' or \ key[:8] != 'checkbox': continue filename = unquote_paranoid(key[8:]) check_for_filename_hack(filename) utf8_unlink(path.join(file_dir,name,filename)) return handle_attachments(None, query) def handle_attachments(_ignore_, query): """ Display form for attaching and deleting files. (this is an