ajung avatar ajung committed f9646df

- completely rewritten dropbox oauth api
- caching dropbox auth token

Comments (0)

Files changed (6)

docs/source/CHANGES.rst

 ------------------
 
 - enhanced resources_registry API 
+- completely rewritten Dropbox oAuth interface
 
 0.1.0 (11.07.2013)
 ------------------

docs/source/README.rst

 
 - Python 2.7 
 
+For using the Dropbox storage API of ``pp.core`` you need to have ``Phantomjs``
+installed (the ``phantomjs`` binary must be available in the ``$PATH``. PhantomJS
+is required to fake the OAuth process of Dropbox.
+
 Source code
 -----------
 

pp/core/fs_dropbox.py

 # (C) 2013, ZOPYX Limited, www.zopyx.com
 ################################################################
 
-import mechanize
+import os
+import cPickle
+from os.path import expanduser
+import time
+from dropbox import client 
+from dropbox import rest
 from dropbox import session
 from dropboxfs import DropboxFS
+from splinter import Browser
 import fs.wrapfs
 
-DROPBOX_ACCESS_TYPE = 'dropbox'
+from pp.core.logger import LOG
+
+
+access_type = 'dropbox'
+
 
 class DropboxFSWrapper(fs.wrapfs.WrapFS):
     """ A wrapper for a DropboxFS in order to sandbox
 
 def dropboxfs_factory(app_key, app_secret, username, password):
 
-    sess = session.DropboxSession(app_key,
-                                  app_secret,
-                                  DROPBOX_ACCESS_TYPE)
-    request_token = sess.obtain_request_token()
-    url = sess.build_authorize_url(request_token)
-
-    # Emulate automatic login
-    br = mechanize.Browser()
-    page = br.open(url)
-    br.select_form(nr=0)
-    br.form['login_email'] = username
-    br.form['login_password'] = password
-    br.submit()
-    response = br.response().read()
-
-    br.select_form(nr=0)
-    br.submit()
-    response = br.response().read()
-
-    # successful login
-    access_token = sess.obtain_access_token(request_token)
-
-    fs = DropboxFS(app_key,
-                   app_secret,
-                   DROPBOX_ACCESS_TYPE, 
-                   access_token.key, 
-                   access_token.secret)
-    return DropboxFSWrapper(fs)
+    home = expanduser("~")
+    token_filename = os.path.join(home, '.ppcore_{}'.format(username))
+
+    if os.path.exists(token_filename):
+
+        with open(token_filename, 'rb') as fp:
+            access_token = cPickle.loads(fp.read())
+
+    else:
+
+        access_token = None
+        sess = session.DropboxSession(app_key, app_secret, access_type)
+        request_token = sess.obtain_request_token()
+        urlDropbox = sess.build_authorize_url(request_token)
+
+        browser = Browser('phantomjs')
+        LOG.debug('Starting phantomjs browser {}'.format(urlDropbox))
+        browser.visit(urlDropbox)
+
+        browser.find_by_id('email-field').first.find_by_id('login_email').first.fill(username)
+        LOG.debug('Email form successfully filled')
+
+        browser.find_by_id('login_password').first.fill(password)
+        LOG.debug('Password form successfully filled')
+
+        submitButton = browser.is_element_present_by_name('login_submit_dummy')
+
+        if submitButton == True:
+            LOG.debug('Pausing for 5 seconds to avoid clicking errors')
+            time.sleep(5)
+            browser.find_by_name('login_submit_dummy').first.click()
+            LOG.debug('"Submit" button successfully clicked')
+
+            # Allow connection with Dropbox
+            allowButton = browser.is_element_present_by_css('.freshbutton-blue')
+
+            if allowButton == True:
+                browser.find_by_css('.freshbutton-blue').click()
+                browser.quit()
+                access_token = sess.obtain_access_token(request_token)
+                with open(token_filename, 'wb') as fp:
+                    fp.write(cPickle.dumps(access_token))
+
+            else:
+                LOG.error('The "Allow" button is not present, quitting.')
+                browser.quit()
+
+        else:
+            LOG.error('The "Submit" button was not present, quitting.')
+            browser.quit()
+
+    if access_token:
+        fs = DropboxFS(app_key,
+                       app_secret,
+                       access_type, 
+                       access_token.key, 
+                       access_token.secret)
+        return DropboxFSWrapper(fs)
+    else:
+        raise RuntimeError('Unable to get hold of Dropbox access token')

pp/core/project.py

         for name in self.fslayer.listdir(self.current_path):
             fullname = os.path.join(self.current_path, name)
             destdir = os.path.join(self.versions_path, new_version)
-            self.fslayer.makedir(destdir, allow_recreate=True, recursive=True)
+            if not self.fslayer.exists(destdir):
+                self.fslayer.makedir(destdir, allow_recreate=True, recursive=True)
             destname = os.path.join(self.versions_path, new_version, name)
             with self.fslayer.open(destname, 'wb') as fp:
                 fp.write(self.fslayer.open(fullname, 'rb').read())

pp/core/tests/test_project.py

 class Base(object):
 
     def _populate_current(self):
+
         for i in range(5):
             destname = os.path.join(self.project.current_path, 'name%d' % i)
             with self.fslayer.open(destname, 'w') as fp:
     'dropboxfs',
     'dropbox',
     'mechanize',
+    'splinter',
     'fs',
     'boto',
 ]
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.