# vim: set filencoding=utf8 """ Remember The Milk Authentication @author: Mike Crute (mcrute@ag.com) @organization: American Greetings Interactive @date: February 03, 2010 """ import json import urllib from logging import getLogger from hashlib import md5 from milkman import API_URL logger = getLogger('rtmapi') class APIPerms(object): READ = "read" WRITE = "write" DELETE = "delete" def flatten_sorted_dict(in_dict): items = sorted(in_dict.items()) flat_items = [''.join(item) for item in items] return ''.join(flat_items) class APIError(Exception): pass class Request(object): def __init__(self, api_key, secret, service='rest'): self.service = service self.secret = secret self.params = { 'format': 'json', 'api_key': api_key, } @classmethod def get_factory(cls, api_key, secret): return lambda: cls(api_key, secret) @property def url(self): self._sign_request() params = urllib.urlencode(self.params) return '{0}/{1}?{2}'.format(API_URL, self.service, params) def _sign_request(self): param_string = self.secret param_string += flatten_sorted_dict(self.params) self.params['api_sig'] = md5(param_string).hexdigest() def __setitem__(self, key, value): self.params[key] = value def __getitem__(self, key): return self.params[key] def _parse_json_data(self, data): body = data['rsp'] status = body['stat'] if status == 'fail': error = APIError(body['err']['msg']) error.code = int(body['err']['code']) raise error del body['stat'] return body def execute(self): data = urllib.urlopen(self.url) raw_data = data.read() json_data = json.loads(raw_data) return self._parse_json_data(json_data) class Authenticator(object): def __init__(self, request_factory): self.request_factory = request_factory self.token = None def authenticate(self, token=None): if token: self.token = token if not self.check_token(self.token): raw_input("Please visit: {0}".format(self.get_auth_url())) self.token = self.get_token() def get_auth_url(self): req = self.request_factory() req.service = 'auth' req['perms'] = APIPerms.DELETE req['frob'] = self._get_frob() return req.url def _get_frob(self): req = self.request_factory() req['method'] = 'rtm.auth.getFrob' self.frob = req.execute()['frob'] return self.frob def get_token(self): req = self.request_factory() req['method'] = 'rtm.auth.getToken' req['frob'] = self.frob print req.execute() def check_token(self, token): if not token: return False req = self.request_factory() req['method'] = 'rtm.auth.checkToken' req['token'] = token try: req.execute() return True except APIError, err: if err.code == 98: return False raise class APIConnection(object): def __init__(self, api_key, secret): self.request_factory = Request.get_factory(api_key, secret) self.auth = Authenticator(self.request_factory) def authenticate(self, token=None): self.auth.authenticate(token) print self.auth.token def get_lists(self): req = self.request_factory() req['method'] = 'rtm.lists.getList' req['auth_token'] = self.auth.token print req.execute() if __name__ == '__main__': API_KEY = "38816a01a7937588081d33ea74b6f5ee" SECRET = "d4caed275cf9a63e" TOKEN = "54f3378cb114e6cc330e1c2fd34a11e96e2a26c5" api = APIConnection(API_KEY, SECRET) api.authenticate(TOKEN) api.get_lists()