From 006689c7cdc79038757882ba1a36358a632b493f Mon Sep 17 00:00:00 2001 From: csaunders Date: Sun, 9 Oct 2011 03:16:56 +0800 Subject: [PATCH] PhoneGap wrapper around Shopify4J to make authenticated API calls to the Shopify API from Javascript --- Android/ShopGap/README.md | 100 +++++++++++++++++++++ Android/ShopGap/ShopGapPlugin.java | 138 +++++++++++++++++++++++++++++ Android/ShopGap/shopgap.js | 41 +++++++++ 3 files changed, 279 insertions(+) create mode 100644 Android/ShopGap/README.md create mode 100644 Android/ShopGap/ShopGapPlugin.java create mode 100644 Android/ShopGap/shopgap.js diff --git a/Android/ShopGap/README.md b/Android/ShopGap/README.md new file mode 100644 index 00000000..8e3f7983 --- /dev/null +++ b/Android/ShopGap/README.md @@ -0,0 +1,100 @@ +# ShopGap plugin for Android/Phonegap + +Chris Saunders // @csaunders + +## About + +ShopGap is a wrapper around [Shopify4J](http://github.com/shopify/Shopify4J) to allow you to make Authenticated API calls to the Shopify API. + +## Dependencies + +You will need to include Shopify4J and all of it's dependencies in your project in order for this tool to work. This should be as simple as adding Shopify4J as a Library in your Android configuration. + +## Using the plugin + +**This has been developed against PhoneGap 1.1.0** + +* Add java code to your projects source + +* Register the plugin in the plugins.xml file + +```xml + +``` + +* Setup your authenticated session with the Shopify API + +```javascript +window.plugins.shopGap.setup( + 'YOUR_API_KEY', + 'GENERATED_API_PASSWORD', + 'SHOP_NAME', + successFunctionOrNull, + failureFunctionOrNull +); +``` + +* Make calls to the Shopify API + +```javascript +var success = function(resultJson){ + console.log(JSON.stringify(resultJson)); +} + +window.plugins.shopGap.read( + 'products', // endpoint + null, // query -- not supported yet + null, // data -- not needed for GET requests + function(r){success(r);}, // success callback + function(e){console.log}); // failure callback +``` + +### Endpoints + +The plugin takes care of most of the work for the endpoints, all you need to +do is fill in a few missing pieces. + +```javascript +// get all products, +window.plugins.shopGap.read('products', null, null, s, f); + +// get product 1 +window.plugins.shopGap.read('products/1', null, null, s, f); + +// create product +window.plugins.shopGap.create('products', null, JSON.stringify(newProduct), s, f); + +// update product 1 +window.plugins.shopGap.update('products/1', null, JSON.stringify(updateProduct), s, f); + +// delete product 1 +window.plugins.shopGap.destry('products/1', null, null, s, f); +``` + +## Release Notes + +0.1.0 Initial Release + +## License + +The MIT License + +Copyright (c) 2011 Chris Saunders + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. \ No newline at end of file diff --git a/Android/ShopGap/ShopGapPlugin.java b/Android/ShopGap/ShopGapPlugin.java new file mode 100644 index 00000000..d4308d17 --- /dev/null +++ b/Android/ShopGap/ShopGapPlugin.java @@ -0,0 +1,138 @@ +package ca.christophersaunders.shopgap; + +import java.io.BufferedInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.StringReader; + +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; + +import com.phonegap.api.Plugin; +import com.phonegap.api.PluginResult; +import com.phonegap.api.PluginResult.Status; +import com.shopify.api.client.ShopifyClient; +import com.shopify.api.credentials.Credential; +import com.shopify.api.endpoints.JsonPipeService; + +public class ShopGapPlugin extends Plugin { + private static final String API_KEY = "apikey"; + private static final String PASSWORD = "password"; + private static final String SHOPNAME = "shopname"; + private static final String CALL = "call"; + private static final String ENDPOINT = "endpoint"; + private static final String QUERY = "query"; + private static final String DATA = "data"; + + private ShopifyClient client; + private JsonPipeService service; + + enum Methods { CALL_API, SETUP }; + enum Call { READ, CREATE, UPDATE, DESTROY }; + + @Override + public PluginResult execute(String func, JSONArray arguments, String callbackId) { + try { + JSONObject argsMap = arguments.getJSONObject(0); + switch(determineMethod(func)) { + case CALL_API: + JSONObject results = callAPI(determineCall(argsMap.getString(CALL)), argsMap); + return new PluginResult(Status.OK, results); + case SETUP: + if(setupClient(argsMap)) { + return new PluginResult(Status.OK); + } + break; + default: + return new PluginResult(PluginResult.Status.INVALID_ACTION); + } + } catch (JSONException e) { + // Trololololololo + return new PluginResult(PluginResult.Status.JSON_EXCEPTION); + } + return null; + } + + private Methods determineMethod(String name){ + if(name.equals("callapi")) + return Methods.CALL_API; + if(name.equals("setup")) + return Methods.SETUP; + return null; + } + + private Call determineCall(String callname) { + if(callname.equals("read")) + return Call.READ; + if (callname.equals("update")) + return Call.UPDATE; + if (callname.equals("create")) + return Call.CREATE; + if (callname.equals("destroy")) + return Call.DESTROY; + return null; + } + + private boolean setupClient(JSONObject args) throws JSONException { + if (args.has(API_KEY) && args.has(PASSWORD) && args.has(SHOPNAME)) { + String apiKey = args.getString(API_KEY); + String passwd = args.getString(PASSWORD); + String shop = args.getString(SHOPNAME); + + Credential cred = new Credential(apiKey, "", shop, passwd); + client = new ShopifyClient(cred); + service = client.constructService(JsonPipeService.class); + return true; + } + return false; + } + + private JSONObject callAPI(Call call, JSONObject args) { + try { + String endpoint = null, data = null, query = null; + if(args.has(ENDPOINT)) + endpoint = args.getString(ENDPOINT); + if(args.has(QUERY)) + query = args.getString(QUERY); + if(args.has(DATA)) + data = args.getString(DATA); + + InputStream result = null; + + switch(call) { + case CREATE: + result = service.create(endpoint, data); + break; + case READ: + result = service.read(endpoint); + break; + case UPDATE: + result = service.update(endpoint, data); + break; + case DESTROY: + result = service.destroy(endpoint); + break; + } + + if( result != null) { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + BufferedInputStream bis = new BufferedInputStream(result); + byte[] resultData = new byte[0x4000]; + int dataRead = 0; + while((dataRead = bis.read(resultData)) > 0) { + baos.write(resultData, 0, dataRead); + } + return new JSONObject(new String(baos.toByteArray())); + } + + } catch (JSONException e) { + e.printStackTrace(); + } catch (IOException e) { + e.printStackTrace(); + } + return new JSONObject(); + } + +} diff --git a/Android/ShopGap/shopgap.js b/Android/ShopGap/shopgap.js new file mode 100644 index 00000000..4da4a332 --- /dev/null +++ b/Android/ShopGap/shopgap.js @@ -0,0 +1,41 @@ +var ShopGap = function(){}; + +ShopGap.prototype.setup = function(apiKey, password, shopname, onSuccessFn, onFailureFn){ + var args = {'apikey': apiKey, 'password': password, 'shopname': shopname}; + return PhoneGap.exec(onSuccessFn, onFailureFn, 'ShopGapPlugin', 'setup', [args]); +}; + +ShopGap.prototype.consArgs = function(call, endpoint, query, data){ + return {call: call, endpoint: endpoint, query: query, data: data}; +}; + +ShopGap.prototype.read = function(endpoint, query, data, success, failure){ + return this.callapi(this.consArgs('read', endpoint, query, data), success, failure); +}; + +ShopGap.prototype.update = function(endpoint, query, data, success, failure){ + return this.callapi(this.consArgs('update', endpoint, query, data), success, failure); +}; + +ShopGap.prototype.create = function(endpoint, query, data, success, failure){ + return this.callapi(this.consArgs('create', endpoint, query, data), success, failure); +}; + +ShopGap.prototype.destroy = function(endpoint, query, data, success, failure){ + return this.callapi(this.consArgs('destroy', endpoint, query, data), success, failure); +}; + +ShopGap.prototype.callapi = function(args, onSuccessFn, onFailureFn){ + return PhoneGap.exec(onSuccessFn, onFailureFn, 'ShopGapPlugin', 'callapi', [args]); +}; + +/* +ShopGap.prototype.callapi = function(call, endpoint, query, data, onSuccessFn, onFailureFn){ + var args = {'endpoint': endpoint, 'data': data, 'query': query}; + return PhoneGap.exec(onSuccessFn, onFailureFn, 'ShopGapPlugin', 'callapi', [args]); +}; +*/ + +PhoneGap.addConstructor(function(){ + PhoneGap.addPlugin('shopGap', new ShopGap()); +});