app.py 4.21 KB
Newer Older
okhin's avatar
okhin committed
1
2
3
#!/usr/bin/env python

import sqlite3
okhin's avatar
okhin committed
4
5
6
import datetime
import uuid
import json
okhin's avatar
okhin committed
7
8
9
10

from bottle import route, run, request, abort, install, get, post
from bottle_sqlite import SQLitePlugin
import jwt
11
import Asterisk
okhin's avatar
okhin committed
12
13
14

install(SQLitePlugin(dbfile='call.db'))

okhin's avatar
okhin committed
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
def sanitize_phonenumber(number):
    """
    This function is used to sanitize a phone number.
    If it starts with a +, it will be removed and replaced by 00.
    Any chars who do notbelong to [0-9] will be stripped.
    If the number doesn't starts with 00, a TypeError will be raised
    """
    if number[0] == '+':
        number = '00' + number[1:]
    number = ''.join([c for c in number if c in '0123456789'])
    if not number.startswith('00'):
        raise TypeError('{} is not a valid international number, it should start with 00')
    return number

class Call(json.JSONEncoder):
    """
    This Class is used to manage operatiosn on a call, to print it and dump it.
    """
    history = {}
    def __init__(self, caller, callee, owner):
        try:
            self.caller = caller
            self.callee = callee
            self.owner = owner
            self.id = uuid.uuid4()
        except Exception as e:
            raise e

    def url(self):
        return ''.join(['/calls/', self.id])

    def default(self, o):
        """
        We need to implement this to be able to JSONEncode
        """
        return {  'caller': self.caller
                , 'callee': self.callee
                , 'callid': self.callee
                , 'url': self.url()
                , 'history': self.history
                , 'owner': self.owner }

    @classmethod
    def load(cls, callid, db):
59
        results = db.execute('SELECT caller, callee, owner, callid, history FROM calls WHERE callid = ?;', (callid,))
okhin's avatar
okhin committed
60
61
62
63
64
65
66
67
68
        try:
            result = results.fetchone()
            object = cls(result[0], result[1], result[2])
            object.id = result[3]
            object.history = json.loads(result[4])
            return object
        except:
            return None

69
70
71
72
73
74
75
76
    def save(self, db):
        '''
        Save the Call to database.
        '''
        db.execute('''INSERT OR REPLACE INTO calls (caller, callee, owner, callid, history)
                VALUES (?, ?, ?, ?, ?)
        ''', (self.caller, self.callee, self.owner, self.callid, json.dumps(self.history)))

okhin's avatar
okhin committed
77
78
79
80
81
82
83
84
85
86
# We need a decorator to check if our query is authenticated.
# We will store an API key and SECRET in ur database, the client
# needs to have both of them.
# He must then send us a JWT token with an API claim in the payload.
# The JWT token must be encoded and signed with the SECRET. If the
# token is bad, we return a 403.
def authenticated(f):
    def wrapped(db, *args, **kwargs):
        # Let's get the JWT token. It should be a params (from get or post or whatev')
        if 'token' not in request.params:
okhin's avatar
okhin committed
87
            abort(401, "No token found in the query")
okhin's avatar
okhin committed
88
89
        # We want the api id in the params to.
        if 'api' not in request.params:
okhin's avatar
okhin committed
90
            abort(401, "No api id found in the params")
okhin's avatar
okhin committed
91
92
93
94
95
96
97
        # Now, let's get the token on our side
        try:
            results = db.execute('SELECT token FROM users WHERE api = ?', (request.params['api'],)).fetchall()
            assert len(results) == 1
            token = results[0][0]
            auth_token = jwt.decode(request.params['token'], token)
            assert auth_token['api'] == request.params['api']
okhin's avatar
okhin committed
98
99
            for key in auth_token:
                request.params[key] = auth_token[key]
okhin's avatar
okhin committed
100
101
102
103
104
105
106
        except (jwt.exceptions.InvalidTokenError, AssertionError) as e:
            abort(403, e)
        except Exception as e:
            abort(500, e)
        return f(db, *args, **kwargs)
    return wrapped

okhin's avatar
okhin committed
107
@get('/calls/')
okhin's avatar
okhin committed
108
@authenticated
okhin's avatar
okhin committed
109
110
111
112
113
114
115
116
117
118
119
def calls(db):
    """
    Return the list of calls associated to the connected user.
    The call has a status, caller, callee and history (status change+timestamp)
    """
    results = db.execute('SELECT callid FROM calls WHERE owner = ?;', (request.params['api'],))
    calls = []
    for call in results.fetchall():
        calls.append(Calls.load(call[0], db))
    head = {'call': '/calls/', 'user': request.params['api'], 'hits': len(calls)}
    return {'head': head, 'data': calls}
okhin's avatar
okhin committed
120
121
    
run(host='localhost', port=8080, debug=True)