First commit. Here we go.
[canola-rtm] / canola-rtm / rtm / client.py
diff --git a/canola-rtm/rtm/client.py b/canola-rtm/rtm/client.py
new file mode 100644 (file)
index 0000000..b4c93b6
--- /dev/null
@@ -0,0 +1,156 @@
+# -*- coding: utf-8 -*-
+# Canola2 Remember The Milk Plugin
+# Authors: Andrey Popelo <andrey@popelo.com>
+#
+# Based on Python module for Remember The Milk API
+# (http://intellectronica.net/python-rtm) 
+# originally created by Tom Berger <tom.berger@gmail.com>
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+# Additional permission under GNU GPL version 3 section 7
+#
+# If you modify this Program, or any covered work, by linking or combining it
+# with Canola2 and its core components (or a modified version of any of those),
+# containing parts covered by the terms of Instituto Nokia de Tecnologia End
+# User Software Agreement, the licensors of this Program grant you additional
+# permission to convey the resulting work.
+
+from urllib import urlencode
+from urllib2 import urlopen
+from md5 import md5
+
+
+class Method(object):
+    """Remember The Milk API method.
+    
+    This class represents an RTM API method. Together with Client class and
+    Category class it allows to access RTM API methods using dot-notation.
+    Eg.
+                rtm.tasks.getList()
+       Client --^   ^     ^-- Method
+                    └- Category
+    """
+
+    def __init__(self, client, category_name, method_name):
+        self.client = client
+        self.category_name = category_name
+        self.method_name = method_name
+
+    def __call__(self, **kwargs):
+        return self.client.get(
+            method='rtm.%s.%s' % (self.category_name, self.method_name),
+            auth_token=self.client.token,
+            **kwargs)
+
+
+class Category(object):
+    """Remember The Milk API category.
+    
+    This class represents an RTM API category. Together with Client class and
+    Method class it allows to access RTM API methods using dot-notation.
+    Eg.
+                rtm.tasks.getList()
+       Client --^   ^     ^-- Method
+                    └- Category
+    """
+
+    def __init__(self, client, category_name):
+        self.client = client
+        self.category_name = category_name
+
+    def __getattr__(self, attr):
+        return Method(self.client, self.category_name, attr)
+
+
+class Client(object):
+    """Remember The Milk Backend.
+
+    This class provides an interface to manage data on Remember The Milk
+    server.
+    You can access RTM API methods using dot-notation.
+    Eg.
+                rtm.tasks.getList()
+       Client --^   ^     ^-- Method
+                    └- Category
+    """
+
+    URL_SERVICE_REST = "http://api.rememberthemilk.com/services/rest/"
+    URL_SERVICE_AUTH = "http://www.rememberthemilk.com/services/auth/"
+
+    def __init__(self, api_key, secret, token=None):
+        self.api_key = api_key
+        self.secret = secret
+        self._token = token
+        self._frob = None
+
+    def __getattr__(self, attr):
+        return Category(self, attr)
+
+    def sign(self, params):
+        data = self.secret + ''.join(
+            k + params[k] for k in sorted(params.keys()))
+
+        # KILLME
+        print "\n Sign data: " + data + "\n"
+
+        return md5(data).hexdigest()
+
+    def fetch(self, url, **kwargs):
+        if kwargs:
+            url = url + '?' + urlencode(kwargs)
+
+        # KILLME
+        print "\nRTM Request:\n  " + url + "\n"
+
+        return urlopen(url).read()
+
+    def get(self, **params):
+        params['api_key'] = self.api_key
+        params['format'] = 'json'
+        params['api_sig'] = self.sign(params)
+
+        json = self.fetch(self.URL_SERVICE_REST, **params)
+
+        # KILLME
+        print "\nRTM Response:\n  " + json + "\n"
+
+        # TODO parse json and return valid data
+
+        return None
+
+    @property
+    def auth_url(self):
+        params = {
+            'api_key': self.api_key,
+            'perms'  : 'delete',
+            'frob'   : self.frob
+            }
+        params['api_sig'] = self.sign(params)
+        return self.URL_SERVICE_AUTH + '?' + urlencode(params)
+
+    @property
+    def token(self):
+        if self._token is None:
+            frob = self._frob
+            rsp = self.get(method='rtm.auth.getToken', frob=frob)
+            self._token = rsp.auth.token
+        return self._token
+
+    @property
+    def frob(self):
+        if self._frob is None:
+            rsp = self.get(method='rtm.auth.getFrob')
+            self._frob = rsp.frob
+        return self._frob