#!/usr/bin/env python
# -*- coding: iso-8859-1 -*-
"""clippingkeeper.py: show a simple form to save a weblog feed's entry for clipping
To customize:
- change the appropriate values in clippingkeeper.cfg
"""
__author__ = "Andrew Ittner "
__version__ = "0.2.4, $Revision$"
__date__ = "$Date$"
__copyright__ = "Copyright (c) 2007 Andrew Ittner"
__license__ = "Expat (aka MIT)"
# built-in
import cgi, traceback, os, cgitb, datetime, ConfigParser, types
# 3rd-party
import HTMLTags as htags
from pyPgSQL import PgSQL
import mx.DateTime as mxDT
# enable trackback on errors
cgitb.enable()
# global variables
global lstcategories
# list of categories for filing an entry
lstcategories = []
def main():
"""primary routine: check if this is show or save, handle data appropriately
possible 'action' querystring values:
start: show the blank form
save: save the data & show the new data
test: show basic info (cgi testing)
view: view all records in db
update: set isnew=1 on selected entries & show them
info: show bookmarklets and other data
"""
# get options first
getoptions()
# prep vars
strform = '' # form for data entry or viewing
strtitle = '' #
contents
strh1 = '' #
contents
stage = 0 #0=show form for editing; 10 = save data & show results
strqs = '' # for debugging
strqstitle = '' # title param, if any
strqsurl = '' # url param, if any
dateadded = None
#dbg = {'dbpath_absolute': os.path.abspath(DBPATH),
#'dbpathexists_absolute': os.path.exists(os.path.abspath(DBPATH)),
#'dbpathexists': os.path.exists(DBPATH)}
dbg = {'dbhost': DBHOST,
'dbname': DBNAME,
'dbuser': DBUSER}
qs = os.environ.get('QUERY_STRING', None)
strqs = unicode(qs)
if qs == None:
# assume this is the start; show form
stage = 0
else:
# split it out
dctqs = cgi.parse_qs(qs)
# check for action
if dctqs.has_key('action'):
if dctqs['action'][0] == 'start':
stage = 0
elif dctqs['action'][0] == 'save':
stage = 10
dateadded = datetime.datetime.now()
elif dctqs['action'][0] == 'test':
stage = 200
elif dctqs['action'][0] == 'view':
stage = 300
elif dctqs['action'][0] == 'update':
stage = 400
elif dctqs['action'][0] == 'info':
stage = 500
else:
# unknown stage
stage = -1
strform = "unknown stage; dctqs['action'] == %s" % dctqs['action']
else:
stage = 0
# per http://www.voidspace.org.uk/python/articles/cgi_web_applications_two.shtml
#encoding = dctqs.get('_charset_', 'UTF8')
if dctqs.has_key('title'):
strqstitle = dctqs['title'][0] #.decode(encoding)
else:
strqstitle = '' #'no title given'
if dctqs.has_key('url'):
strqsurl = dctqs['url'][0]#.decode(encoding)
# what to do?
if stage == 0:
strtitle = 'Add entry'
strh1 = 'Add an entry'
strform = makeform(False, title=unicode(strqstitle, 'utf-8'), url=unicode(strqsurl, 'utf-8'))
elif stage == 10:
strtitle = 'Saved entry'
objform = cgi.FieldStorage()
# deal with unicode title
thetitle = objform.getvalue('inputtitle', '').decode('latin_1').encode('utf-8')
strform = makeform(True,
title=unicode(thetitle, 'utf-8'),
url=objform.getvalue('inputurl'),
category=objform.getvalue('inputcats', '{no category}'),
text=objform.getvalue('inputcktext'),
dateadded=dateadded)
tplresults = savedata(title=thetitle,
url=objform.getvalue('inputurl'),
category=objform.getvalue('inputcats', '{no category}'),
text=objform.getvalue('inputcktext'),
dateadded=dateadded)
if tplresults[0]:
# saved successfully
strh1 = 'Entry save results (new id: %s)' % tplresults[1]
else:
# problem saving
strh1 = 'Failed to save: %s' % tplresults[1]
elif stage == 200:
# testing; retrieve test.txt & display
strtitle = 'Testing'
strh1 = 'Testing area'
testcontents = ''
try:
testcontents = file('clippingkeeper.cfg', 'r').read()
except:
testcontents = traceback.format_exc()
strform = str(htags.P('Contents of "clippingkeeper.cfg" in the same directory as clippingkeeper.py.') + \
htags.PRE(testcontents))
elif stage == 300:
# show existing entries
strtitle = 'View all records'
strh1 = 'Viewing all records'
# view type: all, new, used
viewtype = -1
if not dctqs.has_key('view'):
# view all
viewtype = -1
elif dctqs['view'][0] == 'new':
# view new (isnew=1)
viewtype = 1
elif dctqs['view'][0] == 'used':
viewtype = 0
else:
# default to viewtype = -1
pass
result = getdata(viewtype=viewtype)
if result[0]:
entries = result[1]
# make form to mark entries as used
strform = '
'
else:
strform = 'getdata() failed:
%s
' % result[1]
elif stage == 400:
strtitle = 'Updated records'
strh1 = 'Records recently marked "used"'
strform = ''
# get form contents
form = cgi.FieldStorage()
if form.has_key('entries'):
# update db
entriestoset = tuple([int(x) for x in form.getlist('entries')])
strform = str(htags.P('entries to set: %s' % str(entriestoset)))
if not updateentries(entriestoset):
# warn user
strform = str(htags.P('updateentries(%s) failed.' % str(entriestoset)))
else:
# get list of updated entries
strform += str(htags.P('entries set successfully'))
result = getdata(entriestoset)
#strform += str(htags.P(str(result)))
if result[0]:
entries = result[1]
for category in sorted(entries.keys()):
strform += makecategoryview(category, entries[category], False)
strform += ""
strform += makeentriesoutputbox('rest', entries.values()[0])
else:
strform += str(htags.P('getdata failed'))
else:
for k in form.keys():
if k == 'entries':
strform += str(htags.P('Entries = %s' % form.getlist(k)))
else:
strform += str(htags.P('%s = %s' % (cgi.escape(k), cgi.escape(form.getvalue(k, '')))))
elif stage == 500:
# info
strtitle = 'Information about clippingkeeper'
strh1 = 'Info'
servername = os.environ.get('SERVER_NAME', 'SERVER')
JS_TITLEANDURL = """javascript:window.open('http://%(servername)s/clippingkeeper.py?title=' + encodeURI(document.title) + '&url=' + encodeURIComponent(document.URL), 'es');return;"""
JS_SELECTION = """javascript:if (top.frames.length > 0){for (var i=0; i0){break;}}} else {var r=document.selection.createRange();}var
w=window.open('http://%(servername)s/clippingkeeper.py?title=' + encodeURI(r.text) + '&url=' + encodeURIComponent(r.parentElement().toString()), 'es');"""
tags = [htags.H2('Bookmarklets'),
htags.P('The following are the two types of javascript bookmarklets for accessing clippingkeeper.' + \
'Currently, these are only tested on Opera.')]
tags.append(htags.H3('Single page'))
tags.append(htags.P('uses document.title and document.URL'))
tags.append(htags.P(htags.A('Title and url', Href=JS_TITLEANDURL % {'servername': servername})))
tags.append(htags.H3('Selected text'))
tags.append(htags.P('uses selected text in current document OR first document in set of frames that has selected text'))
tags.append(htags.P(htags.A('Selected text', Href=JS_SELECTION % {'servername': servername})))
tags.append(htags.H2('Notes'))
tags.append(htags.P('Replace "SERVER" with the server and port combination that serves clippingkeeper.py, if the server and port were not customized.'))
strform = '\n'.join([unicode(h) for h in tags])
else:
strtitle = "Limbo"
strh1 = "A problem occurred."
strform = "Unanticipated code path."
# return value
headers = u'Content-Type: text/html\nCache-Control: no-cache\n\n'
doctype = u'\n'
links = u' | '.join(linklist())
strreturn = u'%(headers)s%(doctype)s%(strtitle)s\n' + \
'\n' + \
'\n
%(strh1)s
\n%(strform)s\n\n' + \
'
%(links)s
\n'
return strreturn.encode('utf-8') % vars() #{'title': '?', 'form': strform, 'h1': '?'}
def linklist():
"""return a list of the available internal links as anchor elements
returns list"""
links = [htags.A('start', Href='%s?action=start' % CGIURL),
htags.A('view all', Href='%s?action=view' % CGIURL),
htags.A('view new', Href='%s?action=view&view=new' % CGIURL),
htags.A('view used', Href='%s?action=view&view=used' % CGIURL),
htags.A('info', Href='%s?action=info' % CGIURL)]
return [str(a) for a in links]
def makeform(reportvalues=False, title='', url='', category='',
text='', dateadded=None):
"""create the