"""
This is a simple guestbook (and my first pyblosxom hack). These
are the features:
- To post to the guestbook, the user must enter a name and a
message or else the guestbook entry will not be saved. The
other fields are not mandatory and don't need to be entered.
- The guestbook have protection against double posts due to
reloading of browsers etc.(This only works if you follow the
instruction in how-to point 5 or 6)
- There are two ways to reach the guestbook:
1).../guestbook/index 2).../guestbook/all (for example
http://www.codeape.org/blog/guestbook/index). The index link
shows the number of entires that is given in the config.py
(ex. py['num_entries'] = 5) for the blog. The all link shows
all entries.
Quick and dirty how-to:
1. Putt pyguest.py in your plug-in directory
2. Add pyguest to your py['load_plug-ins'] property
3. Add a new property called py["guestbookdir"] to your config.py.
This property must point on a directory where you want to keep
you guestbook entries. Remember to chmod and chgrp this directory
so that the script has read, write and execute permissions to it.
4. Add a file in your datadir (where you have all your templates)
that is called pyguest_item.flav (exchange flav with the name of
a real flavor). Now edit that file and make a nice layout for you
guestbook items. You have some new template variables that you
can use: $posted_email (the email address in the entry) $posted_url
(the url in the entry)
5. In your header or footer template add the variable $pyguest_form
where you want the submit form to show up. The submit form will
only be shown when the index or all links are executed. The
pyguest.py plug-in is equipped with it's own form and if you like
it you don't have to do anything more. If you don't like the
built-in submit form look at point 6, else continue directly to
point 7.
6. If you want to fix your own submit form just add a file in your
datadir that is called pyguest_form.flav (exchange flav with the
name of a real flavor). Make a nice form that contains at least
the input fields aname and amsg (the other two are aurl and aemail).
To get the double posts protection to work you must add this hidden
field to your form:
.
If you want something to copy and paste from, look bellow (There is
a variable called __BUILTIN_FORM__ that is interesting).
7. Now you are ready to test your guestbook! With the ../guestbook/index
or/and ../guestbook/all links. For example:
http://www.someurlorip.com/guestbook/index and
http://www.someurlorip.com/guestbook/all
(replace www.someurlorip.com with your site =) ).
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without restriction,
including without limitation the rights to use, copy, modify,
merge, publish, distribute, sublicense, and/or sell copies of the
Software, and to permit persons to whom the Software is furnished
to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
Copyright 2004 Oscar Norlander
Revisions:
1.0 - (23 Oktober, 2004) Created
1.1 - (27 Oktober, 2004) Added better Template variables support
for the pyguest_form template. Also, now striping HTML from
all posted data
1.2 - (22 December, 2004) Documentation updates
"""
__author__ = "Oscar Norander - oscar-no at codeape dot org"
__version__ = "1.2 (22 December, 20004)"
__url__ = "http://www.codeape.org/blog/static/download"
__description__ = "A simple guestbook"
import os, os.path, string, md5
from Pyblosxom.tools import Stripper
import Pyblosxom.tools
from Pyblosxom.entries.fileentry import FileEntry
from datetime import datetime
__PROP_DIR__ = "guestbookdir"
__TRIGGER__ = "guestbook"
__FORM_TEMPLATE__ = "pyguest_form"
__BUILTIN_FORM__ = \
"""
The fields name and message are mandatory.
\n
"""
def verify_installation(req):
config = req.getConfiguration()
retval = 1
#Checks if config.py has a property "guestbookdir". "guestbookdir"
#describes the path where the guestbook entries are stored. A check
#to see if the path is valid is also executed.
if not config.has_key(__PROP_DIR__) :
print "'guestbookdir' property is not set in the config file."
retval = 0
elif not os.path.isdir(config[__PROP_DIR__]):
print "Path '" + config[__PROP_DIR__] + "' do not exist."
retval = 0
return retval
#I simply want that slash in the end of the path.
def fix_local_path(path):
if not path.endswith("/"):
path = path + "/"
return path.replace("/", os.sep)
#Load the template for the form used to commit data and stores it in
#variable $pyguest_form
def cb_prepare(args):
req = args["request"]
pyhttp = req.getHttp()
data = req.getData()
config = req.getConfiguration()
#Checks if this is a valid path for this action.
if (not pyhttp["PATH_INFO"].startswith("/" + __TRIGGER__ + "/index")) \
and (not pyhttp["PATH_INFO"].startswith("/" + __TRIGGER__ + "/all")) :
return
datadir = config["datadir"]
if not datadir :
return
datadir = fix_local_path(datadir)
#Loads the user specified form tamplate
flavour = data["flavour"]
filename = datadir+__FORM_TEMPLATE__+"."+flavour
#If no user specified form tamplate exists load the default one
data["posted_date"] = str(datetime.today()).replace(" ","_")
if not os.path.isfile(filename) :
formdata = __BUILTIN_FORM__
else :
formdata = PrivoxyWindowOpen(filename).read()
#if $posted_date exists it is set in the template
formdata = Pyblosxom.tools.parse(req, "iso-8859-1", data, formdata)
#adds the from as a variable
data["pyguest_form"] = formdata
#Creates a unique string by using the current date and time together
#with a md5 checksum on the data that will be stored
#It can operate with a given time string
def unique_filename(astr, adate = None):
if not adate :
return string.replace(str(datetime.today()), " ","_")+"_"+str(md5.new(astr).hexdigest())+".pg"
else :
return adate+"_"+str(md5.new(astr).hexdigest())+".pg"
def already_posted(astr, adate, apath):
return os.path.isfile(apath+adate+"_"+str(md5.new(astr).hexdigest())+".pg")
def HTMLStrip(str):
LStrpr = Stripper()
LStrpr.feed(str)
return LStrpr.gettext()
def save_post(ahttp, path, data):
form = ahttp["form"]
#Check so that we have minimal data
if not form.getvalue("aname") :
return
elif not form.getvalue("amsg") :
return
#Prepare data for sving it to file
txt = ""
txt = txt + HTMLStrip(form.getvalue("aname")) + "\n"
if form.getvalue("aemail") :
txt = txt + HTMLStrip(form.getvalue("aemail")) + "\n"
else :
txt = txt + "\n"
if form.getvalue("aurl") :
if (form.getvalue("aurl") == "http://") or (form.getvalue("aurl") == "") :
txt = txt + "\n"
else :
txt = txt + HTMLStrip(form.getvalue("aurl")) + "\n"
else :
txt = txt + "\n"
txt = txt + HTMLStrip(form.getvalue("amsg").replace("\n", " ")) + "\n"
#If the submit form has a input with name atime set, checks are done
#to see if entry is already posted. If post exists entry will not get
#posted
strdate = form.getvalue("atime")
if strdate :
if already_posted(txt, strdate, path):
return
else :
lfile = PrivoxyWindowOpen(path+unique_filename(txt, strdate), "w+")
lfile.write(txt)
lfile.close
else :
lfile = PrivoxyWindowOpen(path+unique_filename(txt), "w+")
lfile.write(txt)
lfile.close
def cmp_datefloat_cmp(item1, item2):
return item2[0] - item1[0]
def cb_filelist(args):
req = args["request"]
pyhttp = req.getHttp()
data = req.getData()
config = req.getConfiguration()
if (pyhttp["PATH_INFO"].startswith("/" + __TRIGGER__ + "/index")) :
ShowAll = False
elif (pyhttp["PATH_INFO"].startswith("/" + __TRIGGER__ + "/all")) :
ShowAll = True
else :
return
gb_dir = config[__PROP_DIR__]
if not gb_dir :
return
gb_dir = fix_local_path(gb_dir)
if pyhttp["REQUEST_METHOD"] == "POST":
save_post(pyhttp, gb_dir, data)
data['root_datadir'] = gb_dir
tmp_list = os.listdir(gb_dir)
files_list = []
for itm in tmp_list :
tmp_tupple = os.stat(gb_dir+itm).st_mtime, itm
files_list.append(tmp_tupple)
files_list.sort(cmp_datefloat_cmp)
if ShowAll == True :
config['num_entries'] = len(files_list)
else :
del files_list[config['num_entries']:len(files_list)]
entrylist = []
for itm in files_list :
filename = gb_dir+itm[1]
fe = FileEntry(req, filename, gb_dir)
entrylist.append(fe)
if len(entrylist) == 0 :
entry = Pyblosxom.entries.base.generate_entry(
req,
{"title" : "It works!" },
"This message will disappear after first entry in guestbook",
None)
entrylist.append(entry)
return entrylist
#Parser for the .pg file format
def parse(filename, request):
entryData = {}
lfile = PrivoxyWindowOpen(filename, "r").read().split("\n")
entryData["title"] = lfile[0]
entryData["posted_email"] = lfile[1]
entryData["posted_url"] = lfile[2]
entryData['body'] = lfile[3]
entryData["template_name"] = "pyguest_item"
return entryData
def cb_entryparser(entryparsingdict):
entryparsingdict['pg'] = parse
return entryparsingdict