[gnome-maps/wip/osm-edit: 9/16] osmEdit: Implement OAuth-authorized calls for updating



commit a8b3e811c0ade01b76c1baa6b469ed7af8c629bd
Author: Marcus Lundblad <ml update uu se>
Date:   Mon Nov 23 22:56:09 2015 +0100

    osmEdit: Implement OAuth-authorized calls for updating
    
    https://bugzilla.gnome.org/show_bug.cgi?id=726628

 src/osmConnection.js |  166 ++++++++++++++++++++++++++++++++++++--------------
 src/osmEdit.js       |    2 +-
 2 files changed, 120 insertions(+), 48 deletions(-)
---
diff --git a/src/osmConnection.js b/src/osmConnection.js
index 53dbf55..d547100 100644
--- a/src/osmConnection.js
+++ b/src/osmConnection.js
@@ -52,8 +52,13 @@ const OSMConnection = new Lang.Class({
 
     _init: function(params) {
         this._session = new Soup.Session();
+        /* OAuth proxy used for enrolling access tokens */
         this._oauthProxy = Rest.OAuthProxy.new(CONSUMER_KEY, CONSUMER_SECRET,
                                                OAUTH_ENDPOINT_URL, false);
+        /* OAuth proxy used for making OSM uploads */
+        this._callProxy = Rest.OAuthProxy.new(CONSUMER_KEY, CONSUMER_SECRET,
+                                              BASE_URL + '/' + API_VERSION,
+                                              false);
 
         /* TODO: stopgap to supply username/password
            to use with HTTP basic auth, should be
@@ -123,27 +128,66 @@ const OSMConnection = new Lang.Class({
     },
 
     openChangeset: function(comment, callback) {
+        /* we assume that this would only be called if there's already been an
+           OAuth access token enrolled, so, if the currently instanciated
+           proxy instance doesn't have a token set, we could safely count on
+           it being present in the keyring */
+        if (this._oauthProxy.get_token() === null) {
+            Secret.password_lookup(SECRET_SCHEMA, {}, null,
+                                   function(source, result) {
+                                        this._onPasswordLookedUp(result,
+                                                                 comment,
+                                                                 callback);
+                                   }.bind(this));
+        } else {
+            this._doOpenChangeset(comment, callback);
+        }
+    },
+
+    _onPasswordLookedUp: function(result, comment, callback) {
+        let password = Secret.password_lookup_finish(result);
+
+        if (password) {
+            let token = password.split(':')[0];
+            let secret = password.split(':')[1];
+
+            this._callProxy.token = token;
+            this._callProxy.token_secret = secret;
+            this._doOpenChangeset(comment, callback);
+        } else {
+            callback(false, null, null);
+        }
+    },
+
+    _doOpenChangeset: function(comment, callback) {
         let changeset =
             Maps.OSMChangeset.new(comment, 'gnome-maps ' + pkg.version);
         let xml = changeset.serialize();
 
         Utils.debug('about open changeset:\n' + xml + '\n');
 
-        let url = this._getOpenChangesetUrl();
-        let uri = new Soup.URI(url);
-        let msg = new Soup.Message({ method: 'PUT', uri: uri });
-        msg.set_request('text/xml', Soup.MemoryUse.COPY, xml, xml.length);
+        let call = Maps.OSMOAuthProxyCall.new(this._callProxy, xml);
+        call.set_method('PUT');
+        call.set_function('/changeset/create');
 
-        this._session.queue_message(msg, (function(obj, message) {
-            if (message.status_code !== Soup.Status.OK) {
-                callback(false, message.status_code, null);
-                return;
-            }
+        call.invoke_async(null, (function(call, res, userdata) {
+                    this._onChangesetOpened(call, callback);
+                                }).bind(this));
+    },
+
+    _onChangesetOpened: function(call, callback) {
+        Utils.debug('status: ' + call.get_status_code());
+
+        if (call.get_status_code() !== Soup.Status.OK) {
+            callback(false, call.get_status_code(), null);
+            return;
+        }
+
+        let changesetId = GLib.ascii_strtoull(call.get_payload(), '', 10);
+
+        Utils.debug('opened changeset: ' + changesetId);
 
-            let changesetId =
-                GLib.ascii_strtoull (message.response_body.data, '', 10);
-            callback(true, message.status_code, changesetId);
-        }));
+        callback(true, call.get_status_code(), changesetId);
     },
 
     uploadObject: function(object, type, changeset, callback) {
@@ -153,19 +197,22 @@ const OSMConnection = new Lang.Class({
 
         Utils.debug('about to upload object:\n' + xml + '\n');
 
-        let url = this._getCreateOrUpdateUrl(object, type);
-        let uri = new Soup.URI(url);
-        let msg = new Soup.Message({ method: 'PUT', uri: uri });
-        msg.set_request('text/xml', Soup.MemoryUse.COPY, xml, xml.length);
+        let call = Maps.OSMOAuthProxyCall.new(this._callProxy, xml);
+        call.set_method('PUT');
+        call.set_function(this._getCreateOrUpdateFunction(object, type));
 
-        this._session.queue_message(msg, (function(obj, message) {
-            if (message.status_code !== Soup.Status.OK) {
-                callback(false, message.status_code, null);
-                return;
-            }
+        call.invoke_async(null, (function(call, res, userdata) {
+                    this._onObjectUploaded(call, callback);
+                                }).bind(this));
+    },
 
-            callback(true, message.status_code, message.response_body.data);
-        }));
+    _onObjectUploaded: function(call, callback) {
+        if (call.get_status_code() !== Soup.Status.OK) {
+            callback(false, call.get_status_code(), null);
+            return;
+        }
+
+        callback(true, call.get_status_code(), call.get_payload());
     },
 
     deleteObject: function(object, type, changeset, callback) {
@@ -174,37 +221,41 @@ const OSMConnection = new Lang.Class({
 
         Utils.debug('about to delete object:\n' + xml + '\n');
 
-        let url = this._getDeleteUrl(object, type);
-        let uri = new Soup.URI(url);
-        let msg = new Soup.Message({ method: 'DELETE', uri: uri });
-
-        Utils.debug('calling delete URL: ' + url);
+        let call = Maps.OSMOAuthProxyCall.new(this._callProxy, xml);
+        call.set_method('DELETE');
+        call.set_function(this._getDeleteFunction(object, type));
 
-        msg.set_request('text/xml', Soup.MemoryUse.COPY, xml, xml.length);
+        call.invoke_async(null, (function(call, res, userdata) {
+                    this._onObjectDeleted(call, callback);
+                                }).bind(this));
+    },
 
-        this._session.queue_message(msg, (function(obj, message) {
-            if (message.status_code !== Soup.Status.OK) {
-                callback(false, message.status_code, null);
-                return;
-            }
+    _onObjectDeleted: function(call, callback) {
+        if (call.get_status_code() !== Soup.Status.OK) {
+            callback(false, call.get_status_code(), null);
+            return;
+        }
 
-            callback(true, message.status_code, message.response_body.data);
-        }));
+        callback(true, call.get_status_code(), call.get_payload());
     },
 
     closeChangeset: function(changesetId, callback) {
-        let url = this._getCloseChangesetUrl(changesetId);
-        let uri = new Soup.URI(url);
-        let msg = new Soup.Message({ method: 'PUT', uri: uri });
+        let call = this._callProxy.new_call();
+        call.set_method('PUT');
+        call.set_function(this._getCloseChangesetFunction(changesetId));
 
-        this._session.queue_message(msg, (function(obj, message) {
-            if (message.status_code !== Soup.Status.OK) {
-                callback(false, message.status_code);
-                return;
-            }
+        call.invoke_async(null, (function(call, res, userdata) {
+                    this._onChangesetClosed(call, callback);
+                                }).bind(this));
+    },
 
-            callback(true, message.status_code);
-        }));
+    _onChangesetClosed: function(call, callback) {
+        if (call.get_status_code() !== Soup.Status.OK) {
+            callback(false, call.get_status_code(), null);
+            return;
+        }
+
+        callback(true, call.get_status_code(), call.get_payload());
     },
 
     _getOpenChangesetUrl: function() {
@@ -216,6 +267,10 @@ const OSMConnection = new Lang.Class({
             changesetId + '/close';
     },
 
+    _getCloseChangesetFunction: function(changesetId) {
+        return '/changeset/' + changesetId + '/close';
+    },
+
     _getCreateOrUpdateUrl: function(object, type) {
         if (object.id) {
             let id = object.id;
@@ -233,6 +288,13 @@ const OSMConnection = new Lang.Class({
         }
     },
 
+    _getCreateOrUpdateFunction: function(object, type) {
+        if (object.id)
+            return type + '/' + object.id;
+        else
+            return type + '/create';
+    },
+
     _getDeleteUrl: function(object, type) {
         let id = object.id;
 
@@ -247,6 +309,10 @@ const OSMConnection = new Lang.Class({
         return this._getBaseUrl() + '/' + API_VERSION + '/' + type + '/' + id;
     },
 
+    _getDeleteFunction: function(object, type) {
+        return type + '/' + id;
+    },
+
     _authenticate: function(session, msg, auth, retrying, user_data) {
         Utils.debug('authenticate triggered');
         if (retrying)
@@ -426,6 +492,12 @@ const OSMConnection = new Lang.Class({
     },
 
     signOut: function() {
+        /* clear token on call proxy, so it will use a new token if the user
+           signs in again (with a new access token) during this running
+           session */
+        this._callProxy.token = null;
+        this._callProxy.token_secret = null;
+
         Secret.password_clear(SECRET_SCHEMA, {}, null,
             this._onPasswordCleared.bind(this));
     },
diff --git a/src/osmEdit.js b/src/osmEdit.js
index 274d51b..6c88cec 100644
--- a/src/osmEdit.js
+++ b/src/osmEdit.js
@@ -83,7 +83,7 @@ const OSMEdit = new Lang.Class({
     _onChangesetOpened: function(success, status, changesetId, object, type,
                                  action, callback) {
         if (success) {
-            let osmType = this._getOSMTypeName(type);
+            let osmType = Utils.osmTypeToString(type);
             action(object, osmType, changesetId, callback);
         } else {
             callback(false, status);


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]