Skip to content

Commit 4264545

Browse files
committed
Merge pull request #1232 from PyBossa/twitter-importer
Twitter importer
2 parents f49169b + 8cae3fe commit 4264545

31 files changed

+2122
-1316
lines changed

Diff for: doc/changelog/index.rst

+2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
Changelog
22
=========
33

4+
* v1.3.0_
45
* v1.2.2_
56
* v1.2.1_
67
* v1.2.0_
@@ -10,6 +11,7 @@ Changelog
1011
* v1.1.0_
1112
* v0.2.3_
1213

14+
.. _v1.3.0: v1.3.0.html
1315
.. _v1.2.1: v1.2.2.html
1416
.. _v1.2.1: v1.2.1.html
1517
.. _v1.2.0: v1.2.0.html

Diff for: doc/changelog/v1.3.0.rst

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
================
2+
Changelog v1.3.0
3+
================
4+
5+
* Add Twitter importer.

Diff for: doc/customizing.rst

+19-6
Original file line numberDiff line numberDiff line change
@@ -252,6 +252,8 @@ them.
252252
.. _Twitter: https://dev.twitter.com/
253253
.. _`TWITTER_CONSUMER_KEY`: https://github.com/PyBossa/pybossa/blob/master/settings_local.py.tmpl#L52
254254
.. _`TWITTER_CONSUMER_SECRET`: https://github.com/PyBossa/pybossa/blob/master/settings_local.py.tmpl#L53
255+
.. note::
256+
This will also enable the Twitter task importer.
255257

256258
Facebook
257259
~~~~~~~~
@@ -264,7 +266,6 @@ variables: `FACEBOOK_APP_ID`_ and `FACEBOOK_APP_SECRET`_ and uncomment them.
264266
.. _`FACEBOOK_APP_ID`: https://github.com/PyBossa/pybossa/blob/master/settings_local.py.tmpl#L54
265267
.. _`FACEBOOK_APP_SECRET`: https://github.com/PyBossa/pybossa/blob/master/settings_local.py.tmpl#L55
266268

267-
268269
Google
269270
~~~~~~
270271

@@ -331,7 +332,6 @@ type of users:
331332
332333
ANNOUNCEMENT = {'root': 'Your secret message'}
333334
334-
335335
There is an example of the **ANNOUNCEMENT** variable in the
336336
`settings_local.py.tmpl <https://github.com/PyBossa/pybossa/blob/master/settings_local.py.tmpl>`_
337337
file, so you can easily adapt it for your own server. Basically, the
@@ -727,7 +727,7 @@ interested users.
727727
Enabling the Flickr Task importer
728728
=================================
729729

730-
PyBossa has five different types of built-in importers. Users can use them to
730+
PyBossa has several different types of built-in importers. Users can use them to
731731
import tasks for their projects directly from the Web interface. However, using
732732
the Flickr one requires an API key and shared secret from Flickr in order to
733733
communicate with the service.
@@ -743,16 +743,29 @@ refer to `here <https://www.flickr.com/services/api/>`_.
743743
Enabling the Dropbox Task importer
744744
==================================
745745

746-
In addition to the Flickr importer, PyBossa also offers the Dropbox importer, which
747-
allows to import directly all kind of files from a Dropbox account. In order to
748-
use it, you'll need to register your PyBossa server as a Dropbox app, as explained
746+
PyBossa also offers the Dropbox importer, which allows to import directly all
747+
kind of files from a Dropbox account. In order to use it, you'll need to
748+
register your PyBossa server as a Dropbox app, as explained
749749
`here <https://www.dropbox.com/developers/dropins/chooser/js#setup>`_.
750750

751751
Don't worry about the Javascript snippet part, we've already handled that for you.
752752
Instead, get the App key you will be given and add it to your settings_local.py::
753753

754754
DROPBOX_APP_KEY = 'your-key'
755755

756+
Enabling the Twitter Task importer
757+
==================================
758+
759+
If you already have enabled the Twitter authentication, then the Twitter task
760+
importer will be enabled too. Otherwise, you will need to create an application
761+
in Twitter_ and copy and paste the **Consumer key and secret** into the next
762+
variables: `TWITTER_CONSUMER_KEY`_ and `TWITTER_CONSUMER_SECRET`_ and uncomment
763+
them.
764+
765+
.. _Twitter: https://dev.twitter.com/
766+
.. note::
767+
This will also enable PyBossa's Twitter login.
768+
756769
Enabling Server Sent Events
757770
===========================
758771

Diff for: doc/user/overview.rst

+69-7
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,7 @@ built-in :ref:`task-creator`. You have to do the following:
137137
see several options. The first five are for using the different kinds of
138138
importers supported by PyBossa.
139139

140-
.. image:: http://i.imgur.com/e9GhNlE.png
140+
.. image:: http://i.imgur.com/GbdkgEI.png
141141

142142
The **CSV** importer, allows you to upload your own CSV file:
143143

@@ -247,11 +247,11 @@ project, you will have to follow the next steps:
247247
:width: 100%
248248

249249

250-
3. And click on the **Import Tasks**
250+
3. And click on the **Import Tasks**
251251
button. After clicking on it you will see several different options. The first
252252
five correspond to the different importers PyBossa supports:
253253

254-
.. image:: http://i.imgur.com/e9GhNlE.png
254+
.. image:: http://i.imgur.com/GbdkgEI.png
255255

256256
4. Click in the **Use an EpiCollect Project** one.
257257

@@ -321,7 +321,7 @@ These are the steps:
321321

322322
2. Then click on the **Import Tasks** button, and select the **Flickr importer**:
323323

324-
.. image:: http://i.imgur.com/e9GhNlE.png
324+
.. image:: http://i.imgur.com/GbdkgEI.png
325325

326326
3. Type the ID of the Flickr set you want to import the photos from, then click
327327
on the import button:
@@ -359,7 +359,7 @@ presenter of the project:
359359
* link: the link to the Dropbox page showing the file.
360360
* link_raw: the link to the raw file served by Dropbox. This is the one you'll have to use if you want to direct link to the file from the presenter (e.g. for using an image in a <img> tag, you'd do: <img src=task.info.link_raw>).
361361

362-
In addition to these generic information, the Dropbox importer also will recognize
362+
In addition to this generic information, the Dropbox importer will also recognize
363363
some kind of files by their extension and will attach some extra information to
364364
them.
365365

@@ -398,9 +398,71 @@ These are the steps:
398398

399399
.. image:: http://i.imgur.com/u5vusQR.png
400400

401-
2. Then click on the **Import Tasks** button, and select the **Flickr importer**:
401+
2. Then click on the **Import Tasks** button, and select the **Dropbox importer**:
402+
403+
.. image:: http://i.imgur.com/GbdkgEI.png
404+
405+
3. Fill in the two fields you will find in the form. The first one is for the
406+
source of your tweets. If you want them to be imported from a user account, then
407+
write it with the "@" symbol, like "@PyBossa". If you just want to import tweets
408+
containing a word on them (or a #hashtag), then type it there. The second field
409+
is for you to specify how many tweets you want to import. You can import as many
410+
as you want!
411+
412+
Finally, click on the "Import" button, and you are done:
413+
414+
.. image:: http://i.imgur.com/hYWxI19.png
415+
416+
.. _twitter-import:
417+
418+
Importing the tasks from a Twitter account or search result
419+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
420+
421+
Another option for importing tasks is using the built-in Twitter importer. It
422+
allows to import tweets as tasks from either a specified Twitter user account, or
423+
from the results returned from a search to the Twitter search API.
424+
425+
Tasks imported with it will have the tweet data attached to their info field,
426+
and can later be used from within the task presenter. This data is a direct
427+
transcription of the data returned by the Twitter API, in particular a Tweet_
428+
object.
429+
430+
.. _Tweet: https://dev.twitter.com/overview/api/tweets
431+
432+
Please notice that the values returned by the Twitter API may vary. However,
433+
the following fields are guaranteed to be always included in the info field of
434+
the tasks:
435+
436+
* created_at: the date and time the tweet was made.
437+
* favorite_count: number of times the tweet has been marked as 'favorite'.
438+
* retweet_count: number of times the tweet has been retweeted.
439+
* coordinates: geographic coordinates of the place the tweet was made from. Note
440+
that this is not always available for every tweet.
441+
* tweet_id: the internal ID handled by Twitter to identify this tweet.
442+
* user: an object_ with information about the tweet author, as returned by the
443+
Twitter API.
444+
* text: the actual content of the tweet.
445+
446+
In addition, an extra field "user_screen_name" has been added to the info field:
447+
* user_screen_name: the screen name (or 'handle') of the author of the tweet.
448+
449+
.. _object: https://dev.twitter.com/overview/api/users
450+
451+
For more information, please refer to the Twitter_ documentation.
452+
.. _Twitter: https://dev.twitter.com/
453+
454+
.. note::
455+
**When importing tweets from a search, retweets will be ignored!**
456+
457+
So, to import tasks with the Twitter importer, do as follows:
458+
459+
1. Navigate to your project's page and click in the **Tasks** section:
460+
461+
.. image:: http://i.imgur.com/u5vusQR.png
462+
463+
2. Then click on the **Import Tasks** button, and select the **Twitter importer**:
402464

403-
.. image:: http://i.imgur.com/e9GhNlE.png
465+
.. image:: http://i.imgur.com/GbdkgEI.png
404466

405467
3. Click on the "Choose from Dropbox" icon. You will be asked your Dropbox
406468
account credentials. then select as many files as you want:

Diff for: doc/user/project_settings.rst

+3-3
Original file line numberDiff line numberDiff line change
@@ -258,10 +258,10 @@ navigation bar:
258258

259259
Tasks can be imported using any of the PyBossa built-in importers, such
260260
as :ref:`csv-import` and :ref:`epicollect-import`. To set up an autoimporter,
261-
please refer to the instructions for :ref:`csv-import`, :ref:`epicollect-import`
262-
or :ref:`flickr-import`, as the procedure is the same:
261+
please refer to the instructions for :ref:`csv-import`, :ref:`epicollect-import`,
262+
:ref:`flickr-import` or :ref:`twitter-import`, as the procedure is the same:
263263

264-
.. image:: http://i.imgur.com/nvTP7aX.png
264+
.. image:: http://i.imgur.com/20PHlHe.png
265265

266266
The only difference is that the tasks won't be imported only once, but regularly,
267267
as explained. However, the same behaviour should be expected, so autoimporting a

Diff for: pybossa/__init__.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -26,4 +26,4 @@
2626
"""
2727

2828

29-
__version__ = "1.2.2" # pragma: no cover
29+
__version__ = "1.3.0" # pragma: no cover

Diff for: pybossa/core.py

+42-11
Original file line numberDiff line numberDiff line change
@@ -276,15 +276,22 @@ def setup_blueprints(app):
276276
for bp in blueprints:
277277
app.register_blueprint(bp['handler'], url_prefix=bp['url_prefix'])
278278

279-
# The RQDashboard is actually registering a blueprint to the app, so this is
280-
# a propper place for it to be initialized
281279
from rq_dashboard import RQDashboard
282280
RQDashboard(app, url_prefix='/admin/rq', auth_handler=current_user,
283281
redis_conn=sentinel.master)
284282

285283

286284
def setup_external_services(app):
287285
"""Setup external services."""
286+
setup_twitter_login(app)
287+
setup_facebook_login(app)
288+
setup_google_login(app)
289+
setup_flickr_importer(app)
290+
setup_dropbox_importer(app)
291+
setup_twitter_importer(app)
292+
293+
294+
def setup_twitter_login(app):
288295
try: # pragma: no cover
289296
if (app.config['TWITTER_CONSUMER_KEY'] and
290297
app.config['TWITTER_CONSUMER_SECRET']):
@@ -297,9 +304,10 @@ def setup_external_services(app):
297304
print inst
298305
print "Twitter signin disabled"
299306
log_message = 'Twitter signin disabled: %s' % str(inst)
300-
app.logger.error(log_message)
307+
app.logger.info(log_message)
301308

302-
# Enable Facebook if available
309+
310+
def setup_facebook_login(app):
303311
try: # pragma: no cover
304312
if (app.config['FACEBOOK_APP_ID']
305313
and app.config['FACEBOOK_APP_SECRET']):
@@ -312,9 +320,10 @@ def setup_external_services(app):
312320
print inst
313321
print "Facebook signin disabled"
314322
log_message = 'Facebook signin disabled: %s' % str(inst)
315-
app.logger.error(log_message)
323+
app.logger.info(log_message)
324+
316325

317-
# Enable Google if available
326+
def setup_google_login(app):
318327
try: # pragma: no cover
319328
if (app.config['GOOGLE_CLIENT_ID']
320329
and app.config['GOOGLE_CLIENT_SECRET']):
@@ -327,24 +336,28 @@ def setup_external_services(app):
327336
print inst
328337
print "Google signin disabled"
329338
log_message = 'Google signin disabled: %s' % str(inst)
330-
app.logger.error(log_message)
339+
app.logger.info(log_message)
331340

332-
# Enable Flickr if available
341+
342+
def setup_flickr_importer(app):
333343
try: # pragma: no cover
334344
if (app.config['FLICKR_API_KEY']
335345
and app.config['FLICKR_SHARED_SECRET']):
336346
flickr.init_app(app)
337347
from pybossa.view.flickr import blueprint as flickr_bp
338348
app.register_blueprint(flickr_bp, url_prefix='/flickr')
349+
importer_params = {'api_key': app.config['FLICKR_API_KEY']}
350+
importer.register_flickr_importer(importer_params)
339351
except Exception as inst: # pragma: no cover
340352
print type(inst)
341353
print inst.args
342354
print inst
343355
print "Flickr importer not available"
344356
log_message = 'Flickr importer not available: %s' % str(inst)
345-
app.logger.error(log_message)
357+
app.logger.info(log_message)
358+
346359

347-
# Enable Dropbox if available
360+
def setup_dropbox_importer(app):
348361
try: # pragma: no cover
349362
if app.config['DROPBOX_APP_KEY']:
350363
importer.register_dropbox_importer()
@@ -354,7 +367,25 @@ def setup_external_services(app):
354367
print inst
355368
print "Dropbox importer not available"
356369
log_message = 'Dropbox importer not available: %s' % str(inst)
357-
app.logger.error(log_message)
370+
app.logger.info(log_message)
371+
372+
373+
def setup_twitter_importer(app):
374+
try: # pragma: no cover
375+
if (app.config['TWITTER_CONSUMER_KEY'] and
376+
app.config['TWITTER_CONSUMER_SECRET']):
377+
importer_params = {
378+
'consumer_key': app.config['TWITTER_CONSUMER_KEY'],
379+
'consumer_secret': app.config['TWITTER_CONSUMER_SECRET']
380+
}
381+
importer.register_twitter_importer(importer_params)
382+
except Exception as inst: # pragma: no cover
383+
print type(inst)
384+
print inst.args
385+
print inst
386+
print "Twitter importer not available"
387+
log_message = 'Twitter importer not available: %s' % str(inst)
388+
app.logger.info(log_message)
358389

359390

360391
def setup_geocoding(app):

Diff for: pybossa/flickr_client.py

+7-10
Original file line numberDiff line numberDiff line change
@@ -27,16 +27,15 @@ class FlickrClient(object):
2727
def __init__(self, app=None):
2828
"""Init method."""
2929
self.app = app
30-
self.client = None
30+
self.oauth_client = None
3131
if app is not None: # pragma: no cover
3232
self.init_app(app)
3333

3434
def init_app(self, app): # pragma: no cover
3535
"""Method to init object following factories pattern."""
3636
from flask import session
37-
from pybossa.core import importer
3837
self.app = app
39-
self.client = OAuth().remote_app(
38+
self.oauth_client = OAuth().remote_app(
4039
'flickr',
4140
request_token_url='https://www.flickr.com/services/oauth/request_token',
4241
access_token_url='https://www.flickr.com/services/oauth/access_token',
@@ -45,9 +44,7 @@ def init_app(self, app): # pragma: no cover
4544
consumer_secret=app.config['FLICKR_SHARED_SECRET'],
4645
access_token_method='GET')
4746
tokengetter = functools.partial(self.get_token, session)
48-
self.client.tokengetter(tokengetter)
49-
importer_params = {'api_key': app.config['FLICKR_API_KEY']}
50-
importer.register_flickr_importer(importer_params)
47+
self.oauth_client.tokengetter(tokengetter)
5148

5249
def get_user_albums(self, session):
5350
"""Get user albums from Flickr."""
@@ -58,7 +55,7 @@ def get_user_albums(self, session):
5855
'&primary_photo_extras=url_q'
5956
'&format=json&nojsoncallback=1'
6057
% self._get_user_nsid(session))
61-
res = self.client.get(url, token='')
58+
res = self.oauth_client.get(url, token='')
6259
if res.status == 200 and res.data.get('stat') == 'ok':
6360
albums = res.data['photosets']['photoset']
6461
return [self._extract_album_info(album) for album in albums]
@@ -70,15 +67,15 @@ def get_user_albums(self, session):
7067

7168
def authorize(self, *args, **kwargs):
7269
"""Authorize method."""
73-
return self.client.authorize(*args, **kwargs)
70+
return self.oauth_client.authorize(*args, **kwargs)
7471

7572
def authorized_response(self):
7673
"""Authorized response."""
77-
return self.client.authorized_response()
74+
return self.oauth_client.authorized_response()
7875

7976
def get_oauth_client(self):
8077
"""Get OAuth client."""
81-
return self.client
78+
return self.oauth_client
8279

8380
def get_token(self, session):
8481
"""Get token from session."""

0 commit comments

Comments
 (0)