changeset 60:9d3a95d80def

add laterlinks2
author paulo
date Fri, 18 Jul 2014 00:47:15 -0700
parents 6edb5112c804
children 16bcb4ae6985
files laterlinks2/laterlinks_app.py laterlinks2/lldb.tsv laterlinks2/lldb_unread.tsv laterlinks2/test_server.py
diffstat 2 files changed, 207 insertions(+), 0 deletions(-) [+]
line diff
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/laterlinks2/laterlinks_app.py	Fri Jul 18 00:47:15 2014 -0700
     1.3 @@ -0,0 +1,169 @@
     1.4 +import datetime
     1.5 +import cgi
     1.6 +import urlparse
     1.7 +import csv
     1.8 +import traceback
     1.9 +
    1.10 +import html
    1.11 +
    1.12 +
    1.13 +DEBUG = True
    1.14 +STRTIME_FMT = "%Y-%m-%d %H:%M:%S"
    1.15 +MY_PIN = "qworpy"
    1.16 +
    1.17 +
    1.18 +class LLDialect(csv.Dialect):
    1.19 +	delimiter = '\t'
    1.20 +	quoting = csv.QUOTE_NONE
    1.21 +	lineterminator = '\n'
    1.22 +
    1.23 +
    1.24 +LLDIALECT = LLDialect()
    1.25 +LLDB_FN = "lldb.tsv"
    1.26 +LLDB_UNREAD_FN = "lldb_unread.tsv"
    1.27 +
    1.28 +
    1.29 +class LLError(Exception):
    1.30 +	pass
    1.31 +
    1.32 +class PinFailError(LLError):
    1.33 +	def __str__(self):
    1.34 +		return "PIN FAIL!"
    1.35 +
    1.36 +class MissingFieldsError(LLError):
    1.37 +	def __str__(self):
    1.38 +		return "MISSING FIELD(s)!"
    1.39 +
    1.40 +
    1.41 +def lldb_unread_load():
    1.42 +	return csv.reader(open(LLDB_UNREAD_FN), LLDIALECT)
    1.43 +
    1.44 +
    1.45 +def lldb_add(inp):
    1.46 +	try:
    1.47 +		title = inp["title"][0]
    1.48 +		url = inp["url"][0]
    1.49 +	except (KeyError, IndexError):
    1.50 +		raise MissingFieldsError()
    1.51 +
    1.52 +	dt_str = datetime.datetime.now().strftime(STRTIME_FMT)
    1.53 +	with open(LLDB_FN, 'a') as lldb_f:
    1.54 +		csv.writer(lldb_f, LLDIALECT).writerow([title, url, dt_str])
    1.55 +	with open(LLDB_UNREAD_FN, 'a') as lldb_f:
    1.56 +		csv.writer(lldb_f, LLDIALECT).writerow([title, url, dt_str])
    1.57 +
    1.58 +
    1.59 +def lldb_unread_delete(inp):
    1.60 +	try:
    1.61 +		delete = inp["delete"]
    1.62 +	except KeyError:
    1.63 +		raise MissingFieldsError()
    1.64 +
    1.65 +	lldb_unread = [i for i in lldb_unread_load()]
    1.66 +	lldb_unread_f = open(LLDB_UNREAD_FN, 'w')
    1.67 +
    1.68 +
    1.69 +	try:
    1.70 +		for i in delete:
    1.71 +			for j in lldb_unread:
    1.72 +				dt_str = j[2]
    1.73 +				if i == dt_str:
    1.74 +					lldb_unread.remove(j)
    1.75 +	finally:
    1.76 +		csv.writer(lldb_unread_f, LLDIALECT).writerows(lldb_unread)
    1.77 +		lldb_unread_f.close()
    1.78 +	
    1.79 +		
    1.80 +
    1.81 +def parse_wsgi_input(environ):
    1.82 +	return urlparse.parse_qs(environ["wsgi.input"].read())
    1.83 +
    1.84 +
    1.85 +def get_pin(inp):
    1.86 +	if "pin" not in inp:
    1.87 +		raise PinFailError()
    1.88 +
    1.89 +	pin = inp["pin"][0]
    1.90 +	if pin != MY_PIN:
    1.91 +		raise PinFailError()
    1.92 +
    1.93 +	return pin
    1.94 +
    1.95 +
    1.96 +def main(environ):
    1.97 +	pin = '' 
    1.98 +	is_post = (environ["REQUEST_METHOD"] == "POST")
    1.99 +	inp = parse_wsgi_input(environ)
   1.100 +
   1.101 +	if is_post:
   1.102 +		pin = get_pin(inp)
   1.103 +		if inp["submit"][0] == "Add":
   1.104 +			lldb_add(inp)
   1.105 +		elif inp["submit"][0] == "Delete":
   1.106 +			lldb_unread_delete(inp)
   1.107 +
   1.108 +	title = "later links..."
   1.109 +	root = html.HTML("html")
   1.110 +
   1.111 +	header = root.header
   1.112 +	header.link(rel="stylesheet", type="text/css", href="index.css")
   1.113 +	header.title(title)
   1.114 +	
   1.115 +	body = root.body
   1.116 +	body.h1(title)
   1.117 +
   1.118 +
   1.119 +	if (DEBUG):
   1.120 +		debug = body.pre
   1.121 +		for i in environ.items():
   1.122 +			debug += cgi.escape("%s = %s \n" % i)
   1.123 +
   1.124 +		debug += cgi.escape("wsgi.input.read = %s" % inp)
   1.125 +
   1.126 +	form = body.form(action="index.fcgi", method="post")
   1.127 +
   1.128 +	table = form.table
   1.129 +	hrow = table.tr
   1.130 +	hrow.th("Link")
   1.131 +	hrow.th("Created")
   1.132 +	hrow.th.input(type="submit", name="submit", value="Delete")
   1.133 +
   1.134 +	for i in lldb_unread_load():
   1.135 +		(title, url, dt_str) = (j.decode("utf-8") for j in i)
   1.136 +		row = table.tr
   1.137 +		row.td.a(title, href=url)
   1.138 +		row.td(dt_str)
   1.139 +		row.td.input(type="checkbox", name="delete", value=dt_str)
   1.140 +
   1.141 +	p1 = form.p
   1.142 +	p1.label("Title").input(type="text", name="title", size="64")
   1.143 +	p1.br
   1.144 +	p1.label("URL").input(type="text", name="url", size="64")
   1.145 +	p1.br
   1.146 +	p1.input(type="submit", name="submit", value="Add")
   1.147 +
   1.148 +	p2 = form.p
   1.149 +	p2.input(type="password", name="pin", value=pin)
   1.150 +
   1.151 +	return unicode(root).encode("utf-8")
   1.152 +
   1.153 +
   1.154 +def app(environ, start_response):
   1.155 +	response_code = "500 Internal Server Error"
   1.156 +	response_type = "text/plain; charset=UTF-8"
   1.157 +
   1.158 +	try:
   1.159 +		response_body = main(environ)
   1.160 +		response_type = "text/html; charset=UTF-8"
   1.161 +	except LLError as e:
   1.162 +		response_body = str(e)
   1.163 +	except:
   1.164 +		response_body = traceback.format_exc()
   1.165 +
   1.166 +	response_headers = [
   1.167 +		("Content-Type", response_type),
   1.168 +		("Content-Length", str(len(response_body))),
   1.169 +	]
   1.170 +	start_response(response_code, response_headers)
   1.171 +
   1.172 +	return [response_body]
     2.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     2.2 +++ b/laterlinks2/test_server.py	Fri Jul 18 00:47:15 2014 -0700
     2.3 @@ -0,0 +1,38 @@
     2.4 +import os
     2.5 +import sys
     2.6 +import signal
     2.7 +
     2.8 +import cherrypy
     2.9 +from cherrypy import wsgiserver
    2.10 +
    2.11 +import laterlinks_app
    2.12 +
    2.13 +
    2.14 +def sighandler(signum, frame):
    2.15 +	sys.stderr.write("Caught signal: %s \n" % signum)
    2.16 +	server.stop()
    2.17 +
    2.18 +
    2.19 +class FileServerRoot:
    2.20 +	def default(self, *args):
    2.21 +		if len(args) == 0:
    2.22 +			raise cherrypy.HTTPError(404)
    2.23 +
    2.24 +		filepath = os.path.abspath(os.path.join(*args))
    2.25 +		return cherrypy.lib.static.serve_file(filepath)
    2.26 +
    2.27 +	default.exposed = True
    2.28 +
    2.29 +
    2.30 +if __name__ == "__main__":
    2.31 +	fileServerApp = cherrypy.Application(FileServerRoot())
    2.32 +	dispatcher = wsgiserver.WSGIPathInfoDispatcher({
    2.33 +		"/index.fcgi": laterlinks_app.app,
    2.34 +		"": fileServerApp,
    2.35 +	})
    2.36 +	server = wsgiserver.CherryPyWSGIServer(('0.0.0.0', 8000), dispatcher)
    2.37 +
    2.38 +	signal.signal(signal.SIGINT, sighandler)
    2.39 +	signal.signal(signal.SIGTERM, sighandler)
    2.40 +
    2.41 +	server.start()