annotate laterlinks2/laterlinks_app.py @ 78:f833a888c548

add cookie-based PIN system, and update laterlinks to use it
author paulo
date Thu, 02 Jun 2016 00:27:50 -0700
parents 49ca145627cb
children d7d67887102f
rev   line source
paulo@60 1 import datetime
paulo@60 2 import cgi
paulo@60 3 import urlparse
paulo@60 4 import csv
paulo@60 5 import traceback
paulo@60 6
paulo@60 7 import html
paulo@60 8
paulo@78 9 import pinlib
paulo@78 10
paulo@60 11
paulo@60 12 DEBUG = True
paulo@60 13 STRTIME_FMT = "%Y-%m-%d %H:%M:%S"
paulo@60 14
paulo@60 15
paulo@60 16 class LLDialect(csv.Dialect):
paulo@60 17 delimiter = '\t'
paulo@60 18 quoting = csv.QUOTE_NONE
paulo@60 19 lineterminator = '\n'
paulo@60 20
paulo@60 21
paulo@60 22 LLDIALECT = LLDialect()
paulo@60 23 LLDB_FN = "lldb.tsv"
paulo@60 24 LLDB_UNREAD_FN = "lldb_unread.tsv"
paulo@60 25
paulo@60 26
paulo@60 27 class LLError(Exception):
paulo@60 28 pass
paulo@60 29
paulo@60 30 class PinFailError(LLError):
paulo@60 31 def __str__(self):
paulo@60 32 return "PIN FAIL!"
paulo@60 33
paulo@60 34 class MissingFieldsError(LLError):
paulo@60 35 def __str__(self):
paulo@60 36 return "MISSING FIELD(s)!"
paulo@60 37
paulo@60 38
paulo@60 39 def lldb_unread_load():
paulo@60 40 return csv.reader(open(LLDB_UNREAD_FN), LLDIALECT)
paulo@60 41
paulo@60 42
paulo@60 43 def lldb_add(inp):
paulo@60 44 try:
paulo@60 45 title = inp["title"][0]
paulo@60 46 url = inp["url"][0]
paulo@60 47 except (KeyError, IndexError):
paulo@60 48 raise MissingFieldsError()
paulo@60 49
paulo@60 50 dt_str = datetime.datetime.now().strftime(STRTIME_FMT)
paulo@60 51 with open(LLDB_FN, 'a') as lldb_f:
paulo@60 52 csv.writer(lldb_f, LLDIALECT).writerow([title, url, dt_str])
paulo@60 53 with open(LLDB_UNREAD_FN, 'a') as lldb_f:
paulo@60 54 csv.writer(lldb_f, LLDIALECT).writerow([title, url, dt_str])
paulo@60 55
paulo@60 56
paulo@60 57 def lldb_unread_delete(inp):
paulo@60 58 try:
paulo@60 59 delete = inp["delete"]
paulo@60 60 except KeyError:
paulo@60 61 raise MissingFieldsError()
paulo@60 62
paulo@60 63 lldb_unread = [i for i in lldb_unread_load()]
paulo@60 64 lldb_unread_f = open(LLDB_UNREAD_FN, 'w')
paulo@60 65
paulo@60 66
paulo@60 67 try:
paulo@60 68 for i in delete:
paulo@60 69 for j in lldb_unread:
paulo@60 70 dt_str = j[2]
paulo@60 71 if i == dt_str:
paulo@60 72 lldb_unread.remove(j)
paulo@60 73 finally:
paulo@60 74 csv.writer(lldb_unread_f, LLDIALECT).writerows(lldb_unread)
paulo@60 75 lldb_unread_f.close()
paulo@60 76
paulo@60 77
paulo@60 78
paulo@60 79 def parse_wsgi_input(environ):
paulo@60 80 return urlparse.parse_qs(environ["wsgi.input"].read())
paulo@60 81
paulo@60 82
paulo@60 83
paulo@60 84 def main(environ):
paulo@60 85 is_post = (environ["REQUEST_METHOD"] == "POST")
paulo@78 86 cookies = pinlib.parse_cookies(environ)
paulo@60 87 inp = parse_wsgi_input(environ)
paulo@60 88
paulo@60 89 if is_post:
paulo@78 90 try:
paulo@78 91 pinlib.check(cookies)
paulo@78 92 except pinlib.PinFailError:
paulo@78 93 raise PinFailError
paulo@60 94 if inp["submit"][0] == "Add":
paulo@60 95 lldb_add(inp)
paulo@60 96 elif inp["submit"][0] == "Delete":
paulo@60 97 lldb_unread_delete(inp)
paulo@60 98
paulo@60 99 title = "later links..."
paulo@60 100 root = html.HTML("html")
paulo@60 101
paulo@60 102 header = root.header
paulo@60 103 header.link(rel="stylesheet", type="text/css", href="index.css")
paulo@60 104 header.title(title)
paulo@60 105
paulo@60 106 body = root.body
paulo@60 107 body.h1(title)
paulo@60 108
paulo@60 109
paulo@60 110 if (DEBUG):
paulo@60 111 debug = body.pre
paulo@60 112 for i in environ.items():
paulo@60 113 debug += cgi.escape("%s = %s \n" % i)
paulo@60 114
paulo@78 115 debug += cgi.escape("wsgi.input.read = %s \n" % inp)
paulo@78 116 debug += cgi.escape("cookies = %s \n" % cookies)
paulo@60 117
paulo@60 118 form = body.form(action="index.fcgi", method="post")
paulo@60 119
paulo@60 120 table = form.table
paulo@60 121 hrow = table.tr
paulo@60 122 hrow.th("Link")
paulo@60 123 hrow.th("Created")
paulo@60 124 hrow.th.input(type="submit", name="submit", value="Delete")
paulo@60 125
paulo@60 126 for i in lldb_unread_load():
paulo@60 127 (title, url, dt_str) = (j.decode("utf-8") for j in i)
paulo@60 128 row = table.tr
paulo@60 129 row.td.a(title, href=url)
paulo@60 130 row.td(dt_str)
paulo@60 131 row.td.input(type="checkbox", name="delete", value=dt_str)
paulo@60 132
paulo@60 133 p1 = form.p
paulo@60 134 p1.label("Title").input(type="text", name="title", size="64")
paulo@60 135 p1.br
paulo@60 136 p1.label("URL").input(type="text", name="url", size="64")
paulo@60 137 p1.br
paulo@60 138 p1.input(type="submit", name="submit", value="Add")
paulo@60 139
paulo@60 140 return unicode(root).encode("utf-8")
paulo@60 141
paulo@60 142
paulo@60 143 def app(environ, start_response):
paulo@60 144 response_code = "500 Internal Server Error"
paulo@60 145 response_type = "text/plain; charset=UTF-8"
paulo@60 146
paulo@60 147 try:
paulo@60 148 response_body = main(environ)
paulo@78 149 response_code = "200 OK"
paulo@60 150 response_type = "text/html; charset=UTF-8"
paulo@60 151 except LLError as e:
paulo@60 152 response_body = str(e)
paulo@60 153 except:
paulo@60 154 response_body = traceback.format_exc()
paulo@60 155
paulo@60 156 response_headers = [
paulo@60 157 ("Content-Type", response_type),
paulo@60 158 ("Content-Length", str(len(response_body))),
paulo@60 159 ]
paulo@60 160 start_response(response_code, response_headers)
paulo@60 161
paulo@60 162 return [response_body]