Completed
Push — master ( a9f319...d94b17 )
by Fox
01:28
created

ServiceWallabag._new_token()   A

Complexity

Conditions 2

Size

Total Lines 21

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
cc 2
c 2
b 0
f 0
dl 0
loc 21
rs 9.3142
1
# coding: utf-8
2
# add here the call of any native lib of python like datetime etc.
3
import arrow
4
import requests
5
from requests import HTTPError
6
# add the python API here if needed
7
from wallabag_api.wallabag import Wallabag as Wall
8
# django classes
9
from django.core.urlresolvers import reverse
10
from django.utils.log import getLogger
11
from django.core.cache import caches
12
13
# django_th classes
14
from django_th.services.services import ServicesMgr
15
from django_th.html_entities import HtmlEntities
16
from django_th.models import UserService, ServicesActivated
17
from th_wallabag.models import Wallabag
18
19
"""
20
    handle process with wallabag
21
    put the following in settings.py
22
23
    TH_SERVICES = (
24
        ...
25
        'th_wallabag.my_wallabag.ServiceWallabag',
26
        ...
27
    )
28
"""
29
30
logger = getLogger('django_th.trigger_happy')
31
32
cache = caches['th_wallabag']
33
34
35
class ServiceWallabag(ServicesMgr):
36
37
    def __init__(self, token=None, **kwargs):
38
        super(ServiceWallabag, self).__init__(token, **kwargs)
39
        self.token = token
40
        self.user = kwargs.get('user')
41
42
    def _get_wall_data(self):
43
        us = UserService.objects.get(token=self.token, name='ServiceWallabag')
44
45
        params = dict({'access_token': self.token,
46
                       'archive': 0,
47
                       'star': 0,
48
                       'delete': 0,
49
                       'sort': 'created',
50
                       'order': 'desc',
51
                       'page': 1,
52
                       'perPage': 30,
53
                       'tags': []})
54
55
        responses = requests.get(us.host + '/api/entries.json',
56
                                 params=params)
57
        if responses.status_code == 401:
58
            params['access_token'] = self._refresh_token()
59
            responses = requests.get(us.host + '/api/entries.json',
60
                                     params=params)
61
        elif responses.status_code != 200:
62
            raise HTTPError(responses.status_code, responses.json())
63
64
        return responses
65
66
    def read_data(self, **kwargs):
67
        """
68
            get the data from the service
69
            as the pocket service does not have any date
70
            in its API linked to the note,
71
            add the triggered date to the dict data
72
            thus the service will be triggered when data will be found
73
74
            :param kwargs: contain keyword args : trigger_id at least
75
            :type kwargs: dict
76
77
            :rtype: list
78
        """
79
        self.date_triggered = arrow.get(kwargs.get('date_triggered'))
80
        self.trigger_id = kwargs.get('trigger_id')
81
        self.user = kwargs.get('user') if kwargs.get('user') else ''
82
83
        responses = self._get_wall_data()
84
85
        data = []
86
        try:
87
            json_data = responses.json()
88
89
            for d in json_data['_embedded']['items']:
90
                created_at = arrow.get(d.get('created_at'))
91
                date_triggered = arrow.get(self.date_triggered)
92
93
                if created_at > date_triggered:
94
                    data.append({'title': d.get('title'),
95
                                 'content': d.get('content')})
96
            if len(data) > 0:
97
                cache.set('th_wallabag_' + str(self.trigger_id), data)
98
        except Exception as e:
99
                logger.critical(e)
100
        return data
101
102
    def new_wall(self, token):
103
        """
104
            produce a new wall instance
105
            :param token: to get
106
            :return: Wall instance
107
        """
108
        if token:
109
            try:
110
                us = UserService.objects.get(
111
                    token=self.token, name='ServiceWallabag')
112
            except UserService.DoesNotExist:
113
                us = UserService.objects.get(
114
                    user=self.user, name='ServiceWallabag')
115
            finally:
116
                return Wall(host=us.host, client_secret=us.client_secret,
117
                            client_id=us.client_id, token=us.token)
118
119
    def _create_entry(self, title, data, tags):
120
        """
121
            create an entry
122
            :param title: string
123
            :param data: dict
124
            :param tags: list
125
            :return: boolean
126
        """
127
        if data.get('link') and len(data.get('link')) > 0:
128
            wall = self.new_wall(self.token)
129
            try:
130
                wall.post_entries(url=data.get('link').encode(),
131
                                  title=title,
132
                                  tags=(tags.lower()))
133
                logger.debug('wallabag {} created'.format(data.get('link')))
134
                status = True
135
            except Exception as e:
136
                if e.errno == 401:
137
                    status = self._new_token(data.get('userservice_id'),
138
                                             data.get('link').encode(),
139
                                             title,
140
                                             tags.lower())
141
                else:
142
                    logger.critical('issue with something else that a token'
143
                                    ' link ? : {}'.format(data.get('link')))
144
                    logger.critical(e.errno, e.strerror)
145
                    status = False
146
        else:
147
            status = True  # we ignore empty link
148
        return status
149
150
    def _refresh_token(self):
151
        """
152
            refresh the expired token
153
            get the token of the service Wallabag
154
            for the user that uses Wallabag
155
            :return: boolean
156
        """
157
        us = UserService.objects.get(user=self.user, name='ServiceWallabag')
158
        params = {'username': us.username,
159
                  'password': us.password,
160
                  'client_id': us.client_id,
161
                  'client_secret': us.client_secret}
162
        return Wall.get_token(host=us.host, **params)
163
164
    def _new_token(self, userservice_id, link, title, tags):
165
        """
166
            create a new token
167
            :param userservice_id: id of the UserService
168
            :param link: string
169
            :param title: string
170
            :param tags: list
171
            :return: boolean
172
        """
173
        new_token = self._refresh_token()
174
        logger.info('new token : {}'.format(new_token))
175
        UserService.objects.filter(id=userservice_id).update(token=new_token)
176
177
        new_wall = self.new_wall(new_token)
178
        try:
179
            status = new_wall.post_entries(url=link, title=title, tags=tags)
180
        except Exception as e:
181
            logger.critical('could not create a post link ? : {}'.format(link))
182
            logger.critical(e)
183
            status = False
184
        return status
185
186
    def save_data(self, trigger_id, **data):
187
        """
188
            let's save the data
189
190
            :param trigger_id: trigger ID from which to save data
191
            :param data: the data to check to be used and save
192
            :type trigger_id: int
193
            :type data:  dict
194
            :return: the status of the save statement
195
            :rtype: boolean
196
        """
197
        trigger = Wallabag.objects.get(trigger_id=trigger_id)
198
199
        title = self.set_title(data)
200
        # convert htmlentities
201
        title = HtmlEntities(title).html_entity_decode
202
203
        return self._create_entry(title, data, trigger.tag)
204
205
    def auth(self, request):
206
        """
207
            let's auth the user to the Service
208
            :param request: request object
209
            :return: callback url
210
            :rtype: string that contains the url to redirect after auth
211
212
        """
213
        service = UserService.objects.get(
214
            user=request.user, name='ServiceWallabag')
215
        callback_url = 'http://%s%s' % (
216
            request.get_host(), reverse('wallabag_callback'))
217
        params = {'username': service.username,
218
                  'password': service.password,
219
                  'client_id': service.client_id,
220
                  'client_secret': service.client_secret}
221
        access_token = Wall.get_token(host=service.host, **params)
222
        request.session['oauth_token'] = access_token
223
        return callback_url
224
225
    def callback(self, request, **kwargs):
226
        """
227
            Called from the Service when the user accept to activate it
228
            :param request: request object
229
            :return: callback url
230
            :rtype: string , path to the template
231
        """
232
233
        try:
234
            UserService.objects.filter(
235
                user=request.user,
236
                name=ServicesActivated.objects.get(name='ServiceWallabag')
237
            )
238
        except KeyError:
239
            return '/'
240
241
        return 'wallabag/callback.html'
242