1
# -*- coding utf-8 -*-
2
# classes/models/client.py
3
# class:: Client
4
5
from datetime import datetime, timedelta
6
7
from swtstore.classes.database import db
8
from swtstore.classes.models.um import User
9
from swtstore.classes import oauth
10
11
class Client(db.Model):
12
    """
13
    The third-party application registering with the platform
14
    """
15
16
    __tablename__ = 'clients'
17
18
    id = db.Column(db.String(40), primary_key=True)
19
20
    client_secret = db.Column(db.String(55), nullable=False)
21
22
    name = db.Column(db.String(60), nullable=False)
23
24
    description = db.Column(db.String(400))
25
26
    # creator of the client application
27
    user_id = db.Column(db.ForeignKey('users.id'))
28
    creator = db.relationship('User')
29
30
    _is_private = db.Column(db.Boolean)
31
32
    _host_url = db.Column(db.String(60))
33
34
    _redirect_uris = db.Column(db.Text)
35
    _default_scopes = db.Column(db.Text)
36
37
38
    @property
39
    def client_id(self):
40
        return self.id
41
42
    @property
43
    def client_type(self):
44
        if self._is_private:
45
            return 'private'
46
        return 'public'
47
48
    @property
49
    def host_url(self):
50
        return self._host_url
51
52
    @property
53
    def redirect_uris(self):
54
        if self._redirect_uris:
55
            return self._redirect_uris.split()
56
        return []
57
58
    @property
59
    def default_redirect_uri(self):
60
        return self.redirect_uris[0]
61
62
    @property
63
    def default_scopes(self):
64
        if self._default_scopes:
65
            return self._default_scopes.split()
66
        return []
67
68
    def __repr__(self):
69
        return '<Client: %s :: ID: %s>' % (self.name, self.id)
70
71
    def __str__(self):
72
        return '<Client: %s :: ID: %s>' % (self.name, self.id)
73
74
75
    # create and persist the client to the database
76
    def persist(self):
77
        db.session.add(self)
78
        db.session.commit()
79
80
    @staticmethod
81
    def getClientsByCreator(user_id):
82
        clients = Client.query.filter_by(user_id=user_id)
83
        return [each for each in clients]
84
85
86
class Grant(db.Model):
87
    """
88
    A grant token is created in the authorization flow, and will be
89
    destroyed when the authorization finished. In this case, it would be better
90
    to store the data in a cache, which would benefit a better performance.
91
    """
92
    #TODO: this would perform better if its only in the cache. and not in a db.
93
94
    __tablename__ = 'grants'
95
96
    id = db.Column(db.Integer, primary_key=True)
97
    user_id = db.Column(db.Integer, db.ForeignKey('users.id',
98
                                                  ondelete='CASCADE'))
99
    user = db.relationship('User')
100
101
    client_id = db.Column(db.String(40), db.ForeignKey('clients.id'),
102
                          nullable=False)
103
    client = db.relationship('Client')
104
105
    code = db.Column(db.String(255), index=True, nullable=False)
106
107
    redirect_uri = db.Column(db.String(255))
108
    expires = db.Column(db.DateTime)
109
110
    _scopes = db.Column(db.Text)
111
112
    @property
113
    def scopes(self):
114
        if self._scopes:
115
            return self._scopes.split()
116
        return []
117
118
    def delete(self):
119
        db.session.delete(self)
120
        db.session.commit()
121
122
123
class Token(db.Model):
124
    """
125
    The final token to be used by a client
126
    """
127
128
    __tablename__ = 'tokens'
129
130
    id = db.Column(db.Integer, primary_key=True)
131
132
    client_id = db.Column(db.String(40), db.ForeignKey('clients.id'),
133
                          nullable=False)
134
    client = db.relationship('Client')
135
    user_id = db.Column(db.Integer, db.ForeignKey('users.id'))
136
    user = db.relationship('User')
137
138
    token_type = db.Column(db.String(40))
139
140
    access_token = db.Column(db.String(255), unique=True)
141
    refresh_token = db.Column(db.String(255), unique=True)
142
    expires = db.Column(db.DateTime)
143
    _scopes = db.Column(db.Text)
144
145
    @property
146
    def scopes(self):
147
        if self._scopes:
148
            return self._scopes.split()
149
        return []
150
151
152
153
#TODO: find out how to better structure the following code
154
155
# OAuthLib decorators used by OAuthLib in the OAuth flow
156
157
@oauth.clientgetter
158
def loadClient(client_id):
159
    print '@oauth.clientgetter'
160
    #return Client.query.filter_by(id=client_id).first()
161
    return Client.query.get(client_id)
162
163
@oauth.grantgetter
164
def loadGrant(client_id, code):
165
    print '@oauth.grantgetter'
166
    return Grant.query.filter_by(client_id=client_id, code=code).first()
167
168
@oauth.grantsetter
169
def saveGrant(client_id, code, request, *args, **kwargs):
170
    print '@oauth.grantsetter'
171
    expires = datetime.utcnow() + timedelta(seconds=100)
172
    grant = Grant(
173
        client_id = client_id,
174
        code = code['code'],
175
        redirect_uri = request.redirect_uri,
176
        _scopes = ' '.join(request.scopes),
177
        user = User.getCurrentUser(),
178
        expires = expires
179
    )
180
    db.session.add(grant)
181
    db.session.commit()
182
    return grant
183
184
@oauth.tokengetter
185
def loadToken(access_token=None, refresh_token=None):
186
    print '@oauth.tokengetter'
187
    if access_token:
188
        return Token.query.filter_by(access_token=access_token).first()
189
    elif refresh_token:
190
        return Token.query.filter_by(refresh_token=refresh_token).first()
191
192
@oauth.tokensetter
193
def saveToken(token, request, *args, **kwargs):
194
    print '@oauth.tokensetter'
195
196
    toks = Token.query.filter_by(client_id=request.client.id,
197
                                 user_id=request.user.id)
198
    # make sure that every client has only one token connected to a user
199
    for t in toks:
200
        db.session.delete(t)
201
202
    expires_in = token.pop('expires_in')
203
    expires = datetime.utcnow() + timedelta(seconds=expires_in)
204
205
    tok = Token(
206
        access_token = token['access_token'],
207
        refresh_token = token['refresh_token'],
208
        token_type = token['token_type'],
209
        _scopes = token['scope'],
210
        expires = expires,
211
        client_id = request.client.id,
212
        user = request.user
213
    )
214
    db.session.add(tok)
215
    db.session.commit()
216
    return tok
217
218
@oauth.usergetter
219
def getUser():
220
    return User.getCurrentUser()