#!/usr/bin/env python """ Script to award the flock paparazzi badge. We scrape g+ and flickr for photos tagged Flock and Fedora, with the people we find who posted those, we try our best to match them with a FAS username. If we can, then we award them the badge. Author: Ralph Bean """ from __future__ import print_function import __main__ __main__.__requires__ = __requires__ = ["tahrir-api", "sqlalchemy>=0.7"]; import pkg_resources pkg_resources.require(__requires__) import socket import time import getpass import ConfigParser import requests import fedora.client import transaction import tahrir_api.dbapi import fedmsg import fedmsg.config fm_config = fedmsg.config.load_config() fm_config['cert_prefix'] = 'fedbadges' fm_config['name'] = 'relay_inbound' fm_config['active'] = True fedmsg.init(**fm_config) import fedbadges.utils # Get config secrets from a file config = ConfigParser.ConfigParser() config.read(['flock-paparazzi.ini', '/etc/flock-paparazzi.ini']) flickr_api_key = config.get('general', 'flickr_api_key') g_plus_key = config.get('general', 'g_plus_key') userIP = config.get('general', 'userIP') fas_username = config.get('general', 'fas_username') fas_password = config.get('general', 'fas_password') # API urls flickr_url = 'https://api.flickr.com/services/rest/' g_plus_url = 'https://www.googleapis.com/plus/v1/activities' badge_id = 'flock-paparazzi' _fas_cache = {} def get_g_plus_persons(query): token = None while True: params = dict(query=query, key=g_plus_key, userIP=userIP) if token: params['pageToken'] = token response = requests.get(g_plus_url, params=params) body = response.json() token = body.get('nextPageToken', None) # No more results if not body.get('items', None): break # Otherwise, we have a page to process for item in body['items']: for attach in item['object'].get('attachments', []): if attach['objectType'] == 'album': yield item['actor']['displayName'] time.sleep(0.5) # So as to not get rate-limit banned. def flickr_request(**kwargs): response = requests.get(flickr_url, params=dict( api_key=flickr_api_key, format='json', nojsoncallback=1, **kwargs)) return response.json() def get_flickr_page(tags, page=1): return flickr_request( method='flickr.photos.search', content_type=1, tags=tags, tag_mode='all', page=page, ) def get_flickr_persons(tags): pages = get_flickr_page(tags)['photos']['pages'] seen = {} for i in range(1, pages + 1): d = get_flickr_page(tags, i) for photo in d['photos']['photo']: user_id = photo['owner'] if user_id in seen: continue seen[user_id] = {} # https://secure.flickr.com/services/api/flickr.people.getInfo.html user = flickr_request( method='flickr.people.getInfo', user_id=user_id, ) seen[user_id]['username1'] = user['person']['username']['_content'] seen[user_id]['username2'] = user['person']['path_alias'] if 'realname' in user['person']: seen[user_id]['realname1'] = \ user['person']['realname']['_content'] if not seen[user_id]['realname1']: continue try: seen[user_id]['realname2'] = ' '.join([ seen[user_id]['realname1'].split()[0], seen[user_id]['realname1'].split()[-1], ]) except Exception: import traceback traceback.print_exc() if "'" in seen[user_id]['realname1']: seen[user_id]['username3'] = \ seen[user_id]['realname1'].split("'")[1] if '"' in seen[user_id]['realname1']: seen[user_id]['username4'] = \ seen[user_id]['realname1'].split('"')[1] for user_id, d in seen.items(): for key, value in d.items(): yield value def make_fas_cache(username, password): global _fas_cache if _fas_cache: return _fas_cache print("No previous fas cache found. Looking to rebuild.") try: import fedora.client.fas2 except ImportError: print("No python-fedora installed. Not caching fas.") return {} if not username or not password: print("No fas credentials found. Not caching fas.") return {} fasclient = fedora.client.fas2.AccountSystem( username=username, password=password, ) timeout = socket.getdefaulttimeout() socket.setdefaulttimeout(600) try: print("Downloading FAS cache...") request = fasclient.send_request( '/user/list', req_params={'search': '*'}, auth=True, ) finally: socket.setdefaulttimeout(timeout) print("Caching necessary user data") for user in request['people']: for key in ['username', 'human_name']: if user[key]: _fas_cache[user[key]] = user['username'] del request del fasclient return _fas_cache def get_persons(): for person in get_g_plus_persons('Fedora FLOCK'): yield person for person in get_g_plus_persons('flocktofedora'): yield person for person in get_flickr_persons('fedora,flock'): yield person for person in get_flickr_persons('flocktofedora'): yield person def main(): # First, initialize the tahrir db connection uri = fm_config['badges_global']['database_uri'] tahrir = tahrir_api.dbapi.TahrirDatabase( uri, notification_callback=fedbadges.utils.notification_callback, ) # Then, build a fas cache. this takes forever.. cache = make_fas_cache(fas_username, fas_password) badge = tahrir.get_badge(badge_id) already_has_it = [a.person.nickname for a in badge.assertions] # Finally, query the two services and award as we can. for person in get_persons(): # Try to gracefully handle non-ascii names if we can try: person = person.encode('utf-8') except Exception: import traceback traceback.print_exc() continue print("* Considering", person) if person in cache: if cache[person] in already_has_it: print("Skipping %r" % cache[person]) continue print(" *", cache[person], "gets the badge") already_has_it.append(cache[person]) email = cache[person] + "@fedoraproject.org" try: transaction.begin() tahrir.add_assertion(badge_id, email, None) transaction.commit() time.sleep(1) except Exception as e: transaction.abort() print("Failure:", e) if __name__ == '__main__': main()