--- /dev/null
+#!/usr/bin/env python
+
+import web
+import os
+import datetime
+import re
+import smtplib
+import md5
+
+pwd = os.path.dirname( os.path.realpath( __file__ ) )
+
+web.config.debug = True
+
+monthnames = {"01": "January",
+ "02": "February",
+ "03": "March",
+ "04": "April",
+ "05": "May",
+ "06": "June",
+ "07": "July",
+ "08": "August",
+ "09": "September",
+ "10": "October",
+ "11": "November",
+ "12": "December"}
+
+urls = (
+ '/', 'pastweek',
+ '/week', 'pastweek' ,
+ '/month', 'pastmonth' ,
+ '/year', 'pastyear' ,
+ '/feed', 'feed' ,
+ '/(\d\d\d\d)/(\d\d)/(\d\d)', 'day' ,
+ '/(\d\d\d\d)-(\d\d)-(\d\d)', 'day' ,
+ '/(\d\d\d\d)/(\d\d)', 'month' ,
+ '/(\d\d\d\d)', 'year',
+ '', 'redir',
+ )
+
+## This is the way to do it in web.py 0.3+
+#app = web.application(urls, globals())
+
+## Workaround for autoreloading and sessions when using web.config.debug = True
+## Note: I don't actually use sessions
+#if web.config.get("_session") is None:
+# session = web.session.Session(app, web.session.DiskStore('sessions'), initializer={'count': 0})
+# web.config._session = session
+#else:
+# session = web.config._session
+
+# read the paragraphs from a file
+def readFile(filepath):
+ f = open(filepath)
+ lines = map(str.strip, f.readlines())
+ return makeParas(lines)
+
+def loadComment(filepath):
+ f = open(filepath)
+ nameline = f.readline().strip()
+ emailline = f.readline().strip()
+ websiteline = f.readline().strip()
+ timestamp = f.readline().strip()
+ commentbody = makeParas(map(str.strip, f.readlines()))
+ m = md5.new()
+ m.update(emailline.lower())
+ gravatar = "http://www.gravatar.com/avatar/%s?s=48&d=identicon" % str(m.hexdigest())
+ #timestamp = datetime.datetime.fromtimestamp(os.stat(filepath).st_mtime).isoformat()
+ return (nameline, emailline, websiteline, commentbody, timestamp, gravatar)
+
+def getCommentFiles(date): # Returns a list of paths to comment files associated with date
+ filelist = filter( lambda x: re.match(date, x), os.listdir(pwd + "/comments"))
+ return filelist
+
+# Collect lines into paragraph blocks. Returns a list of strings, each containing a well-formed HTML block.
+def makeParas(lines):
+ paragraphs = []
+ thispara = []
+ for line in lines:
+ if len(line) != 0:
+ thispara.append(line)
+ else:
+ paragraphs.append("\n".join(thispara))
+ thispara = []
+ if len(thispara) > 0:
+ paragraphs.append("\n".join(thispara))
+
+ # wrap paragraphs in <p></p> if they aren't other HTML tags that don't want to be wrapped in <p> tags
+ return map( lambda x: x if "<ol>" in x or "<ul>" in x or "<pre>" in x else "<p>" + x + "</p>", paragraphs)
+
+
+def getFileList(numdays=7):
+ files = os.listdir(pwd + "/entries")
+ today = datetime.date.today()
+ then = today - datetime.timedelta(days=numdays)
+ return filter( lambda x: x > then.isoformat() , sorted(files))
+
+class year:
+ def GET(self, theyear):
+ files = sorted(os.listdir(pwd + "/entries"))
+ filelist = filter( lambda x: re.match(theyear, x), files)
+ filelist = map( lambda x: pwd + "/entries/" + x, filelist)
+ # It makes more sense to sort fixed chunks of time in chronological order, rather than feed-style
+ #filelist.reverse()
+ dates = map( lambda filename: re.sub("(.*)(\d\d\d\d-\d\d-\d\d).txt", "\g<2>", filename), filelist )
+ entries = map( readFile, filelist)
+ commentcounts = map(len, map( getCommentFiles, dates))
+ render = web.template.render(pwd + "/templates")
+ # This mess is because web.py 0.2 doesn't include passing common useful functions to the template engine
+ web.template.Template.globals['xrange'] = xrange
+ web.template.Template.globals['len'] = len
+ print render.multiday(zip(dates, entries, commentcounts), "Entries from %s" % theyear)
+ # This is the web.py 0.3+ way to do it.
+ #return render.multiday(dates, entries, "Entries from %s" % theyear)
+
+class month:
+ def GET(self, theyear, themonth):
+ files = sorted(os.listdir(pwd + "/entries"))
+ filelist = filter( lambda x: re.match("%s-%s" % (theyear, themonth), x), files)
+ filelist = map( lambda x: pwd + "/entries/" + x, filelist)
+ #filelist.reverse()
+ dates = map( lambda filename: re.sub("(.*)(\d\d\d\d-\d\d-\d\d).txt", "\g<2>", filename), filelist )
+ entries = map( readFile, filelist)
+ commentcounts = map(len, map( getCommentFiles, dates))
+ render = web.template.render(pwd + "/templates")
+ web.template.Template.globals['xrange'] = xrange
+ web.template.Template.globals['len'] = len
+ print render.multiday(zip(dates, entries, commentcounts), "Entries from %s, %s" % (monthnames[themonth], theyear))
+
+class day:
+ def GET(self, year, month, day):
+ filename = pwd + "/entries/" + year + "-" + month + "-" + day + ".txt"
+ if os.path.isfile(filename):
+ paras = readFile(filename)
+ commentfilelist = os.listdir(pwd + "/comments")
+ files = filter(lambda x: re.match("(.*)" + year + "-" + month + "-" + day + "_(\d\d\d\d\d\d).txt$", x), commentfilelist)
+ files = sorted([pwd + "/comments/" + x for x in files])
+ comments = []
+ for f in files:
+ comments.append(loadComment(f))
+ render = web.template.render(pwd + "/templates")
+ web.template.Template.globals['xrange'] = xrange
+ web.template.Template.globals['len'] = len
+ print render.day("%s-%s-%s" % (year, month, day), paras, comments)
+ else:
+ render = web.template.render(pwd + "/templates")
+ web.template.Template.globals['xrange'] = xrange
+ web.template.Template.globals['len'] = len
+ print render.noentry("%s-%s-%s" % (year, month, day))
+
+
+ def POST(self, year, month, day):
+ i = web.input()
+ name = i.name.strip()
+ email = i.email.strip()
+ website = i.website.strip()
+ if website != "" and not website.startswith("http"):
+ website = "http://" + website
+ comment = i.comment.strip()
+ timestamp = datetime.datetime.today().isoformat()
+ # find a file name that isn't taken
+ fname = ""
+ for i in xrange(0, 1000000):
+ fname = pwd + "/pending/" + year + "-" + month + "-" + day + "_" + ("%06d" % i) + ".txt"
+ if not os.path.exists(fname):
+ break
+ f = open(fname, "a+")
+ f.write(name + "\n")
+ f.write(email + "\n")
+ f.write(website + "\n")
+ f.write(timestamp + "\n")
+ f.write(comment + "\n")
+ f.close()
+
+ s = smtplib.SMTP("127.0.0.1")
+ s.sendmail("shortlog@zarvox.org", ["drew.m.fisher@gmail.com"], "To: Drew Fisher <drew.m.fisher@gmail.com>\nFrom: Shortlog <shortlog@zarvox.org>\nSubject: [shortlog] new comment on %s-%s-%s\n\nName: %s\nEmail: %s\nWebsite: %s\nComment: %s" % (year, month, day, name, email, website, comment ))
+ s.quit()
+ web.header('Content-Type', 'text/html')
+ print "<html><body>Thanks! Your comment has been submitted and will be posted pending review.</body></html>"
+# paras = readFile(pwd + "/entries/" + year + "-" + month + "-" + day + ".txt")
+# render = web.template.render(pwd + "/templates")
+# web.template.Template.globals['xrange'] = xrange
+# web.template.Template.globals['len'] = len
+# print render.day("%s-%s-%s" % (year, month, day), paras)
+
+
+class pastyear:
+ def GET(self):
+ filelist = map( lambda x: pwd + "/entries/" + x, getFileList(365) )
+ filelist.reverse()
+ dates = map( lambda filename: re.sub("(.*)(\d\d\d\d-\d\d-\d\d).txt", "\g<2>", filename), filelist )
+ entries = map( readFile, filelist)
+ commentcounts = map(len, map( getCommentFiles, dates))
+ render = web.template.render(pwd + "/templates")
+ web.template.Template.globals['xrange'] = xrange
+ web.template.Template.globals['len'] = len
+ print render.multiday(zip(dates, entries, commentcounts))
+
+class pastmonth:
+ def GET(self):
+ filelist = map( lambda x: pwd + "/entries/" + x, getFileList(30) )
+ filelist.reverse()
+ dates = map( lambda filename: re.sub("(.*)(\d\d\d\d-\d\d-\d\d).txt", "\g<2>", filename), filelist )
+ entries = map( readFile, filelist)
+ commentcounts = map(len, map( getCommentFiles, dates))
+ render = web.template.render(pwd + "/templates")
+ web.template.Template.globals['xrange'] = xrange
+ web.template.Template.globals['len'] = len
+ print render.multiday(zip(dates, entries, commentcounts))
+
+class pastweek:
+ def GET(self):
+ filelist = map( lambda x: pwd + "/entries/" + x, getFileList(7) )
+ filelist.reverse()
+ dates = map( lambda filename: re.sub("(.*)(\d\d\d\d-\d\d-\d\d).txt", "\g<2>", filename), filelist )
+ entries = map( readFile, filelist)
+ commentcounts = map(len, map( getCommentFiles, dates))
+ render = web.template.render(pwd + "/templates")
+ web.template.Template.globals['xrange'] = xrange
+ web.template.Template.globals['len'] = len
+ print render.multiday(zip(dates, entries, commentcounts))
+
+class redir:
+ def GET(self):
+ web.redirect("/")
+
+class feed:
+ def GET(self):
+ web.header('Content-Type', 'application/atom+xml')
+ filelist = os.listdir(pwd + "/entries")
+ files = filter(lambda x: re.match("(.*)(\d\d\d\d-\d\d-\d\d).txt$", x), filelist)
+ files = [pwd + "/entries/" + x for x in files]
+ stats = [os.stat(f) for f in files]
+ decorated = [(stat.st_mtime, filename) for (filename, stat) in zip(files, stats)]
+ decorated.sort(reverse=True)
+ if len(decorated) == 0:
+ return render.feed(datetime.datetime.today(), [] )
+ group_timestamp = datetime.datetime.fromtimestamp(decorated[0][0]).isoformat() + "-06:00"
+ entries = []
+ for d in decorated[:10]:
+ mtime = datetime.datetime.fromtimestamp(d[0])
+ second = {"date" : re.sub("(.*)(\d\d\d\d-\d\d-\d\d).txt", "\g<2>", d[1]),
+ "content": "".join(readFile(d[1])),
+ "timestamp": (mtime.isoformat() + "-06:00") }
+ entries.append(second)
+ render = web.template.render(pwd +"/templates")
+ print render.feed(group_timestamp, entries)
+
+# web.py 0.3+ way
+#application = web.application(urls, globals()).wsgifunc()
+
+# web.py 0.2 way
+application = web.wsgifunc(web.webpyfunc(urls, globals()))
+
+if __name__ == "__main__":
+ ## The web.py 0.3+ way
+ #app.run()
+ ## The web.py 0.2 way
+ web.run(urls, globals())
+