#!/usr/bin/env python3
'''
A stupidly simple pastebin. To start the server:
$ twist web --class=glue_boy.resource
'''
import datetime
from uuid import uuid4
from klein import Klein
from twisted.enterprise import adbapi
from twisted.internet.defer import ensureDeferred
from twisted.web.static import File
class GluesDatabase:
db_pool = adbapi.ConnectionPool('sqlite3', 'glues.sqlite',
check_same_thread=False)
table = 'glues'
async def get_paste(self, paste_id):
'''
Return the string contents of the paste, raise NotFound exception if no
match is found
'''
await self.db_pool.runOperation("UPDATE glues SET last_accessed = ? "
"WHERE id = ?",
(datetime.datetime.now(), paste_id))
content = await self.db_pool.runQuery("SELECT content FROM glues "
"WHERE id = ?", (paste_id,))
try:
return content[0][0]
except Exception:
raise NotFound()
async def write_paste(self, content):
'''
Write string content to the database, return the id it was written with.
'''
paste_id = uuid4().hex[:6]
await self.db_pool.runOperation("INSERT INTO glues (id, content) "
"VALUES (?, ?)", (paste_id, content))
return paste_id
class NotFound(Exception):
pass
class WebApp:
app = Klein()
db = GluesDatabase()
@app.route('/', methods=['GET', 'POST'])
def new_paste(self, request):
if request.method == b'GET':
# hack to get around: https://github.com/twisted/klein/issues/41
f = File('./')
f.indexNames = ['index.html']
return f
elif request.method == b'POST':
content, *_ = request.args[b'content']
d = ensureDeferred(self.db.write_paste(content))
d.addCallback(
lambda paste_id: request.redirect(f'./content/{paste_id}'))
return d
@app.route('/content/<paste_id>', methods=['GET'])
def existing_paste(self, request, paste_id):
request.setHeader('Content-Type', 'text/plain; charset=utf-8')
return self.db.get_paste(paste_id)
@app.handle_errors(NotFound)
def not_found(self, request, failure):
'''
error handling is ... funny, the name of this function doesn't matter
because it is resolving through the decorator (by exception type)
'''
request.setResponseCode(404)
return 'Not Found'
resource = WebApp().app.resource