#!/usr/bin/python from BaseHTTPServer import HTTPServer, BaseHTTPRequestHandler from urllib import quote, unquote_plus import sqlite3, os, sys, re, time PORT = 8000 DBNAME = 'default.db' # connect to DB, init if necessary def loadDB(): global DB print >> sys.stderr, 'Loading DB:', DBNAME needsInit = not os.path.exists(DBNAME) DB = sqlite3.connect(DBNAME) if needsInit: print >> sys.stderr, 'Initializing DB:', DBNAME cur = DB.cursor() cur.execute('create table node (title varchar(255) unique, body varchar(65535), time integer)') cur.execute('create table softlink (title1 varchar(255), title2 varchar(255), rank integer)') cur.execute('create index idx_softlink on softlink (title1, title2)') cur.close() postNode('home', 0, DEFAULT_HOME_NODE) DEFAULT_HOME_NODE = r''' Welcome to your Personal Everything!
Paragraphs/sections are individually editable and are separated by
on a line by itself. Once they are saved, you won't be able to see the
any more, but it's there. To create new paragraphs, just add one or more
s where desired, followed by text. When you save the paragraph, you will see the new paragraphs separately. To delete a paragraph, just remove all of its text and save it. Empty paragraphs are automatically removed.
Use brackets to create [links] (you enter: \[links]) and [this is a pipelink|pipelinks] (you enter: \[this is a pipelink|pipelinks]). To enter actual brackets, you can either use the HTML entities [ and ] or put a \ before any left brackets: \\[like this] Links to non-existent nodes will be displayed in [There is probably no node with this title.|red]. Links beginning with http:// will be identified as external links, like so: [http://www.google.com]. (The \[^] marks them as being external, even when [http://www.google.com|pipelinked].)
Allowed HTML tags: b, i, u, s, sup, sub, big, small, tt.
For more HTML, put at the very beginning of a paragraph. This will make the whole paragraph raw HTML (and hence disable linking and automatic line-breaking). Be careful with this, as it is probably possible to screw up a node accidentally with bad HTML.
'''
def htmlSafe(s):
return s.replace('&','&').replace('<','<').replace('>','>')
def unhtmlSafe(s):
return s.replace('>','>').replace('<','<').replace('&','&')
def decodeQuery(s):
d = {}
for kv in s.split('&'):
if '=' not in kv: continue
k, v = kv.split('=', 1)
d[k] = unquote_plus(v)
return d
def linker(m, softlink = None):
style = ''
if type(m) == str or type(m) == unicode: dest = text = str(m)
else: dest = text = m.group(1)
if '|' in text: dest, text = text.split('|', 1)
if dest[:7].lower() == 'http://': link = dest; text += '[^]'
else:
link = '/node/' + dest
if softlink and dest != softlink:
link += '?softlink=' + quote(softlink)
cur = DB.cursor()
cur.execute('select time from node where title=?', (dest,))
if not cur.fetchone(): style = 'style="color: red" '
cur.close()
return '%s' % (style, dest, link, text)
RE_LINKS = re.compile(r'(?%s%s>' % (m.group(1), m.group(2), m.group(1))
RE_ALLOWED_ENTITIES = re.compile(r'&(#\d+|[a-zA-Z0-9]+);')
def getNode(title):
body = getNodeBody(title)
exists = (body != None)
if not exists: body = []
display = '''\
'''
pi = 0
for p in body:
clean = p
# html mode
if p[:12] == '<html>':
p = unhtmlSafe(p[12:])
else:
# links and brackets
p = RE_LINKS.sub(lambda x: linker(x, title), p)
p = p.replace(r'\[', '[')
# html tags
oldp = None
while oldp != p:
oldp = p
p = RE_ALLOWED_TAGS.sub(RE_ALLOWED_TAGS_FUNC, p)
# html entities
p = RE_ALLOWED_ENTITIES.sub(lambda m: '&%s;' % m.group(1), p)
# automatic linebreaks
p = re.sub(r'\r?\n', '
', p)
# paragraph magic
display += ('
''' + title + ''' | ''' + ('delete' if exists else '') + ''' | database: ''' + DBNAME + ''' change |
')] while '' in lst: lst.remove('') return lst def postNode(title, pi, text): body = getNodeBody(title) if body == None: body = [] body[pi:pi+1] = map(htmlSafe, re.split(r'\r?\n
\r?\n', text)) body = '
'.join(body)
if not len(body): return deleteNode(title)
cur = DB.cursor()
cur.execute('insert or replace into node (title, body, time) values (?,?,?)', (title, body, time.time()))
cur.close()
DB.commit()
def softlinkNode(title1, title2):
if title1 == title2: return
if title1 > title2: title1, title2 = title2, title1
cur = DB.cursor()
cur.execute('update softlink set rank=rank+1 where title1=? and title2=?', (title1, title2))
if cur.rowcount == 0: # create softlink
cur.execute('insert into softlink values (?,?,?)', (title1, title2, 1))
cur.close()
DB.commit()
def deleteNode(title):
cur = DB.cursor()
cur.execute('delete from node where title=?', (title,))
cur.close()
DB.commit()
def doSearch(curnode, query):
cur = DB.cursor()
results = {}
for term in query.split():
cur.execute('select title from node where title like ?', ('%%%s%%' % term,))
for tup in cur.fetchall():
if tup[0] not in results: results[tup[0]] = 1
else: results[tup[0]] += 1
cur.close()
if not len(results): return # this will redirect to the nodeshell
html = 'Search results for %s
' % (query, query)
results = [(a, b) for b, a in results.items()]
results.sort(); results.reverse()
for rank, title in results:
html += linker(title, curnode)
return html
NICEBOX = '
%s | ||||
' + linker(ln, curnode) + ' | '; i += 1 if i == 5: html += '||||
| '; i += 1 return html + '