~nprescott/glue-boy

ref: 2b49357fe5591ab555d10650209a4046ced98294 glue-boy/glue_boy.py -rwxr-xr-x 2.6 KiB
2b49357f — Nolan Prescott Better exception handling practice 3 years ago
                                                                                
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
#!/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