Completed
Push — master ( 65a8c1...cbc1c4 )
by Fox
01:26
created

ServiceEvernote.get_evernote_client()   A

Complexity

Conditions 2

Size

Total Lines 13

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 2
c 1
b 0
f 0
dl 0
loc 13
rs 9.4285
1
# coding: utf-8
2
import arrow
3
4
# evernote API
5
from evernote.api.client import EvernoteClient
6
from evernote.edam.notestore import NoteStore
7
import evernote.edam.type.ttypes as Types
8
from evernote.edam.error.ttypes import EDAMSystemException
9
from evernote.edam.error.ttypes import EDAMErrorCode
10
11
# django classes
12
from django.conf import settings
13
from django.utils.log import getLogger
14
from django.core.cache import caches
15
16
# django_th classes
17
from django_th.services.services import ServicesMgr
18
from django_th.models import UserService, ServicesActivated
19
from th_evernote.models import Evernote
20
from th_evernote.evernote_mgr import create_note, set_notebook, get_notebook, \
21
    set_header, set_tag, get_tag, set_note_attribute, set_note_footer
22
from th_evernote.sanitize import sanitize
23
24
"""
25
    handle process with evernote
26
    put the following in settings.py
27
28
    TH_EVERNOTE = {
29
        'sandbox': True,
30
        'consumer_key': 'abcdefghijklmnopqrstuvwxyz',
31
        'consumer_secret': 'abcdefghijklmnopqrstuvwxyz',
32
    }
33
    sanbox set to True to make your test and False for production purpose
34
35
    TH_SERVICES = (
36
        ...
37
        'th_evernote.my_evernote.ServiceEvernote',
38
        ...
39
    )
40
"""
41
42
logger = getLogger('django_th.trigger_happy')
43
44
cache = caches['th_evernote']
45
46
47
class ServiceEvernote(ServicesMgr):
48
49
    def __init__(self, token=None):
50
        super(ServiceEvernote, self).__init__(token)
51
        self.sandbox = settings.TH_EVERNOTE['sandbox']
52
        self.consumer_key = settings.TH_EVERNOTE['consumer_key']
53
        self.consumer_secret = settings.TH_EVERNOTE['consumer_secret']
54
        self.token = token
55
56
        kwargs = {'consumer_key': self.consumer_key,
57
                  'consumer_secret': self.consumer_secret,
58
                  'sandbox': self.sandbox}
59
60
        if self.token:
61
            kwargs = {'token': token, 'sandbox': self.sandbox}
62
63
        self.client = EvernoteClient(**kwargs)
64
65
    def read_data(self, **kwargs):
66
        """
67
            get the data from the service
68
69
            :param kwargs: contain keyword args : trigger_id at least
70
            :type kwargs: dict
71
72
            :rtype: list
73
        """
74
        date_triggered = kwargs.get('date_triggered')
75
        trigger_id = kwargs.get('trigger_id')
76
77
        kwargs['model_name'] = 'Evernote'
78
79
        trigger = super(ServiceEvernote, self).read_data(**kwargs)
80
81
        data = []
82
        new_date_triggered = arrow.get(str(date_triggered)[:-6],
83
                                       'YYYY-MM-DD HH:mm:ss')
84
        new_date_triggered = str(new_date_triggered).replace(
85
            ':', '').replace('-', '').replace(' ', '')
86
        date_filter = "created:{} ".format(new_date_triggered[:-6])
87
88
        notebook_filter = ''
89
        if trigger.notebook:
90
            notebook_filter = "notebook:{} ".format(trigger.notebook)
91
        tag_filter = "tag:{} ".format(trigger.tag) if trigger.tag != '' else ''
92
93
        complet_filter = ''.join((notebook_filter, tag_filter, date_filter))
94
95
        # filter
96
        my_filter = NoteStore.NoteFilter()
97
        my_filter.words = complet_filter
98
99
        spec = NoteStore.NotesMetadataResultSpec()
100
        spec.includeTitle = True
101
        spec.includeAttributes = True
102
103
        note_store = self.client.get_note_store()
104
        our_note_list = note_store.findNotesMetadata(self.token,
105
                                                     my_filter,
106
                                                     0,
107
                                                     100,
108
                                                     spec)
109
110
        for note in our_note_list.notes:
111
            whole_note = note_store.getNote(self.token,
112
                                            note.guid,
113
                                            True,
114
                                            True,
115
                                            False,
116
                                            False)
117
            content = self._cleaning_content(whole_note.content)
118
            data.append(
119
                {'title': note.title,
120
                 'my_date': arrow.get(note.created),
121
                 'link': whole_note.attributes.sourceURL,
122
                 'content': content})
123
124
        cache.set('th_evernote_' + str(trigger_id), data)
125
126
        return data
127
128
    def save_data(self, trigger_id, **data):
129
        """
130
            let's save the data
131
            don't want to handle empty title nor content
132
            otherwise this will produce an Exception by
133
            the Evernote's API
134
135
            :param trigger_id: trigger ID from which to save data
136
            :param data: the data to check to be used and save
137
            :type trigger_id: int
138
            :type data:  dict
139
            :return: the status of the save statement
140
            :rtype: boolean
141
        """
142
        kwargs = {}
143
        # set the title and content of the data
144
        title, content = super(ServiceEvernote, self).save_data(trigger_id,
145
                                                                data,
146
                                                                **kwargs)
147
148
        if len(title):
149
            # get the evernote data of this trigger
150
            trigger = Evernote.objects.get(trigger_id=trigger_id)
151
152
            try:
153
                note_store = self.client.get_note_store()
154
            except EDAMSystemException as e:
155
                # rate limite reach have to wait 1 hour !
156
                if e.errorCode == EDAMErrorCode.RATE_LIMIT_REACHED:
157
                    logger.warn("Rate limit reached {code}\n"
158
                                "Retry your request in {msg} seconds\n"
159
                                "Data set to cache again until"
160
                                " limit reached".format(code=e.errorCode,
161
                                                        msg=e.rateLimitDuration)
162
                                )
163
                    cache.set('th_evernote_' + str(trigger_id),
164
                              data,
165
                              version=2)
166
                    return True
167
                else:
168
                    logger.critical(e)
169
                    return False
170
            except Exception as e:
171
                logger.critical(e)
172
                return False
173
174
            # note object
175
            note = Types.Note()
176
            if trigger.notebook:
177
                # get the notebookGUID ...
178
                notebook_id = get_notebook(note_store, trigger.notebook)
179
                # create notebookGUID if it does not exist then return its id
180
                note.notebookGuid = set_notebook(note_store,
181
                                                 trigger.notebook,
182
                                                 notebook_id)
183
184
                if trigger.tag:
185
                    # ... and get the tagGUID if a tag has been provided
186
                    tag_id = get_tag(note_store, trigger.tag)
187
                    if tag_id is False:
188
                        tag_id = set_tag(note_store, trigger.tag, tag_id)
189
                        # set the tag to the note if a tag has been provided
190
                        note.tagGuids = tag_id
191
192
                logger.debug("notebook that will be used %s", trigger.notebook)
193
194
            # attribute of the note: the link to the website
195
            note_attribute = set_note_attribute(data)
196
            if note_attribute:
197
                note.attributes = note_attribute
198
199
            # footer of the note
200
            footer = set_note_footer(data, trigger)
201
            content += footer
202
203
            note.title = title
204
            note.content = set_header()
205
            note.content += sanitize(content)
206
            # create a note
207
            return create_note(note_store, note, trigger_id, data)
208
209
        else:
210
            logger.critical("no title provided "
211
                            "for trigger ID {}".format(trigger_id))
212
            return False
213
214
    def get_evernote_client(self, token=None):
215
        """
216
            get the token from evernote
217
        """
218
        if token:
219
            return EvernoteClient(
220
                token=token,
221
                sandbox=self.sandbox)
222
        else:
223
            return EvernoteClient(
224
                consumer_key=self.consumer_key,
225
                consumer_secret=self.consumer_secret,
226
                sandbox=self.sandbox)
227
228
    def auth(self, request):
229
        """
230
            let's auth the user to the Service
231
        """
232
        client = self.get_evernote_client()
233
        request_token = client.get_request_token(
234
            self.callback_url(request, 'evernote'))
235
236
        # Save the request token information for later
237
        request.session['oauth_token'] = request_token['oauth_token']
238
        request.session['oauth_token_secret'] = request_token[
239
            'oauth_token_secret']
240
241
        # Redirect the user to the Evernote authorization URL
242
        # return the URL string which will be used by redirect()
243
        # from the calling func
244
        return client.get_authorize_url(request_token)
245
246
    def callback(self, request, **kwargs):
247
        """
248
            Called from the Service when the user accept to activate it
249
        """
250
        try:
251
            client = self.get_evernote_client()
252
            # finally we save the user auth token
253
            # As we already stored the object ServicesActivated
254
            # from the UserServiceCreateView now we update the same
255
            # object to the database so :
256
            # 1) we get the previous object
257
            us = UserService.objects.get(
258
                user=request.user,
259
                name=ServicesActivated.objects.get(name='ServiceEvernote'))
260
            # 2) then get the token
261
            us.token = client.get_access_token(
262
                request.session['oauth_token'],
263
                request.session['oauth_token_secret'],
264
                request.GET.get('oauth_verifier', '')
265
            )
266
            # 3) and save everything
267
            us.save()
268
        except KeyError:
269
            return '/'
270
271
        return 'evernote/callback.html'
272
273
    @staticmethod
274
    def _cleaning_content(data):
275
276
        data = data.replace('<?xml version="1.0" encoding="UTF-8"?>\n<!DOCTYPE en-note SYSTEM "http://xml.evernote.com/pub/enml2.dtd">\n<en-note>', '')
277
        data = data.replace('</en-note>', '')
278
279
        return data
280