├── .gitignore ├── .travis.yml ├── LICENSE ├── README.md ├── clojure ├── .gitignore ├── README.md ├── project.clj ├── resources │ └── config.clj └── src │ └── sphere_hello_api │ └── product.clj ├── create_config.sh ├── crystal ├── .editorconfig ├── .gitignore ├── README.md ├── shard.yml ├── spec │ ├── spec_helper.cr │ └── sphereio_spec.cr └── src │ └── sphereio.cr ├── curl ├── README.md ├── config └── hello-api ├── go └── README.md ├── groovy ├── .gitignore ├── README.md ├── apidump.groovy ├── config.groovy ├── index.groovy ├── runtest.sh └── server.groovy ├── haskell ├── README.md ├── config.json ├── sphere-hello-api.cabal └── src │ ├── Main.hs │ └── SphereHelloApi │ ├── ApiAccess.hs │ ├── Products.hs │ └── Tokens.hs ├── ios ├── .gitignore ├── HelloAPI.xcodeproj │ ├── project.pbxproj │ └── project.xcworkspace │ │ └── contents.xcworkspacedata ├── HelloAPI.xcworkspace │ └── contents.xcworkspacedata ├── HelloAPI │ ├── CTAppDelegate.h │ ├── CTAppDelegate.m │ ├── CTDetailViewController.h │ ├── CTDetailViewController.m │ ├── CTMasterViewController.h │ ├── CTMasterViewController.m │ ├── Default-568h@2x.png │ ├── Default.png │ ├── Default@2x.png │ ├── HelloAPI-Info.plist │ ├── HelloAPI-Prefix.pch │ ├── en.lproj │ │ ├── CTDetailViewController_iPad.xib │ │ ├── CTDetailViewController_iPhone.xib │ │ ├── CTMasterViewController_iPad.xib │ │ ├── CTMasterViewController_iPhone.xib │ │ └── InfoPlist.strings │ ├── main.m │ └── project.plist ├── HelloAPITests │ ├── HelloAPITests-Info.plist │ ├── HelloAPITests.h │ ├── HelloAPITests.m │ └── en.lproj │ │ └── InfoPlist.strings ├── Podfile ├── Podfile.lock ├── README.md ├── screenshot-ipad.png └── screenshot-iphone.png ├── java └── README.md ├── javascript ├── .gitignore ├── Gruntfile.coffee ├── README.md ├── bin │ └── get_token ├── index.html ├── package.json └── src │ ├── hello.coffee │ ├── hello.js │ └── test.coffee ├── kotlin └── README.md ├── nodejs └── README.md ├── php └── README.md ├── python2 ├── README.md ├── config.py ├── hello-api └── requirements.txt ├── python3 ├── README.md ├── config.py ├── hello-api └── requirements.txt ├── renovate.json ├── ruby ├── .gitignore ├── Gemfile ├── README.md ├── config.yaml ├── hello-api └── lib │ └── login.rb ├── rust ├── .gitignore ├── Cargo.toml ├── HACKING.md ├── README.md ├── examples │ └── fetch_products.rs ├── rustfmt.toml ├── src │ ├── auth.rs │ ├── client.rs │ ├── errors.rs │ ├── lib.rs │ └── region.rs └── tests │ └── auth.rs └── scala ├── .gitignore ├── README.md ├── build.sbt ├── project └── build.properties └── src └── main ├── resources ├── application.conf └── logback.xml └── scala └── SphereHello.scala /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | *.iml 3 | .gradle 4 | *.pyc -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: java 2 | script: 3 | - bash create_config.sh 4 | - export projects_dir=$(pwd) 5 | - export expected_product_count=5 6 | - cd $projects_dir/python2 && sudo pip install -r requirements.txt && ./hello-api | grep "MB PREMIUM TECH T" 7 | - cd $projects_dir/python3 && sudo apt-get install python3-setuptools && sudo easy_install3 pip && sudo pip install -r requirements.txt && ./hello-api | grep "MB PREMIUM TECH T" 8 | - cd $projects_dir/curl && sudo apt-get install jq && ./hello-api | grep $expected_product_count 9 | - cd $projects_dir/scala && sbt run | grep 'Number of products' 10 | - 'cd $projects_dir/javascript && npm install -g grunt-cli casperjs && npm install && ./bin/get_token --client_id "${CLIENT_ID}" --client_secret "${CLIENT_SECRET}" --project_key "${PROJECT_KEY}" && grunt test' 11 | - cd $projects_dir/groovy && sudo bash ./runtest.sh 12 | jdk: 13 | - oraclejdk8 14 | env: 15 | global: 16 | - secure: ISBTx5dCLRYtT+vp5MXFiZoJMF9l/I+W40fCIGp/OYJVm5uX3QdY9tqmPPJtHyGNYC/U2MNrhg/Z+8opwxQ931e9kCUfg/7nk6EX8t0gYV4tMKkaqr+NJ7S7uyu8SrFbcwABzUo5/91ujKkrsp/R5yQ/kCggDND+utpEVSWB9LY= 17 | - secure: cTja//s9O9IYrCOgjeFp4j0MJzVfjCnADlF69hPQsLaJNAPAGc6JRcUeaOeVZHSMI3y3qh4IGgfAm3QuxyUFTn5RP0OVpDAYri29Ubn7SYA55cho7K+YUZbrnCFuFMypZ8dVVbdZA2cFefUUnVhuGXHFlVUWUPUwUFd0o2oSw5Y= 18 | - secure: j3EAxprAcKq4aaGn/WA9VKn41C9Kismp/I0caLWP6k2dZvk1SZGnaiZXuAeqLxQMQ4cU4WH6qupnxCb/oS+0OxIe6UE7QAM7Xk8e5jp52NTubCkBJH04gi3BSVapLtDK1ePerNJuwOo0LZh9hwGwMWGy2XEZe59B5V50vvyp8Qo= 19 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 SPHERE.IO 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Hello Sphere API 2 | ================ 3 | 4 | ![SPHERE.IO icon](https://admin.sphere.io/assets/images/sphere_logo_rgb_long.png) 5 | 6 | [![Build Status](https://travis-ci.org/sphereio/sphere-hello-api.png?branch=master)](https://travis-ci.org/sphereio/sphere-hello-api) 7 | 8 | First steps to accessing the API of [SPHERE.IO](http://sphere.io/) in several languages. 9 | -------------------------------------------------------------------------------- /clojure/.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | /lib 3 | /classes 4 | /checkouts 5 | pom.xml 6 | pom.xml.asc 7 | *.jar 8 | *.class 9 | .lein-deps-sum 10 | .lein-failures 11 | .lein-plugins 12 | .lein-repl-history 13 | -------------------------------------------------------------------------------- /clojure/README.md: -------------------------------------------------------------------------------- 1 | # Clojure Hello on SPHERE.IO 2 | 3 | A clojure example to authenticate your application to [SPHERE.IO](http://sphere.io) and get the number of products 4 | in your project. 5 | 6 | ## Run 7 | 8 | The following steps assume a current [leiningen](http://leiningen.org/) installation on your machine. 9 | 10 | 1. `git clone git://github.com/commercetools/sphere-hello-api.git` 11 | 2. `cd sphere-hello-api/clojure` 12 | 3. Put your sphere credentials to the `resources/config.clj`. 13 | 4. Execute ```$ lein run``` 14 | 15 | -------------------------------------------------------------------------------- /clojure/project.clj: -------------------------------------------------------------------------------- 1 | (defproject sphere-hello-api "1.0" 2 | :description "An example application that authenticates and access project data using SPHERE.IO API" 3 | :main sphere-hello-api.product 4 | :dependencies 5 | [[org.clojure/clojure "1.5.1"] 6 | [clj-http "0.7.7"] 7 | [org.clojure/data.codec "0.1.0"] 8 | [org.clojure/data.json "0.2.3"] 9 | [sonian/carica "1.0.3"]]) 10 | -------------------------------------------------------------------------------- /clojure/resources/config.clj: -------------------------------------------------------------------------------- 1 | {:api-url "https://api.sphere.io" 2 | :auth-api-url "https://auth.sphere.io/oauth/token" 3 | 4 | ; TODO: fill in your sphere credentials 5 | :client-id "" 6 | :client-secret "" 7 | :project-key ""} -------------------------------------------------------------------------------- /clojure/src/sphere_hello_api/product.clj: -------------------------------------------------------------------------------- 1 | (ns sphere-hello-api.product 2 | (:use [carica.core]) 3 | (:require [clj-http.client :as client] 4 | [clojure.data.codec.base64 :as base64] 5 | [clojure.data.json :as json])) 6 | 7 | (defn encode [s] 8 | (String. (base64/encode (.getBytes s)) "UTF-8")) 9 | 10 | (defn login 11 | "Retrieves oauth access token" 12 | [] 13 | (let [auth-token (str "Basic " (encode (str (config :client-id) ":" (config :client-secret)))) 14 | auth-response (client/post (config :auth-api-url) 15 | {:headers {"Authorization" auth-token 16 | "Content-Type" "application/x-www-form-urlencoded"} 17 | :body (str "grant_type=client_credentials&scope=manage_project:" (config :project-key))})] 18 | ((json/read-str (:body auth-response)) "access_token"))) 19 | 20 | (defn -main [& args] 21 | (let [access-token (login) 22 | products-response (client/get 23 | (str (config :api-url) "/" (config :project-key) "/product-projections") 24 | {:headers {"Authorization" (str "Bearer " access-token)}})] 25 | (println "Number of products:" ((json/read-str (:body products-response)) "total")))) -------------------------------------------------------------------------------- /create_config.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | cat > "scala/src/main/resources/application.conf" << EOF 4 | sphere-hello { 5 | clientId=$CLIENT_ID 6 | clientSecret=$CLIENT_SECRET 7 | projectKey=$PROJECT_KEY 8 | } 9 | EOF 10 | 11 | cat > "curl/config" << EOF 12 | CLIENT_ID="$CLIENT_ID" 13 | CLIENT_SECRET="$CLIENT_SECRET" 14 | PROJECT_KEY="$PROJECT_KEY" 15 | EOF 16 | 17 | cat > "python2/config.py" << EOF 18 | PROJECT_KEY = "$PROJECT_KEY" 19 | CLIENT_ID = "$CLIENT_ID" 20 | CLIENT_SECRET = "$CLIENT_SECRET" 21 | EOF 22 | 23 | cat > "python3/config.py" << EOF 24 | PROJECT_KEY = "$PROJECT_KEY" 25 | CLIENT_ID = "$CLIENT_ID" 26 | CLIENT_SECRET = "$CLIENT_SECRET" 27 | EOF 28 | 29 | cat > "groovy/config.groovy" << EOF 30 | project_key = "$PROJECT_KEY" 31 | client_id = "$CLIENT_ID" 32 | client_secret = "$CLIENT_SECRET" 33 | EOF 34 | -------------------------------------------------------------------------------- /crystal/.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*.cr] 4 | charset = utf-8 5 | end_of_line = lf 6 | insert_final_newline = true 7 | indent_style = space 8 | indent_size = 2 9 | trim_trailing_whitespace = true 10 | -------------------------------------------------------------------------------- /crystal/.gitignore: -------------------------------------------------------------------------------- 1 | /docs/ 2 | /lib/ 3 | /bin/ 4 | /.shards/ 5 | *.dwarf 6 | 7 | # Libraries don't need dependency lock 8 | # Dependencies will be locked in applications that use them 9 | /shard.lock 10 | -------------------------------------------------------------------------------- /crystal/README.md: -------------------------------------------------------------------------------- 1 | # sphereio 2 | 3 | ## Usage 4 | 5 | ```crystal 6 | require "sphereio" 7 | ``` 8 | 9 | To get your access token using your `client_id` and `client_secret`: 10 | 11 | ```crystal 12 | SphereIO.login("MyClientID", "MyClientSecret", "MyProjectKey") 13 | ``` 14 | -------------------------------------------------------------------------------- /crystal/shard.yml: -------------------------------------------------------------------------------- 1 | name: sphereio 2 | version: 0.1.0 3 | 4 | authors: 5 | - Holden Omans 6 | 7 | crystal: 0.27.2 8 | 9 | license: MIT 10 | 11 | dependencies: 12 | halite: 13 | github: icyleaf/halite 14 | -------------------------------------------------------------------------------- /crystal/spec/spec_helper.cr: -------------------------------------------------------------------------------- 1 | require "spec" 2 | require "../src/sphereio" 3 | -------------------------------------------------------------------------------- /crystal/spec/sphereio_spec.cr: -------------------------------------------------------------------------------- 1 | require "./spec_helper" 2 | 3 | describe SphereIO do 4 | # TODO: Write tests 5 | 6 | it "works" do 7 | true.should eq(true) 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /crystal/src/sphereio.cr: -------------------------------------------------------------------------------- 1 | require "halite" 2 | require "base64" 3 | 4 | module SphereIO 5 | def self.login(client_id, client_secret, project_key) 6 | encoded = Base64.urlsafe_encode "#{client_id}:#{client_secret}" 7 | headers = { 8 | "Authorization" => "Basic #{encoded}", 9 | "Content-Type" => "application/x-www-form-urlencoded", 10 | } 11 | 12 | body = "grant_type=client_credentials&scope=manage_project:#{project_key}" 13 | resp = Halite.post("https://auth.sphere.io/oauth/token", headers: headers, raw: body) 14 | 15 | # Raise error on bad return status 16 | resp.raise_for_status 17 | 18 | # Return our access token as a string 19 | resp.parse("json")["access_token"].as_s 20 | rescue ex : Halite::ClientError | Halite::ServerError 21 | raise "Problems on getting access token from auth.sphere.io: [#{ex.status_code}] #{ex.status_message} (#{ex.class})" 22 | rescue ex 23 | raise "Problems on getting access token from auth.sphere.io: #{ex.message}" 24 | end 25 | end 26 | -------------------------------------------------------------------------------- /curl/README.md: -------------------------------------------------------------------------------- 1 | CURL Hello on SPHERE.IO 2 | ======================= 3 | 4 | An curl/bash example to authenticate your application to [SPHERE.IO](http://sphere.io) and get the number of products in your project. 5 | 6 | ## Run 7 | 8 | To get the command line usage just run: 9 | ```bash 10 | $ ./hello-api 11 | ``` 12 | 13 | If you don't want to pass your credentials via command line options, please have a look at the `config` file. 14 | -------------------------------------------------------------------------------- /curl/config: -------------------------------------------------------------------------------- 1 | CLIENT_ID="" 2 | CLIENT_SECRET="" 3 | PROJECT_KEY="" 4 | -------------------------------------------------------------------------------- /curl/hello-api: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | usage() { 4 | echo "$(basename $0) - get number of products in your sphere project." 5 | echo "" 6 | echo "Arguments:" 7 | echo "-c : Client ID of your sphere project." 8 | echo "-s : Client secret of your sphere project." 9 | echo "-p : Key of your sphere project." 10 | echo "-f : You can provide all those 3 arguments in a simple property file:" 11 | echo " CLIENT_ID=''" 12 | echo " CLIENT_SECRET=''" 13 | echo " PROJECT_KEY=''" 14 | } 15 | 16 | login() { 17 | local enc="$(echo -n "${CLIENT_ID}:${CLIENT_SECRET}" | base64)" 18 | local result="$(curl -s -X POST -H "Authorization: Basic ${enc}" -d "grant_type=client_credentials&scope=manage_project:${PROJECT_KEY}" https://auth.sphere.io/oauth/token)" 19 | local t="$(echo $result | jq '.access_token')" 20 | local t="${t%\"}" # removing leading quote 21 | readonly ACCESS_TOKEN="${t#\"}" # removing trailing quote 22 | if [ "$ACCESS_TOKEN" = "null" ]; then 23 | echo "$result" 24 | exit 2 25 | fi 26 | } 27 | 28 | get_products() { 29 | curl -s "https://api.sphere.io/${PROJECT_KEY}/product-projections?access_token=${ACCESS_TOKEN}" | jq '.total' 30 | } 31 | 32 | check_tools() { 33 | which curl >/dev/null 34 | if [ "$?" != "0" ]; then 35 | echo "Please install curl - http://curl.haxx.se/" 36 | exit 1 37 | fi 38 | which jq >/dev/null 39 | if [ "$?" != "0" ]; then 40 | echo "Please install jq - http://stedolan.github.io/jq/" 41 | exit 1 42 | fi 43 | } 44 | 45 | 46 | check_tools 47 | 48 | set -e 49 | 50 | while getopts "f:c:s:p:h" OPT; do 51 | case "${OPT}" in 52 | f) 53 | readonly CONFIG_FILE="${OPTARG}" 54 | ;; 55 | c) 56 | readonly CLIENT_ID="${OPTARG}" 57 | ;; 58 | s) 59 | readonly CLIENT_SECRET="${OPTARG}" 60 | ;; 61 | p) 62 | readonly PROJECT_KEY="${OPTARG}" 63 | ;; 64 | h) 65 | usage 66 | exit 0 67 | ;; 68 | *) 69 | echo "Unknown argument '${OPT}'!" 70 | usage 71 | exit 1 72 | ;; 73 | esac 74 | done 75 | 76 | if [ -f "$CONFIG_FILE" ]; then 77 | . $CONFIG_FILE 78 | fi 79 | 80 | if [ -z "$CLIENT_ID" ]; then 81 | echo "Parameter '-c'/client_id missing!" 82 | usage 83 | exit 1 84 | fi 85 | 86 | if [ -z "$CLIENT_SECRET" ]; then 87 | echo "Parameter '-s'/client_secret missing!" 88 | usage 89 | exit 1 90 | fi 91 | 92 | if [ -z "$PROJECT_KEY" ]; then 93 | echo "Parameter '-p'/project_key missing!" 94 | usage 95 | exit 1 96 | fi 97 | 98 | login 99 | get_products 100 | -------------------------------------------------------------------------------- /go/README.md: -------------------------------------------------------------------------------- 1 | See [sphere-hello-api-golang](https://github.com/sphereio/sphere-hello-api-golang) -------------------------------------------------------------------------------- /groovy/.gitignore: -------------------------------------------------------------------------------- 1 | lib 2 | .idea 3 | *.iml 4 | localconfig.groovy 5 | 6 | -------------------------------------------------------------------------------- /groovy/README.md: -------------------------------------------------------------------------------- 1 | 2 | # A minimal SPHERE.IO API access in groovy 3 | 4 | This are just two Groovy _scripts_ to play around. For real Groovy-based solutions please do all SPHERE.IO API access via the JVM SDK (https://github.com/sphereio/sphere-jvm-sdk). For production you may also want to take a look at High Performance Groovy-Capable Microframeworks like http://ratpack.io 5 | 6 | 7 | ## Prerequisite 8 | * Groovy 1.8.6 (or higher) on a Java 7 JVM (or higher). Please note: JVM8 is supported only from Groovy 2.3 upwards. 9 | * Working "groovy" (and optionally "grape") command in the path. 10 | * Internet Access 11 | 12 | ## How to run 13 | 1. Create an account and project at http://admin.sphere.io if you don't have one yet 14 | 2. Navigate to "Developers" -> "API CIENTS" and copy your permissions and project key into the `config.groovy` file. 15 | 3. Run application to fetch data from the API: 16 | * just call `groovy apidump.groovy` 17 | * play with adding calls to other endpoints and play with the results. The SPHERE.IO API documentation located at http://dev.sphere.io/ is your friend. 18 | 4. (optional) If you feel like wanting to show a Browser window, start the minimal webserver (depending on your Ivy environment, you may have to adjust the servlet API `@Grab` statement) 19 | * run `groovy ./server.groovy` 20 | * open http://localhost:8080/index.groovy in your Browser 21 | * start playing around in the template part of `index.groovy`. See http://groovy.codehaus.org/Groovlets with the MarkupBuilder for documentation. 22 | 23 | -------------------------------------------------------------------------------- /groovy/apidump.groovy: -------------------------------------------------------------------------------- 1 | import groovy.json.JsonSlurper 2 | import javax.xml.bind.DatatypeConverter 3 | 4 | def config = new ConfigSlurper().parse(new File('config.groovy').toURI().toURL()) 5 | 6 | def getOauthToken(config) { 7 | 8 | // Prepare oauth request 9 | def auth_url = new URL("https://auth.sphere.io/oauth/token") 10 | def query = "grant_type=client_credentials&scope=manage_project:$config.project_key" 11 | def secret = DatatypeConverter.printBase64Binary("$config.client_id:$config.client_secret".getBytes()); 12 | 13 | // do the oauth HTTP request the built-in (verbose) java way: 14 | def HttpURLConnection connection = auth_url.openConnection() 15 | connection.setRequestMethod("POST") 16 | connection.setRequestProperty("Authorization", "Basic $secret") 17 | connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded") 18 | connection.setDoOutput(true) 19 | 20 | def os = connection.getOutputStream() 21 | os.write(query.getBytes("UTF-8")) 22 | os.flush() 23 | os.close() 24 | connection.connect() 25 | def oauth_data = new JsonSlurper().parse(new InputStreamReader(connection.getInputStream(), "UTF-8")) 26 | connection.disconnect() 27 | 28 | return oauth_data 29 | } 30 | 31 | def callSphere(config, String endpoint, String query){ 32 | 33 | def apiUrl = new URL("https://api.sphere.io/$config.project_key/$endpoint?$config.query") 34 | def HttpURLConnection connection = apiUrl.openConnection() 35 | connection.setRequestMethod("GET") 36 | connection.setRequestProperty("Authorization", "Bearer $config.access_token") 37 | connection.setDoInput(true) 38 | connection.connect() 39 | def result = new JsonSlurper().parse(new InputStreamReader(connection.getInputStream(),"UTF-8")) 40 | connection.disconnect() 41 | return result 42 | } 43 | 44 | println "Getting oauth token" 45 | def oauth_data = getOauthToken(config) 46 | config.access_token = oauth_data["access_token"] 47 | 48 | println "querying SPHERE.IO" 49 | def productProjections = callSphere(config, "product-projections", "") 50 | 51 | // Dump the object serialization to stdout (here is a good point to start doing something sensible) 52 | // TODO pretty print the object 53 | println "here are your products as a groovy friednly nested map" 54 | println productProjections 55 | -------------------------------------------------------------------------------- /groovy/config.groovy: -------------------------------------------------------------------------------- 1 | project_key = "" 2 | client_id = "" 3 | client_secret = "" 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /groovy/index.groovy: -------------------------------------------------------------------------------- 1 | 2 | import groovy.json.JsonSlurper 3 | import javax.servlet.ServletContext 4 | 5 | 6 | def callSphere(String endpoint, String query){ 7 | def ServletContext app = application 8 | def project_key = app.getInitParameter("project_key") 9 | def access_token = app.getInitParameter("access_token") 10 | 11 | def apiUrl = new URL("https://api.sphere.io/$project_key/$endpoint?$query") 12 | def HttpURLConnection connection = apiUrl.openConnection() 13 | connection.setRequestMethod("GET") 14 | connection.setRequestProperty("Authorization", "Bearer $access_token") 15 | connection.setDoInput(true) 16 | connection.connect() 17 | def result = new JsonSlurper().parse(new InputStreamReader(connection.getInputStream(),"UTF-8")) 18 | connection.disconnect() 19 | return result 20 | } 21 | 22 | def productProjections = callSphere("product-projections", "") 23 | 24 | // using the "html" autobound groovlet magic to create the output. See http://groovy.codehaus.org/Groovlets, esp. the MarkupBuilder 25 | // TIP: use the ?. "safe dereference" Groovy operator when navigating optional parts of the API response, e.g. in localized string maps 26 | 27 | html.html { 28 | head { 29 | title 'SPHERE.IO Groovy Hello World' 30 | } 31 | body { 32 | h1 'Welcome to SPHERE.IO via Groovy' 33 | p "Found the following ${productProjections.count} Products" 34 | ul { 35 | for ( product in productProjections?.results) { 36 | li{ 37 | p "${product.name?.en}" 38 | for(image in product.masterVariant.images){ 39 | img(src : image.url, alt : product.name?.en, width: "150px", height: "150px") 40 | } 41 | } 42 | } 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /groovy/runtest.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # be verbose: 3 | set -x 4 | # return error for whole script if any command returns error (append " || true" to override that for a line): 5 | set -e 6 | # clear the fog about what's in the path: 7 | java -version || true 8 | 9 | # make sure groovy is there 10 | sudo apt-get install groovy 11 | 12 | # print groovy version for transparency. cross-check the java version 13 | groovy -version || true 14 | java -version || true 15 | 16 | # our travis is running on JVM8, too, but Groovy only supports JVM8 since Groovy 2.3, which isn't available on travis.) 17 | GROOVY_JVM=$(groovy -version 2>&1 | sed 's/.*JVM: \(.*\)\.\(.*\)\..*/\1\2/; 1q') 18 | 19 | # if groovy JVM is max 1.7, get stuff and grep for the result 20 | [ "$GROOVY_JVM" -ge 18 ] && echo "groovy is not compatible with JDK8 yet, skipping test" || groovy ./apidump.groovy | grep "MB PREMIUM TECH T" 21 | -------------------------------------------------------------------------------- /groovy/server.groovy: -------------------------------------------------------------------------------- 1 | import org.eclipse.jetty.server.Server 2 | import org.eclipse.jetty.servlet.* 3 | import groovy.servlet.* 4 | import groovy.json.JsonSlurper 5 | import javax.xml.bind.DatatypeConverter 6 | 7 | @Grapes([ 8 | @Grab(group='org.eclipse.jetty.aggregate', module='jetty-server', version='7.6.0.v20120127'), 9 | @Grab(group='org.eclipse.jetty.aggregate', module='jetty-servlet', version='7.6.0.v20120127'), 10 | @Grab(group='javax.servlet', module='servlet-api', version='2.5')]) 11 | 12 | def config = new ConfigSlurper().parse(new File('config.groovy').toURI().toURL()) 13 | 14 | def getOauthToken(config) { 15 | 16 | // Prepare oauth request 17 | def auth_url = new URL("https://auth.sphere.io/oauth/token") 18 | def query = "grant_type=client_credentials&scope=manage_project:$config.project_key" 19 | def secret = DatatypeConverter.printBase64Binary("$config.client_id:$config.client_secret".getBytes()); 20 | 21 | // do the oauth HTTP request the built-in (verbose) java way: 22 | def HttpURLConnection connection = auth_url.openConnection() 23 | connection.setRequestMethod("POST") 24 | connection.setRequestProperty("Authorization", "Basic $secret") 25 | connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded") 26 | connection.setDoOutput(true) 27 | 28 | def os = connection.getOutputStream() 29 | os.write(query.getBytes("UTF-8")) 30 | os.flush() 31 | os.close() 32 | connection.connect() 33 | def oauth_data = new JsonSlurper().parse(new InputStreamReader(connection.getInputStream(), "UTF-8")) 34 | connection.disconnect() 35 | 36 | return oauth_data 37 | } 38 | 39 | def startJetty(config) { 40 | def server = new Server(8080) 41 | def context = new ServletContextHandler(ServletContextHandler.SESSIONS) 42 | context.contextPath = '/' 43 | context.resourceBase = '.' 44 | context.setInitParameter("project_key", config.project_key) 45 | context.setInitParameter("access_token", config.access_token) 46 | context.addServlet(GroovyServlet, '/index.groovy') 47 | server.handler = context 48 | server.start() 49 | } 50 | 51 | println "Getting oauth token" 52 | def oauth_data = getOauthToken(config) 53 | config.access_token = oauth_data["access_token"] 54 | println "Starting Jetty" 55 | startJetty(config) 56 | println "open http://localhost:8080/index.groovy | press Ctrl+C to stop the server." 57 | -------------------------------------------------------------------------------- /haskell/README.md: -------------------------------------------------------------------------------- 1 | # Hello Sphere from Haskell 2 | 3 | The following steps assume an existing haskell installation incl. cabal, e.g. through [haskell-platform](http://www.haskell.org/platform/). 4 | 5 | 1. `git clone git://github.com/commercetools/sphere-hello-api.git` 6 | 2. `cd haskell` 7 | 3. `cabal install` 8 | 4. Put your credentials into `config.json` 9 | 5. `sphere-hello-api config.json` -------------------------------------------------------------------------------- /haskell/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "projectKey":"", 3 | "clientId":"", 4 | "clientSecret":"" 5 | } -------------------------------------------------------------------------------- /haskell/sphere-hello-api.cabal: -------------------------------------------------------------------------------- 1 | name: sphere-hello-api 2 | version: 0.1.0.0 3 | synopsis: Minimal usage sample of the Sphere HTTP APIs. 4 | homepage: http://sphere.io/ 5 | author: Commercetools 6 | maintainer: support@sphere.io 7 | build-type: Simple 8 | cabal-version: >=1.8 9 | 10 | executable sphere-hello-api 11 | hs-source-dirs: src 12 | main-is: Main.hs 13 | build-depends: base ==4.5.*, curl, json 14 | -------------------------------------------------------------------------------- /haskell/src/Main.hs: -------------------------------------------------------------------------------- 1 | module Main where 2 | 3 | import Control.Monad (forM_) 4 | import Network.Curl (withCurlDo) 5 | import Network.Curl.Easy (initialize) 6 | import System.Environment (getArgs) 7 | import System.Exit (exitFailure) 8 | import System.IO (hPutStrLn, stderr) 9 | 10 | import SphereHelloApi.ApiAccess 11 | import qualified SphereHelloApi.Products as Products 12 | import qualified SphereHelloApi.Tokens as Tokens 13 | 14 | main :: IO () 15 | main = withCurlDo $ do 16 | c <- initialize 17 | cfg <- getArgs >>= (\args -> 18 | case args of 19 | [file] -> loadConfig file 20 | _ -> (hPutStrLn stderr $ "Usage: sphere-hello-api ") >> exitFailure) 21 | t <- Tokens.getToken c cfg 22 | -- putStrLn $ "Your access token: " ++ Tokens.access_token t 23 | p <- Products.getProducts c cfg t 24 | putStrLn $ "You have " ++ show (Products.count p) ++ " product(s):" 25 | forM_ (Products.results p) (putStrLn . show) 26 | -------------------------------------------------------------------------------- /haskell/src/SphereHelloApi/ApiAccess.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE DeriveDataTypeable #-} 2 | module SphereHelloApi.ApiAccess where 3 | 4 | import Control.Monad (liftM) 5 | import Text.JSON.Generic 6 | 7 | data ApiConfig = ApiConfig { 8 | projectKey :: String 9 | , clientId :: String 10 | , clientSecret :: String 11 | } deriving (Eq, Show, Data, Typeable) 12 | 13 | loadConfig :: String -> IO ApiConfig 14 | loadConfig = (liftM decodeJSON) . readFile 15 | 16 | productsUrl :: ApiConfig -> String 17 | productsUrl cfg = "https://api-v0.sphere.io/" ++ projectKey cfg ++ "/product-projections" 18 | 19 | tokenUrl = "https://auth-v0.sphere.io/oauth/token" 20 | -------------------------------------------------------------------------------- /haskell/src/SphereHelloApi/Products.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE DeriveDataTypeable #-} 2 | module SphereHelloApi.Products (getProducts, ProductResponse (..), Product (..)) where 3 | 4 | import Network.Curl 5 | import SphereHelloApi.ApiAccess 6 | import SphereHelloApi.Tokens 7 | import Text.JSON.Generic 8 | 9 | getProductsOpts t = 10 | -- CurlVerbose True : 11 | CurlHttpHeaders ["Authorization: Bearer " ++ access_token t] : 12 | method_GET 13 | 14 | getProducts :: Curl -> ApiConfig -> TokenResponse -> IO ProductResponse 15 | getProducts c cfg t = do 16 | resp <- do_curl_ c (productsUrl cfg) (getProductsOpts t) :: IO CurlResponse 17 | -- putStrLn $ respBody resp 18 | return $ decodeJSON (respBody resp) 19 | 20 | data ProductResponse = ProductResponse { 21 | total :: Int 22 | , count :: Int 23 | , offset :: Int 24 | , results :: [Product] 25 | } deriving (Eq, Show, Data, Typeable) 26 | 27 | -- For all the available data see: http://sphere.io/dev/HTTP_API_Projects_Products.html#product-projection 28 | data Product = Product { 29 | name :: String 30 | , description :: String 31 | , slug :: String 32 | } deriving (Eq, Show, Data, Typeable) -------------------------------------------------------------------------------- /haskell/src/SphereHelloApi/Tokens.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE DeriveDataTypeable #-} 2 | module SphereHelloApi.Tokens (TokenResponse (..), getToken) where 3 | 4 | import Network.Curl 5 | import Text.JSON.Generic 6 | import SphereHelloApi.ApiAccess 7 | 8 | getTokenOpts :: ApiConfig -> [CurlOption] 9 | getTokenOpts cfg = 10 | -- CurlVerbose True : 11 | CurlPostFields ["grant_type=client_credentials&scope=manage_project:" ++ projectKey cfg] : 12 | CurlUserPwd (clientId cfg ++ ":" ++ clientSecret cfg) : 13 | method_POST 14 | 15 | getToken :: Curl -> ApiConfig -> IO TokenResponse 16 | getToken c cfg = do 17 | resp <- do_curl_ c tokenUrl (getTokenOpts cfg) :: IO CurlResponse 18 | return $ decodeJSON (respBody resp) 19 | 20 | data TokenResponse = TokenResponse { 21 | access_token :: String 22 | , token_type :: String 23 | , expires_in :: Int 24 | , scope :: String 25 | } deriving (Eq, Show, Data, Typeable) 26 | -------------------------------------------------------------------------------- /ios/.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | .DS_Store 3 | */build/* 4 | *.pbxuser 5 | !default.pbxuser 6 | *.mode1v3 7 | !default.mode1v3 8 | *.mode2v3 9 | !default.mode2v3 10 | *.perspectivev3 11 | !default.perspectivev3 12 | xcuserdata 13 | profile 14 | *.moved-aside 15 | DerivedData 16 | .idea/ 17 | *.hmap 18 | 19 | #CocoaPods 20 | Pods 21 | -------------------------------------------------------------------------------- /ios/HelloAPI.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 9FD7964601C0406D8EE47140 /* libPods.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 55C71F97EDD0414D82CA42FC /* libPods.a */; }; 11 | B983CA5117C39D5200CA9F48 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B983CA5017C39D5200CA9F48 /* UIKit.framework */; }; 12 | B983CA5317C39D5200CA9F48 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B983CA5217C39D5200CA9F48 /* Foundation.framework */; }; 13 | B983CA5517C39D5200CA9F48 /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B983CA5417C39D5200CA9F48 /* CoreGraphics.framework */; }; 14 | B983CA5B17C39D5200CA9F48 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = B983CA5917C39D5200CA9F48 /* InfoPlist.strings */; }; 15 | B983CA5D17C39D5200CA9F48 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = B983CA5C17C39D5200CA9F48 /* main.m */; }; 16 | B983CA6117C39D5200CA9F48 /* CTAppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = B983CA6017C39D5200CA9F48 /* CTAppDelegate.m */; }; 17 | B983CA6317C39D5200CA9F48 /* Default.png in Resources */ = {isa = PBXBuildFile; fileRef = B983CA6217C39D5200CA9F48 /* Default.png */; }; 18 | B983CA6517C39D5200CA9F48 /* Default@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = B983CA6417C39D5200CA9F48 /* Default@2x.png */; }; 19 | B983CA6717C39D5200CA9F48 /* Default-568h@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = B983CA6617C39D5200CA9F48 /* Default-568h@2x.png */; }; 20 | B983CA6A17C39D5200CA9F48 /* CTMasterViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = B983CA6917C39D5200CA9F48 /* CTMasterViewController.m */; }; 21 | B983CA6D17C39D5200CA9F48 /* CTDetailViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = B983CA6C17C39D5200CA9F48 /* CTDetailViewController.m */; }; 22 | B983CA7017C39D5200CA9F48 /* CTMasterViewController_iPhone.xib in Resources */ = {isa = PBXBuildFile; fileRef = B983CA6E17C39D5200CA9F48 /* CTMasterViewController_iPhone.xib */; }; 23 | B983CA7317C39D5200CA9F48 /* CTMasterViewController_iPad.xib in Resources */ = {isa = PBXBuildFile; fileRef = B983CA7117C39D5200CA9F48 /* CTMasterViewController_iPad.xib */; }; 24 | B983CA7617C39D5200CA9F48 /* CTDetailViewController_iPhone.xib in Resources */ = {isa = PBXBuildFile; fileRef = B983CA7417C39D5200CA9F48 /* CTDetailViewController_iPhone.xib */; }; 25 | B983CA7917C39D5200CA9F48 /* CTDetailViewController_iPad.xib in Resources */ = {isa = PBXBuildFile; fileRef = B983CA7717C39D5200CA9F48 /* CTDetailViewController_iPad.xib */; }; 26 | B983CA8117C39D5200CA9F48 /* SenTestingKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B983CA8017C39D5200CA9F48 /* SenTestingKit.framework */; }; 27 | B983CA8217C39D5200CA9F48 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B983CA5017C39D5200CA9F48 /* UIKit.framework */; }; 28 | B983CA8317C39D5200CA9F48 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B983CA5217C39D5200CA9F48 /* Foundation.framework */; }; 29 | B983CA8B17C39D5200CA9F48 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = B983CA8917C39D5200CA9F48 /* InfoPlist.strings */; }; 30 | B983CA8E17C39D5200CA9F48 /* HelloAPITests.m in Sources */ = {isa = PBXBuildFile; fileRef = B983CA8D17C39D5200CA9F48 /* HelloAPITests.m */; }; 31 | B9BDFB9E17C3AB2200F0E383 /* project.plist in Resources */ = {isa = PBXBuildFile; fileRef = B9BDFB9D17C3AB2200F0E383 /* project.plist */; }; 32 | /* End PBXBuildFile section */ 33 | 34 | /* Begin PBXContainerItemProxy section */ 35 | B983CA8417C39D5200CA9F48 /* PBXContainerItemProxy */ = { 36 | isa = PBXContainerItemProxy; 37 | containerPortal = B983CA4517C39D5100CA9F48 /* Project object */; 38 | proxyType = 1; 39 | remoteGlobalIDString = B983CA4C17C39D5200CA9F48; 40 | remoteInfo = HelloAPI; 41 | }; 42 | /* End PBXContainerItemProxy section */ 43 | 44 | /* Begin PBXFileReference section */ 45 | 3B0F7F0E74644BC3B85020B9 /* Pods.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = Pods.xcconfig; path = Pods/Pods.xcconfig; sourceTree = SOURCE_ROOT; }; 46 | 55C71F97EDD0414D82CA42FC /* libPods.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libPods.a; sourceTree = BUILT_PRODUCTS_DIR; }; 47 | B983CA4D17C39D5200CA9F48 /* HelloAPI.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = HelloAPI.app; sourceTree = BUILT_PRODUCTS_DIR; }; 48 | B983CA5017C39D5200CA9F48 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; }; 49 | B983CA5217C39D5200CA9F48 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; 50 | B983CA5417C39D5200CA9F48 /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; }; 51 | B983CA5817C39D5200CA9F48 /* HelloAPI-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "HelloAPI-Info.plist"; sourceTree = ""; }; 52 | B983CA5A17C39D5200CA9F48 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; 53 | B983CA5C17C39D5200CA9F48 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 54 | B983CA5E17C39D5200CA9F48 /* HelloAPI-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "HelloAPI-Prefix.pch"; sourceTree = ""; }; 55 | B983CA5F17C39D5200CA9F48 /* CTAppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CTAppDelegate.h; sourceTree = ""; }; 56 | B983CA6017C39D5200CA9F48 /* CTAppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = CTAppDelegate.m; sourceTree = ""; }; 57 | B983CA6217C39D5200CA9F48 /* Default.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = Default.png; sourceTree = ""; }; 58 | B983CA6417C39D5200CA9F48 /* Default@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Default@2x.png"; sourceTree = ""; }; 59 | B983CA6617C39D5200CA9F48 /* Default-568h@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Default-568h@2x.png"; sourceTree = ""; }; 60 | B983CA6817C39D5200CA9F48 /* CTMasterViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CTMasterViewController.h; sourceTree = ""; }; 61 | B983CA6917C39D5200CA9F48 /* CTMasterViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = CTMasterViewController.m; sourceTree = ""; }; 62 | B983CA6B17C39D5200CA9F48 /* CTDetailViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CTDetailViewController.h; sourceTree = ""; }; 63 | B983CA6C17C39D5200CA9F48 /* CTDetailViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = CTDetailViewController.m; sourceTree = ""; }; 64 | B983CA6F17C39D5200CA9F48 /* en */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = en; path = en.lproj/CTMasterViewController_iPhone.xib; sourceTree = ""; }; 65 | B983CA7217C39D5200CA9F48 /* en */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = en; path = en.lproj/CTMasterViewController_iPad.xib; sourceTree = ""; }; 66 | B983CA7517C39D5200CA9F48 /* en */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = en; path = en.lproj/CTDetailViewController_iPhone.xib; sourceTree = ""; }; 67 | B983CA7817C39D5200CA9F48 /* en */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = en; path = en.lproj/CTDetailViewController_iPad.xib; sourceTree = ""; }; 68 | B983CA7F17C39D5200CA9F48 /* HelloAPITests.octest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = HelloAPITests.octest; sourceTree = BUILT_PRODUCTS_DIR; }; 69 | B983CA8017C39D5200CA9F48 /* SenTestingKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SenTestingKit.framework; path = Library/Frameworks/SenTestingKit.framework; sourceTree = DEVELOPER_DIR; }; 70 | B983CA8817C39D5200CA9F48 /* HelloAPITests-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "HelloAPITests-Info.plist"; sourceTree = ""; }; 71 | B983CA8A17C39D5200CA9F48 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; 72 | B983CA8C17C39D5200CA9F48 /* HelloAPITests.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = HelloAPITests.h; sourceTree = ""; }; 73 | B983CA8D17C39D5200CA9F48 /* HelloAPITests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = HelloAPITests.m; sourceTree = ""; }; 74 | B9BDFB9D17C3AB2200F0E383 /* project.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = project.plist; sourceTree = ""; }; 75 | /* End PBXFileReference section */ 76 | 77 | /* Begin PBXFrameworksBuildPhase section */ 78 | B983CA4A17C39D5200CA9F48 /* Frameworks */ = { 79 | isa = PBXFrameworksBuildPhase; 80 | buildActionMask = 2147483647; 81 | files = ( 82 | B983CA5117C39D5200CA9F48 /* UIKit.framework in Frameworks */, 83 | B983CA5317C39D5200CA9F48 /* Foundation.framework in Frameworks */, 84 | B983CA5517C39D5200CA9F48 /* CoreGraphics.framework in Frameworks */, 85 | 9FD7964601C0406D8EE47140 /* libPods.a in Frameworks */, 86 | ); 87 | runOnlyForDeploymentPostprocessing = 0; 88 | }; 89 | B983CA7B17C39D5200CA9F48 /* Frameworks */ = { 90 | isa = PBXFrameworksBuildPhase; 91 | buildActionMask = 2147483647; 92 | files = ( 93 | B983CA8117C39D5200CA9F48 /* SenTestingKit.framework in Frameworks */, 94 | B983CA8217C39D5200CA9F48 /* UIKit.framework in Frameworks */, 95 | B983CA8317C39D5200CA9F48 /* Foundation.framework in Frameworks */, 96 | ); 97 | runOnlyForDeploymentPostprocessing = 0; 98 | }; 99 | /* End PBXFrameworksBuildPhase section */ 100 | 101 | /* Begin PBXGroup section */ 102 | B983CA4417C39D5100CA9F48 = { 103 | isa = PBXGroup; 104 | children = ( 105 | B983CA5617C39D5200CA9F48 /* HelloAPI */, 106 | B983CA8617C39D5200CA9F48 /* HelloAPITests */, 107 | B983CA4F17C39D5200CA9F48 /* Frameworks */, 108 | B983CA4E17C39D5200CA9F48 /* Products */, 109 | 3B0F7F0E74644BC3B85020B9 /* Pods.xcconfig */, 110 | ); 111 | sourceTree = ""; 112 | }; 113 | B983CA4E17C39D5200CA9F48 /* Products */ = { 114 | isa = PBXGroup; 115 | children = ( 116 | B983CA4D17C39D5200CA9F48 /* HelloAPI.app */, 117 | B983CA7F17C39D5200CA9F48 /* HelloAPITests.octest */, 118 | ); 119 | name = Products; 120 | sourceTree = ""; 121 | }; 122 | B983CA4F17C39D5200CA9F48 /* Frameworks */ = { 123 | isa = PBXGroup; 124 | children = ( 125 | B983CA5017C39D5200CA9F48 /* UIKit.framework */, 126 | B983CA5217C39D5200CA9F48 /* Foundation.framework */, 127 | B983CA5417C39D5200CA9F48 /* CoreGraphics.framework */, 128 | B983CA8017C39D5200CA9F48 /* SenTestingKit.framework */, 129 | 55C71F97EDD0414D82CA42FC /* libPods.a */, 130 | ); 131 | name = Frameworks; 132 | sourceTree = ""; 133 | }; 134 | B983CA5617C39D5200CA9F48 /* HelloAPI */ = { 135 | isa = PBXGroup; 136 | children = ( 137 | B983CA5F17C39D5200CA9F48 /* CTAppDelegate.h */, 138 | B983CA6017C39D5200CA9F48 /* CTAppDelegate.m */, 139 | B9BDFB9D17C3AB2200F0E383 /* project.plist */, 140 | B983CA6817C39D5200CA9F48 /* CTMasterViewController.h */, 141 | B983CA6917C39D5200CA9F48 /* CTMasterViewController.m */, 142 | B983CA6B17C39D5200CA9F48 /* CTDetailViewController.h */, 143 | B983CA6C17C39D5200CA9F48 /* CTDetailViewController.m */, 144 | B983CA6E17C39D5200CA9F48 /* CTMasterViewController_iPhone.xib */, 145 | B983CA7117C39D5200CA9F48 /* CTMasterViewController_iPad.xib */, 146 | B983CA7417C39D5200CA9F48 /* CTDetailViewController_iPhone.xib */, 147 | B983CA7717C39D5200CA9F48 /* CTDetailViewController_iPad.xib */, 148 | B983CA5717C39D5200CA9F48 /* Supporting Files */, 149 | ); 150 | path = HelloAPI; 151 | sourceTree = ""; 152 | }; 153 | B983CA5717C39D5200CA9F48 /* Supporting Files */ = { 154 | isa = PBXGroup; 155 | children = ( 156 | B983CA5817C39D5200CA9F48 /* HelloAPI-Info.plist */, 157 | B983CA5917C39D5200CA9F48 /* InfoPlist.strings */, 158 | B983CA5C17C39D5200CA9F48 /* main.m */, 159 | B983CA5E17C39D5200CA9F48 /* HelloAPI-Prefix.pch */, 160 | B983CA6217C39D5200CA9F48 /* Default.png */, 161 | B983CA6417C39D5200CA9F48 /* Default@2x.png */, 162 | B983CA6617C39D5200CA9F48 /* Default-568h@2x.png */, 163 | ); 164 | name = "Supporting Files"; 165 | sourceTree = ""; 166 | }; 167 | B983CA8617C39D5200CA9F48 /* HelloAPITests */ = { 168 | isa = PBXGroup; 169 | children = ( 170 | B983CA8C17C39D5200CA9F48 /* HelloAPITests.h */, 171 | B983CA8D17C39D5200CA9F48 /* HelloAPITests.m */, 172 | B983CA8717C39D5200CA9F48 /* Supporting Files */, 173 | ); 174 | path = HelloAPITests; 175 | sourceTree = ""; 176 | }; 177 | B983CA8717C39D5200CA9F48 /* Supporting Files */ = { 178 | isa = PBXGroup; 179 | children = ( 180 | B983CA8817C39D5200CA9F48 /* HelloAPITests-Info.plist */, 181 | B983CA8917C39D5200CA9F48 /* InfoPlist.strings */, 182 | ); 183 | name = "Supporting Files"; 184 | sourceTree = ""; 185 | }; 186 | /* End PBXGroup section */ 187 | 188 | /* Begin PBXNativeTarget section */ 189 | B983CA4C17C39D5200CA9F48 /* HelloAPI */ = { 190 | isa = PBXNativeTarget; 191 | buildConfigurationList = B983CA9117C39D5200CA9F48 /* Build configuration list for PBXNativeTarget "HelloAPI" */; 192 | buildPhases = ( 193 | 9E3F006D48344BB88386A4B6 /* Check Pods Manifest.lock */, 194 | B983CA4917C39D5200CA9F48 /* Sources */, 195 | B983CA4A17C39D5200CA9F48 /* Frameworks */, 196 | B983CA4B17C39D5200CA9F48 /* Resources */, 197 | BBE8EA69E6824CDEA5969F26 /* Copy Pods Resources */, 198 | ); 199 | buildRules = ( 200 | ); 201 | dependencies = ( 202 | ); 203 | name = HelloAPI; 204 | productName = HelloAPI; 205 | productReference = B983CA4D17C39D5200CA9F48 /* HelloAPI.app */; 206 | productType = "com.apple.product-type.application"; 207 | }; 208 | B983CA7E17C39D5200CA9F48 /* HelloAPITests */ = { 209 | isa = PBXNativeTarget; 210 | buildConfigurationList = B983CA9417C39D5200CA9F48 /* Build configuration list for PBXNativeTarget "HelloAPITests" */; 211 | buildPhases = ( 212 | B983CA7A17C39D5200CA9F48 /* Sources */, 213 | B983CA7B17C39D5200CA9F48 /* Frameworks */, 214 | B983CA7C17C39D5200CA9F48 /* Resources */, 215 | B983CA7D17C39D5200CA9F48 /* ShellScript */, 216 | ); 217 | buildRules = ( 218 | ); 219 | dependencies = ( 220 | B983CA8517C39D5200CA9F48 /* PBXTargetDependency */, 221 | ); 222 | name = HelloAPITests; 223 | productName = HelloAPITests; 224 | productReference = B983CA7F17C39D5200CA9F48 /* HelloAPITests.octest */; 225 | productType = "com.apple.product-type.bundle"; 226 | }; 227 | /* End PBXNativeTarget section */ 228 | 229 | /* Begin PBXProject section */ 230 | B983CA4517C39D5100CA9F48 /* Project object */ = { 231 | isa = PBXProject; 232 | attributes = { 233 | CLASSPREFIX = CT; 234 | LastUpgradeCheck = 0460; 235 | ORGANIZATIONNAME = Commercetools; 236 | }; 237 | buildConfigurationList = B983CA4817C39D5100CA9F48 /* Build configuration list for PBXProject "HelloAPI" */; 238 | compatibilityVersion = "Xcode 3.2"; 239 | developmentRegion = English; 240 | hasScannedForEncodings = 0; 241 | knownRegions = ( 242 | en, 243 | ); 244 | mainGroup = B983CA4417C39D5100CA9F48; 245 | productRefGroup = B983CA4E17C39D5200CA9F48 /* Products */; 246 | projectDirPath = ""; 247 | projectRoot = ""; 248 | targets = ( 249 | B983CA4C17C39D5200CA9F48 /* HelloAPI */, 250 | B983CA7E17C39D5200CA9F48 /* HelloAPITests */, 251 | ); 252 | }; 253 | /* End PBXProject section */ 254 | 255 | /* Begin PBXResourcesBuildPhase section */ 256 | B983CA4B17C39D5200CA9F48 /* Resources */ = { 257 | isa = PBXResourcesBuildPhase; 258 | buildActionMask = 2147483647; 259 | files = ( 260 | B983CA5B17C39D5200CA9F48 /* InfoPlist.strings in Resources */, 261 | B983CA6317C39D5200CA9F48 /* Default.png in Resources */, 262 | B983CA6517C39D5200CA9F48 /* Default@2x.png in Resources */, 263 | B983CA6717C39D5200CA9F48 /* Default-568h@2x.png in Resources */, 264 | B983CA7017C39D5200CA9F48 /* CTMasterViewController_iPhone.xib in Resources */, 265 | B983CA7317C39D5200CA9F48 /* CTMasterViewController_iPad.xib in Resources */, 266 | B983CA7617C39D5200CA9F48 /* CTDetailViewController_iPhone.xib in Resources */, 267 | B983CA7917C39D5200CA9F48 /* CTDetailViewController_iPad.xib in Resources */, 268 | B9BDFB9E17C3AB2200F0E383 /* project.plist in Resources */, 269 | ); 270 | runOnlyForDeploymentPostprocessing = 0; 271 | }; 272 | B983CA7C17C39D5200CA9F48 /* Resources */ = { 273 | isa = PBXResourcesBuildPhase; 274 | buildActionMask = 2147483647; 275 | files = ( 276 | B983CA8B17C39D5200CA9F48 /* InfoPlist.strings in Resources */, 277 | ); 278 | runOnlyForDeploymentPostprocessing = 0; 279 | }; 280 | /* End PBXResourcesBuildPhase section */ 281 | 282 | /* Begin PBXShellScriptBuildPhase section */ 283 | 9E3F006D48344BB88386A4B6 /* Check Pods Manifest.lock */ = { 284 | isa = PBXShellScriptBuildPhase; 285 | buildActionMask = 2147483647; 286 | files = ( 287 | ); 288 | inputPaths = ( 289 | ); 290 | name = "Check Pods Manifest.lock"; 291 | outputPaths = ( 292 | ); 293 | runOnlyForDeploymentPostprocessing = 0; 294 | shellPath = /bin/sh; 295 | shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [[ $? != 0 ]] ; then\n cat << EOM\nerror: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\nEOM\n exit 1\nfi\n"; 296 | showEnvVarsInLog = 0; 297 | }; 298 | B983CA7D17C39D5200CA9F48 /* ShellScript */ = { 299 | isa = PBXShellScriptBuildPhase; 300 | buildActionMask = 2147483647; 301 | files = ( 302 | ); 303 | inputPaths = ( 304 | ); 305 | outputPaths = ( 306 | ); 307 | runOnlyForDeploymentPostprocessing = 0; 308 | shellPath = /bin/sh; 309 | shellScript = "# Run the unit tests in this test bundle.\n\"${SYSTEM_DEVELOPER_DIR}/Tools/RunUnitTests\"\n"; 310 | }; 311 | BBE8EA69E6824CDEA5969F26 /* Copy Pods Resources */ = { 312 | isa = PBXShellScriptBuildPhase; 313 | buildActionMask = 2147483647; 314 | files = ( 315 | ); 316 | inputPaths = ( 317 | ); 318 | name = "Copy Pods Resources"; 319 | outputPaths = ( 320 | ); 321 | runOnlyForDeploymentPostprocessing = 0; 322 | shellPath = /bin/sh; 323 | shellScript = "\"${SRCROOT}/Pods/Pods-resources.sh\"\n"; 324 | showEnvVarsInLog = 0; 325 | }; 326 | /* End PBXShellScriptBuildPhase section */ 327 | 328 | /* Begin PBXSourcesBuildPhase section */ 329 | B983CA4917C39D5200CA9F48 /* Sources */ = { 330 | isa = PBXSourcesBuildPhase; 331 | buildActionMask = 2147483647; 332 | files = ( 333 | B983CA5D17C39D5200CA9F48 /* main.m in Sources */, 334 | B983CA6117C39D5200CA9F48 /* CTAppDelegate.m in Sources */, 335 | B983CA6A17C39D5200CA9F48 /* CTMasterViewController.m in Sources */, 336 | B983CA6D17C39D5200CA9F48 /* CTDetailViewController.m in Sources */, 337 | ); 338 | runOnlyForDeploymentPostprocessing = 0; 339 | }; 340 | B983CA7A17C39D5200CA9F48 /* Sources */ = { 341 | isa = PBXSourcesBuildPhase; 342 | buildActionMask = 2147483647; 343 | files = ( 344 | B983CA8E17C39D5200CA9F48 /* HelloAPITests.m in Sources */, 345 | ); 346 | runOnlyForDeploymentPostprocessing = 0; 347 | }; 348 | /* End PBXSourcesBuildPhase section */ 349 | 350 | /* Begin PBXTargetDependency section */ 351 | B983CA8517C39D5200CA9F48 /* PBXTargetDependency */ = { 352 | isa = PBXTargetDependency; 353 | target = B983CA4C17C39D5200CA9F48 /* HelloAPI */; 354 | targetProxy = B983CA8417C39D5200CA9F48 /* PBXContainerItemProxy */; 355 | }; 356 | /* End PBXTargetDependency section */ 357 | 358 | /* Begin PBXVariantGroup section */ 359 | B983CA5917C39D5200CA9F48 /* InfoPlist.strings */ = { 360 | isa = PBXVariantGroup; 361 | children = ( 362 | B983CA5A17C39D5200CA9F48 /* en */, 363 | ); 364 | name = InfoPlist.strings; 365 | sourceTree = ""; 366 | }; 367 | B983CA6E17C39D5200CA9F48 /* CTMasterViewController_iPhone.xib */ = { 368 | isa = PBXVariantGroup; 369 | children = ( 370 | B983CA6F17C39D5200CA9F48 /* en */, 371 | ); 372 | name = CTMasterViewController_iPhone.xib; 373 | sourceTree = ""; 374 | }; 375 | B983CA7117C39D5200CA9F48 /* CTMasterViewController_iPad.xib */ = { 376 | isa = PBXVariantGroup; 377 | children = ( 378 | B983CA7217C39D5200CA9F48 /* en */, 379 | ); 380 | name = CTMasterViewController_iPad.xib; 381 | sourceTree = ""; 382 | }; 383 | B983CA7417C39D5200CA9F48 /* CTDetailViewController_iPhone.xib */ = { 384 | isa = PBXVariantGroup; 385 | children = ( 386 | B983CA7517C39D5200CA9F48 /* en */, 387 | ); 388 | name = CTDetailViewController_iPhone.xib; 389 | sourceTree = ""; 390 | }; 391 | B983CA7717C39D5200CA9F48 /* CTDetailViewController_iPad.xib */ = { 392 | isa = PBXVariantGroup; 393 | children = ( 394 | B983CA7817C39D5200CA9F48 /* en */, 395 | ); 396 | name = CTDetailViewController_iPad.xib; 397 | sourceTree = ""; 398 | }; 399 | B983CA8917C39D5200CA9F48 /* InfoPlist.strings */ = { 400 | isa = PBXVariantGroup; 401 | children = ( 402 | B983CA8A17C39D5200CA9F48 /* en */, 403 | ); 404 | name = InfoPlist.strings; 405 | sourceTree = ""; 406 | }; 407 | /* End PBXVariantGroup section */ 408 | 409 | /* Begin XCBuildConfiguration section */ 410 | B983CA8F17C39D5200CA9F48 /* Debug */ = { 411 | isa = XCBuildConfiguration; 412 | buildSettings = { 413 | ALWAYS_SEARCH_USER_PATHS = NO; 414 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 415 | CLANG_CXX_LIBRARY = "libc++"; 416 | CLANG_ENABLE_OBJC_ARC = YES; 417 | CLANG_WARN_CONSTANT_CONVERSION = YES; 418 | CLANG_WARN_EMPTY_BODY = YES; 419 | CLANG_WARN_ENUM_CONVERSION = YES; 420 | CLANG_WARN_INT_CONVERSION = YES; 421 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 422 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 423 | COPY_PHASE_STRIP = NO; 424 | GCC_C_LANGUAGE_STANDARD = gnu99; 425 | GCC_DYNAMIC_NO_PIC = NO; 426 | GCC_OPTIMIZATION_LEVEL = 0; 427 | GCC_PREPROCESSOR_DEFINITIONS = ( 428 | "DEBUG=1", 429 | "$(inherited)", 430 | ); 431 | GCC_SYMBOLS_PRIVATE_EXTERN = NO; 432 | GCC_WARN_ABOUT_RETURN_TYPE = YES; 433 | GCC_WARN_UNINITIALIZED_AUTOS = YES; 434 | GCC_WARN_UNUSED_VARIABLE = YES; 435 | IPHONEOS_DEPLOYMENT_TARGET = 6.1; 436 | ONLY_ACTIVE_ARCH = YES; 437 | SDKROOT = iphoneos; 438 | TARGETED_DEVICE_FAMILY = "1,2"; 439 | }; 440 | name = Debug; 441 | }; 442 | B983CA9017C39D5200CA9F48 /* Release */ = { 443 | isa = XCBuildConfiguration; 444 | buildSettings = { 445 | ALWAYS_SEARCH_USER_PATHS = NO; 446 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 447 | CLANG_CXX_LIBRARY = "libc++"; 448 | CLANG_ENABLE_OBJC_ARC = YES; 449 | CLANG_WARN_CONSTANT_CONVERSION = YES; 450 | CLANG_WARN_EMPTY_BODY = YES; 451 | CLANG_WARN_ENUM_CONVERSION = YES; 452 | CLANG_WARN_INT_CONVERSION = YES; 453 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 454 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 455 | COPY_PHASE_STRIP = YES; 456 | GCC_C_LANGUAGE_STANDARD = gnu99; 457 | GCC_WARN_ABOUT_RETURN_TYPE = YES; 458 | GCC_WARN_UNINITIALIZED_AUTOS = YES; 459 | GCC_WARN_UNUSED_VARIABLE = YES; 460 | IPHONEOS_DEPLOYMENT_TARGET = 6.1; 461 | OTHER_CFLAGS = "-DNS_BLOCK_ASSERTIONS=1"; 462 | SDKROOT = iphoneos; 463 | TARGETED_DEVICE_FAMILY = "1,2"; 464 | VALIDATE_PRODUCT = YES; 465 | }; 466 | name = Release; 467 | }; 468 | B983CA9217C39D5200CA9F48 /* Debug */ = { 469 | isa = XCBuildConfiguration; 470 | baseConfigurationReference = 3B0F7F0E74644BC3B85020B9 /* Pods.xcconfig */; 471 | buildSettings = { 472 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 473 | GCC_PREFIX_HEADER = "HelloAPI/HelloAPI-Prefix.pch"; 474 | INFOPLIST_FILE = "HelloAPI/HelloAPI-Info.plist"; 475 | PRODUCT_NAME = "$(TARGET_NAME)"; 476 | WRAPPER_EXTENSION = app; 477 | }; 478 | name = Debug; 479 | }; 480 | B983CA9317C39D5200CA9F48 /* Release */ = { 481 | isa = XCBuildConfiguration; 482 | baseConfigurationReference = 3B0F7F0E74644BC3B85020B9 /* Pods.xcconfig */; 483 | buildSettings = { 484 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 485 | GCC_PREFIX_HEADER = "HelloAPI/HelloAPI-Prefix.pch"; 486 | INFOPLIST_FILE = "HelloAPI/HelloAPI-Info.plist"; 487 | PRODUCT_NAME = "$(TARGET_NAME)"; 488 | WRAPPER_EXTENSION = app; 489 | }; 490 | name = Release; 491 | }; 492 | B983CA9517C39D5200CA9F48 /* Debug */ = { 493 | isa = XCBuildConfiguration; 494 | buildSettings = { 495 | BUNDLE_LOADER = "$(BUILT_PRODUCTS_DIR)/HelloAPI.app/HelloAPI"; 496 | FRAMEWORK_SEARCH_PATHS = ( 497 | "\"$(SDKROOT)/Developer/Library/Frameworks\"", 498 | "\"$(DEVELOPER_LIBRARY_DIR)/Frameworks\"", 499 | ); 500 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 501 | GCC_PREFIX_HEADER = "HelloAPI/HelloAPI-Prefix.pch"; 502 | INFOPLIST_FILE = "HelloAPITests/HelloAPITests-Info.plist"; 503 | PRODUCT_NAME = "$(TARGET_NAME)"; 504 | TEST_HOST = "$(BUNDLE_LOADER)"; 505 | WRAPPER_EXTENSION = octest; 506 | }; 507 | name = Debug; 508 | }; 509 | B983CA9617C39D5200CA9F48 /* Release */ = { 510 | isa = XCBuildConfiguration; 511 | buildSettings = { 512 | BUNDLE_LOADER = "$(BUILT_PRODUCTS_DIR)/HelloAPI.app/HelloAPI"; 513 | FRAMEWORK_SEARCH_PATHS = ( 514 | "\"$(SDKROOT)/Developer/Library/Frameworks\"", 515 | "\"$(DEVELOPER_LIBRARY_DIR)/Frameworks\"", 516 | ); 517 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 518 | GCC_PREFIX_HEADER = "HelloAPI/HelloAPI-Prefix.pch"; 519 | INFOPLIST_FILE = "HelloAPITests/HelloAPITests-Info.plist"; 520 | PRODUCT_NAME = "$(TARGET_NAME)"; 521 | TEST_HOST = "$(BUNDLE_LOADER)"; 522 | WRAPPER_EXTENSION = octest; 523 | }; 524 | name = Release; 525 | }; 526 | /* End XCBuildConfiguration section */ 527 | 528 | /* Begin XCConfigurationList section */ 529 | B983CA4817C39D5100CA9F48 /* Build configuration list for PBXProject "HelloAPI" */ = { 530 | isa = XCConfigurationList; 531 | buildConfigurations = ( 532 | B983CA8F17C39D5200CA9F48 /* Debug */, 533 | B983CA9017C39D5200CA9F48 /* Release */, 534 | ); 535 | defaultConfigurationIsVisible = 0; 536 | defaultConfigurationName = Release; 537 | }; 538 | B983CA9117C39D5200CA9F48 /* Build configuration list for PBXNativeTarget "HelloAPI" */ = { 539 | isa = XCConfigurationList; 540 | buildConfigurations = ( 541 | B983CA9217C39D5200CA9F48 /* Debug */, 542 | B983CA9317C39D5200CA9F48 /* Release */, 543 | ); 544 | defaultConfigurationIsVisible = 0; 545 | defaultConfigurationName = Release; 546 | }; 547 | B983CA9417C39D5200CA9F48 /* Build configuration list for PBXNativeTarget "HelloAPITests" */ = { 548 | isa = XCConfigurationList; 549 | buildConfigurations = ( 550 | B983CA9517C39D5200CA9F48 /* Debug */, 551 | B983CA9617C39D5200CA9F48 /* Release */, 552 | ); 553 | defaultConfigurationIsVisible = 0; 554 | defaultConfigurationName = Release; 555 | }; 556 | /* End XCConfigurationList section */ 557 | }; 558 | rootObject = B983CA4517C39D5100CA9F48 /* Project object */; 559 | } 560 | -------------------------------------------------------------------------------- /ios/HelloAPI.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /ios/HelloAPI.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ios/HelloAPI/CTAppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // CTAppDelegate.h 3 | // HelloAPI 4 | // 5 | // Created by Leonard Ehrenfried on 8/20/13. 6 | // Copyright (c) 2013 Commercetools. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "CTMasterViewController.h" 11 | 12 | @interface CTAppDelegate : UIResponder 13 | 14 | @property (strong, nonatomic) UIWindow *window; 15 | 16 | @property (strong, nonatomic) UINavigationController *navigationController; 17 | 18 | @property (strong, nonatomic) UISplitViewController *splitViewController; 19 | 20 | @property (strong, nonatomic) CTMasterViewController *masterViewController; 21 | 22 | @end 23 | -------------------------------------------------------------------------------- /ios/HelloAPI/CTAppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // CTAppDelegate.m 3 | // HelloAPI 4 | // 5 | // Created by Leonard Ehrenfried on 8/20/13. 6 | // Copyright (c) 2013 Commercetools. All rights reserved. 7 | // 8 | 9 | #import "CTAppDelegate.h" 10 | 11 | #import "CTMasterViewController.h" 12 | 13 | #import "CTDetailViewController.h" 14 | 15 | #import 16 | #import 17 | 18 | 19 | @implementation CTAppDelegate 20 | 21 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 22 | { 23 | self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; 24 | 25 | // Override point for customization after application launch. 26 | if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone) { 27 | CTMasterViewController *masterViewController = [[CTMasterViewController alloc] initWithNibName:@"CTMasterViewController_iPhone" bundle:nil]; 28 | self.masterViewController = masterViewController; 29 | self.navigationController = [[UINavigationController alloc] initWithRootViewController:masterViewController]; 30 | self.window.rootViewController = self.navigationController; 31 | } else { 32 | CTMasterViewController *masterViewController = [[CTMasterViewController alloc] initWithNibName:@"CTMasterViewController_iPad" bundle:nil]; 33 | self.masterViewController = masterViewController; 34 | UINavigationController *masterNavigationController = [[UINavigationController alloc] initWithRootViewController:masterViewController]; 35 | 36 | CTDetailViewController *detailViewController = [[CTDetailViewController alloc] initWithNibName:@"CTDetailViewController_iPad" bundle:nil]; 37 | UINavigationController *detailNavigationController = [[UINavigationController alloc] initWithRootViewController:detailViewController]; 38 | 39 | masterViewController.detailViewController = detailViewController; 40 | 41 | self.splitViewController = [[UISplitViewController alloc] init]; 42 | self.splitViewController.delegate = detailViewController; 43 | self.splitViewController.viewControllers = @[masterNavigationController, detailNavigationController]; 44 | 45 | self.window.rootViewController = self.splitViewController; 46 | } 47 | 48 | NSString *path = [[NSBundle mainBundle] pathForResource:@"project" ofType:@"plist"]; 49 | NSDictionary *settings = [[NSDictionary alloc] initWithContentsOfFile:path]; 50 | NSString *projectKey = [settings objectForKey:@"projectKey"]; 51 | NSString *clientId = [settings objectForKey:@"clientId"]; 52 | NSString *clientSecret = [settings objectForKey:@"clientSecret"]; 53 | 54 | [self fetchAuthorization:projectKey clientId:clientId clientSecret:clientSecret]; 55 | [self.window makeKeyAndVisible]; 56 | return YES; 57 | } 58 | 59 | - (void)fetchAuthorization:(NSString *)projectKey clientId:(NSString *)clientId clientSecret:(NSString *)clientSecret 60 | { 61 | NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:@"https://auth.sphere.io/oauth/token"]]; 62 | request.HTTPMethod = @"POST"; 63 | [request setValue:@"application/x-www-form-urlencoded" forHTTPHeaderField:@"Content-Type"]; 64 | 65 | NSString *auth = [NSString stringWithFormat:@"%@:%@", clientId, clientSecret]; 66 | NSString *header = [NSString stringWithFormat:@"Basic %@", [auth base64String]]; 67 | [request setValue:header forHTTPHeaderField:@"Authorization"]; 68 | 69 | NSString *body = [NSString stringWithFormat:@"grant_type=client_credentials&scope=manage_project:%@", projectKey]; 70 | request.HTTPBody = [body dataUsingEncoding:NSUTF8StringEncoding]; 71 | 72 | AFJSONRequestOperation *operation = 73 | [AFJSONRequestOperation JSONRequestOperationWithRequest:request 74 | success:^(NSURLRequest *request, NSHTTPURLResponse *response, id json) { 75 | NSDictionary *dict = (NSDictionary*) json; 76 | [self fetchProducts:projectKey token:[dict objectForKey:@"access_token"]]; 77 | } 78 | failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error, id JSON) { 79 | UIAlertView *av = [[UIAlertView alloc] initWithTitle:@"Authenticateion error" 80 | message:[NSString stringWithFormat:@"%@",error] 81 | delegate:nil 82 | cancelButtonTitle:@"OK" otherButtonTitles:nil]; 83 | [av show]; 84 | }]; 85 | 86 | [operation start]; 87 | } 88 | 89 | - (void)fetchProducts:(NSString *)projectKey token:(NSString *)token 90 | { 91 | NSString * url = [NSString stringWithFormat: @"https://api.sphere.io/%@/product-projections", projectKey]; 92 | NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:url]]; 93 | 94 | NSString *header = [NSString stringWithFormat:@"Bearer %@", token]; 95 | [request setValue:header forHTTPHeaderField:@"Authorization"]; 96 | 97 | AFJSONRequestOperation *operation = 98 | [AFJSONRequestOperation JSONRequestOperationWithRequest:request 99 | success:^(NSURLRequest *request, NSHTTPURLResponse *response, id json) { 100 | NSDictionary *dict = (NSDictionary*) json; 101 | NSArray *products = [dict objectForKey:@"results"]; 102 | self.masterViewController.products = products; 103 | [self.masterViewController.tableView reloadData]; 104 | } 105 | failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error, id JSON) { 106 | UIAlertView *av = [[UIAlertView alloc] initWithTitle:@"Error fetching products" 107 | message:[NSString stringWithFormat:@"%@",error] 108 | delegate:nil 109 | cancelButtonTitle:@"OK" otherButtonTitles:nil]; 110 | [av show]; 111 | }]; 112 | 113 | [operation start]; 114 | } 115 | 116 | 117 | - (void)applicationWillResignActive:(UIApplication *)application 118 | { 119 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. 120 | // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game. 121 | } 122 | 123 | - (void)applicationDidEnterBackground:(UIApplication *)application 124 | { 125 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. 126 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 127 | } 128 | 129 | - (void)applicationWillEnterForeground:(UIApplication *)application 130 | { 131 | // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background. 132 | } 133 | 134 | - (void)applicationDidBecomeActive:(UIApplication *)application 135 | { 136 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. 137 | } 138 | 139 | - (void)applicationWillTerminate:(UIApplication *)application 140 | { 141 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 142 | } 143 | 144 | @end 145 | -------------------------------------------------------------------------------- /ios/HelloAPI/CTDetailViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // CTDetailViewController.h 3 | // HelloAPI 4 | // 5 | // Created by Leonard Ehrenfried on 8/20/13. 6 | // Copyright (c) 2013 Commercetools. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface CTDetailViewController : UIViewController 12 | 13 | @property (strong, nonatomic) NSDictionary *detailItem; 14 | 15 | @property (weak, nonatomic) IBOutlet UILabel *detailDescriptionLabel; 16 | @end 17 | -------------------------------------------------------------------------------- /ios/HelloAPI/CTDetailViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // CTDetailViewController.m 3 | // HelloAPI 4 | // 5 | // Created by Leonard Ehrenfried on 8/20/13. 6 | // Copyright (c) 2013 Commercetools. All rights reserved. 7 | // 8 | 9 | #import "CTDetailViewController.h" 10 | 11 | @interface CTDetailViewController () 12 | @property (strong, nonatomic) UIPopoverController *masterPopoverController; 13 | - (void)configureView; 14 | @end 15 | 16 | @implementation CTDetailViewController 17 | 18 | #pragma mark - Managing the detail item 19 | 20 | - (void)setDetailItem:(id)newDetailItem 21 | { 22 | if (_detailItem != newDetailItem) { 23 | _detailItem = newDetailItem; 24 | 25 | // Update the view. 26 | [self configureView]; 27 | } 28 | 29 | if (self.masterPopoverController != nil) { 30 | [self.masterPopoverController dismissPopoverAnimated:YES]; 31 | } 32 | } 33 | 34 | - (void)configureView 35 | { 36 | // Update the user interface for the detail item. 37 | 38 | if (self.detailItem) { 39 | self.detailDescriptionLabel.text = [self.detailItem description]; 40 | } 41 | } 42 | 43 | - (void)viewDidLoad 44 | { 45 | [super viewDidLoad]; 46 | // Do any additional setup after loading the view, typically from a nib. 47 | [self configureView]; 48 | } 49 | 50 | - (void)didReceiveMemoryWarning 51 | { 52 | [super didReceiveMemoryWarning]; 53 | // Dispose of any resources that can be recreated. 54 | } 55 | 56 | - (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil 57 | { 58 | self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]; 59 | if (self) { 60 | self.title = NSLocalizedString(@"Detail", @"Detail"); 61 | } 62 | return self; 63 | } 64 | 65 | #pragma mark - Split view 66 | 67 | - (void)splitViewController:(UISplitViewController *)splitController willHideViewController:(UIViewController *)viewController withBarButtonItem:(UIBarButtonItem *)barButtonItem forPopoverController:(UIPopoverController *)popoverController 68 | { 69 | barButtonItem.title = NSLocalizedString(@"Master", @"Master"); 70 | [self.navigationItem setLeftBarButtonItem:barButtonItem animated:YES]; 71 | self.masterPopoverController = popoverController; 72 | } 73 | 74 | - (void)splitViewController:(UISplitViewController *)splitController willShowViewController:(UIViewController *)viewController invalidatingBarButtonItem:(UIBarButtonItem *)barButtonItem 75 | { 76 | // Called when the view is shown again in the split view, invalidating the button and popover controller. 77 | [self.navigationItem setLeftBarButtonItem:nil animated:YES]; 78 | self.masterPopoverController = nil; 79 | } 80 | 81 | @end 82 | -------------------------------------------------------------------------------- /ios/HelloAPI/CTMasterViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // CTMasterViewController.h 3 | // HelloAPI 4 | // 5 | // Created by Leonard Ehrenfried on 8/20/13. 6 | // Copyright (c) 2013 Commercetools. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @class CTDetailViewController; 12 | 13 | @interface CTMasterViewController : UITableViewController 14 | 15 | @property (strong, nonatomic) CTDetailViewController *detailViewController; 16 | 17 | @property (strong, nonatomic) NSArray *products; 18 | 19 | @end 20 | -------------------------------------------------------------------------------- /ios/HelloAPI/CTMasterViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // CTMasterViewController.m 3 | // HelloAPI 4 | // 5 | // Created by Leonard Ehrenfried on 8/20/13. 6 | // Copyright (c) 2013 Commercetools. All rights reserved. 7 | // 8 | 9 | #import "CTMasterViewController.h" 10 | 11 | #import "CTDetailViewController.h" 12 | 13 | @interface CTMasterViewController () { 14 | NSMutableDictionary *_imageCache; 15 | } 16 | @end 17 | 18 | @implementation CTMasterViewController 19 | 20 | - (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil 21 | { 22 | self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]; 23 | if (self) { 24 | _imageCache = [NSMutableDictionary dictionary]; 25 | self.title = NSLocalizedString(@"Products", @"Products"); 26 | if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad) { 27 | self.clearsSelectionOnViewWillAppear = NO; 28 | self.contentSizeForViewInPopover = CGSizeMake(320.0, 600.0); 29 | } 30 | } 31 | return self; 32 | } 33 | 34 | - (void)viewDidLoad 35 | { 36 | [super viewDidLoad]; 37 | // Do any additional setup after loading the view, typically from a nib. 38 | self.navigationItem.leftBarButtonItem = self.editButtonItem; 39 | 40 | UIBarButtonItem *addButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemAdd target:self action:@selector(insertNewObject:)]; 41 | self.navigationItem.rightBarButtonItem = addButton; 42 | } 43 | 44 | - (void)didReceiveMemoryWarning 45 | { 46 | [super didReceiveMemoryWarning]; 47 | // Dispose of any resources that can be recreated. 48 | } 49 | 50 | - (void)insertNewObject:(id)sender 51 | { 52 | NSIndexPath *indexPath = [NSIndexPath indexPathForRow:0 inSection:0]; 53 | [self.tableView insertRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationAutomatic]; 54 | } 55 | 56 | #pragma mark - Table View 57 | 58 | - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView 59 | { 60 | return 1; 61 | } 62 | 63 | - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section 64 | { 65 | if (self.products){ 66 | return self.products.count; 67 | } 68 | else{ 69 | return 0; 70 | } 71 | 72 | } 73 | 74 | // Customize the appearance of table view cells. 75 | - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath 76 | { 77 | static NSString *CellIdentifier = @"Cell"; 78 | 79 | UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier]; 80 | if (cell == nil) { 81 | cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier]; 82 | if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone) { 83 | cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator; 84 | } 85 | } 86 | 87 | NSMutableDictionary *product = [[self.products objectAtIndex:indexPath.row] mutableCopy]; 88 | NSDictionary *names = [product objectForKey:@"name"]; 89 | cell.textLabel.text = [names objectForKey:@"en"]; 90 | 91 | NSString *image = [[[[product objectForKey:@"masterVariant"] objectForKey:@"images"] objectAtIndex:0] objectForKey:@"url"]; 92 | NSString *url = [image stringByReplacingOccurrencesOfString:@".jpg" withString:@"-thumb.jpg"]; 93 | NSString *uuid = [product objectForKey:@"id"]; 94 | 95 | if (image){ 96 | UIImage *image = [_imageCache objectForKey:uuid]; 97 | 98 | if(image){ 99 | cell.imageView.image = image; 100 | } 101 | else{ 102 | dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ 103 | NSData *data = [NSData dataWithContentsOfURL:[NSURL URLWithString:url]]; 104 | dispatch_async(dispatch_get_main_queue(), ^{ 105 | [_imageCache setObject:[UIImage imageWithData:data] forKey:uuid]; 106 | [tableView reloadRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationNone]; 107 | }); 108 | }); 109 | } 110 | } 111 | return cell; 112 | } 113 | 114 | - (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath 115 | { 116 | // Return NO if you do not want the specified item to be editable. 117 | return NO; 118 | } 119 | 120 | - (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath 121 | { 122 | if (editingStyle == UITableViewCellEditingStyleDelete) { 123 | [tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationFade]; 124 | } else if (editingStyle == UITableViewCellEditingStyleInsert) { 125 | // Create a new instance of the appropriate class, insert it into the array, and add a new row to the table view. 126 | } 127 | } 128 | 129 | /* 130 | // Override to support rearranging the table view. 131 | - (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)fromIndexPath toIndexPath:(NSIndexPath *)toIndexPath 132 | { 133 | } 134 | */ 135 | 136 | /* 137 | // Override to support conditional rearranging of the table view. 138 | - (BOOL)tableView:(UITableView *)tableView canMoveRowAtIndexPath:(NSIndexPath *)indexPath 139 | { 140 | // Return NO if you do not want the item to be re-orderable. 141 | return YES; 142 | } 143 | */ 144 | 145 | - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath 146 | { 147 | NSDictionary *object = self.products[indexPath.row]; 148 | if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone) { 149 | if (!self.detailViewController) { 150 | self.detailViewController = [[CTDetailViewController alloc] initWithNibName:@"CTDetailViewController_iPhone" bundle:nil]; 151 | } 152 | self.detailViewController.detailItem = object; 153 | [self.navigationController pushViewController:self.detailViewController animated:YES]; 154 | } else { 155 | self.detailViewController.detailItem = object; 156 | } 157 | } 158 | 159 | @end 160 | -------------------------------------------------------------------------------- /ios/HelloAPI/Default-568h@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sphereio/sphere-hello-api/48f85e4f97fd2facaf59c6a481ed8baaa07d4a4e/ios/HelloAPI/Default-568h@2x.png -------------------------------------------------------------------------------- /ios/HelloAPI/Default.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sphereio/sphere-hello-api/48f85e4f97fd2facaf59c6a481ed8baaa07d4a4e/ios/HelloAPI/Default.png -------------------------------------------------------------------------------- /ios/HelloAPI/Default@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sphereio/sphere-hello-api/48f85e4f97fd2facaf59c6a481ed8baaa07d4a4e/ios/HelloAPI/Default@2x.png -------------------------------------------------------------------------------- /ios/HelloAPI/HelloAPI-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleDisplayName 8 | ${PRODUCT_NAME} 9 | CFBundleExecutable 10 | ${EXECUTABLE_NAME} 11 | CFBundleIdentifier 12 | io.sphere.${PRODUCT_NAME:rfc1034identifier} 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | ${PRODUCT_NAME} 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | 1.0 21 | CFBundleSignature 22 | ???? 23 | CFBundleVersion 24 | 1.0 25 | LSRequiresIPhoneOS 26 | 27 | UIRequiredDeviceCapabilities 28 | 29 | armv7 30 | 31 | UIStatusBarTintParameters 32 | 33 | UINavigationBar 34 | 35 | Style 36 | UIBarStyleDefault 37 | Translucent 38 | 39 | 40 | 41 | UISupportedInterfaceOrientations 42 | 43 | UIInterfaceOrientationPortrait 44 | UIInterfaceOrientationLandscapeLeft 45 | UIInterfaceOrientationLandscapeRight 46 | 47 | UISupportedInterfaceOrientations~ipad 48 | 49 | UIInterfaceOrientationPortrait 50 | UIInterfaceOrientationPortraitUpsideDown 51 | UIInterfaceOrientationLandscapeLeft 52 | UIInterfaceOrientationLandscapeRight 53 | 54 | 55 | 56 | -------------------------------------------------------------------------------- /ios/HelloAPI/HelloAPI-Prefix.pch: -------------------------------------------------------------------------------- 1 | // 2 | // Prefix header for all source files of the 'HelloAPI' target in the 'HelloAPI' project 3 | // 4 | 5 | #import 6 | 7 | #ifndef __IPHONE_4_0 8 | #warning "This project uses features only available in iOS SDK 4.0 and later." 9 | #endif 10 | 11 | #ifdef __OBJC__ 12 | #import 13 | #import 14 | #endif 15 | -------------------------------------------------------------------------------- /ios/HelloAPI/en.lproj/CTDetailViewController_iPad.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 1536 5 | 12A206j 6 | 2519 7 | 1172.1 8 | 613.00 9 | 10 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 11 | 1856 12 | 13 | 14 | IBNSLayoutConstraint 15 | IBProxyObject 16 | IBUILabel 17 | IBUIView 18 | 19 | 20 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 21 | 22 | 23 | PluginDependencyRecalculationVersion 24 | 25 | 26 | 27 | 28 | IBFilesOwner 29 | IBIPadFramework 30 | 31 | 32 | IBFirstResponder 33 | IBIPadFramework 34 | 35 | 36 | 37 | 274 38 | 39 | 40 | 41 | 298 42 | {{20, 495}, {728, 18}} 43 | 44 | 45 | 46 | 3 47 | MQA 48 | 49 | YES 50 | NO 51 | IBIPadFramework 52 | 53 | 1 54 | 10 55 | Detail view content goes here 56 | 57 | 1 58 | MCAwIDAAA 59 | 60 | 1 61 | 62 | 1 63 | 4 64 | 65 | 66 | Helvetica 67 | 14 68 | 16 69 | 70 | 71 | 72 | {{0, 20}, {768, 1004}} 73 | 74 | 75 | 76 | NO 77 | 78 | 2 79 | 80 | IBIPadFramework 81 | 82 | 83 | 84 | 85 | 86 | 87 | view 88 | 89 | 90 | 91 | 12 92 | 93 | 94 | 95 | 96 | 97 | 0 98 | 99 | 100 | 101 | 102 | 103 | -1 104 | 105 | 106 | File's Owner 107 | 108 | 109 | -2 110 | 111 | 112 | 113 | 114 | 8 115 | 116 | 117 | 118 | 119 | 10 120 | 0 121 | 122 | 10 123 | 1 124 | 125 | 0.0 126 | 127 | 1000 128 | 129 | 5 130 | 22 131 | 2 132 | 133 | 134 | 135 | 6 136 | 0 137 | 138 | 6 139 | 1 140 | 141 | 20 142 | 143 | 1000 144 | 145 | 8 146 | 29 147 | 3 148 | 149 | 150 | 151 | 5 152 | 0 153 | 154 | 5 155 | 1 156 | 157 | 20 158 | 159 | 1000 160 | 161 | 8 162 | 29 163 | 3 164 | 165 | 166 | 167 | 168 | 169 | 170 | 81 171 | 172 | 173 | 174 | 175 | 176 | 94 177 | 178 | 179 | 180 | 181 | 97 182 | 183 | 184 | 185 | 186 | 98 187 | 188 | 189 | 190 | 191 | 192 | 193 | CTDetailViewController 194 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 195 | UIResponder 196 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 197 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 198 | 199 | 200 | 201 | 202 | 203 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 204 | 205 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 206 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 207 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 208 | 209 | 210 | 211 | 212 | 213 | 98 214 | 215 | 216 | 0 217 | IBIPadFramework 218 | YES 219 | 3 220 | YES 221 | 1856 222 | 223 | 224 | -------------------------------------------------------------------------------- /ios/HelloAPI/en.lproj/CTDetailViewController_iPhone.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 1536 5 | 12A269 6 | 2835 7 | 1187 8 | 624.00 9 | 10 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 11 | 1919 12 | 13 | 14 | IBNSLayoutConstraint 15 | IBProxyObject 16 | IBUILabel 17 | IBUIView 18 | 19 | 20 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 21 | 22 | 23 | PluginDependencyRecalculationVersion 24 | 25 | 26 | 27 | 28 | IBFilesOwner 29 | IBCocoaTouchFramework 30 | 31 | 32 | IBFirstResponder 33 | IBCocoaTouchFramework 34 | 35 | 36 | 37 | 274 38 | 39 | 40 | 41 | 298 42 | {{20, 265}, {280, 18}} 43 | 44 | 45 | 46 | 47 | 3 48 | MQA 49 | 50 | YES 51 | NO 52 | IBCocoaTouchFramework 53 | Detail view content goes here 54 | 55 | 1 56 | MCAwIDAAA 57 | darkTextColor 58 | 59 | 60 | 1 61 | 10 62 | 1 63 | 64 | 1 65 | 4 66 | 67 | 68 | Helvetica 69 | 14 70 | 16 71 | 72 | 73 | 74 | {{0, 20}, {320, 548}} 75 | 76 | 77 | 78 | 79 | 3 80 | MQA 81 | 82 | 2 83 | 84 | 85 | 86 | 87 | IBUIScreenMetrics 88 | 89 | YES 90 | 91 | 92 | 93 | 94 | 95 | {320, 568} 96 | {568, 320} 97 | 98 | 99 | IBCocoaTouchFramework 100 | Retina 4 Full Screen 101 | 2 102 | 103 | IBCocoaTouchFramework 104 | 105 | 106 | 107 | 108 | 109 | 110 | view 111 | 112 | 113 | 114 | 3 115 | 116 | 117 | 118 | detailDescriptionLabel 119 | 120 | 121 | 122 | 6 123 | 124 | 125 | 126 | 127 | 128 | 0 129 | 130 | 131 | 132 | 133 | 134 | 1 135 | 136 | 137 | 138 | 139 | 10 140 | 0 141 | 142 | 10 143 | 1 144 | 145 | 0.0 146 | 147 | 1000 148 | 149 | 5 150 | 22 151 | 2 152 | 153 | 154 | 155 | 6 156 | 0 157 | 158 | 6 159 | 1 160 | 161 | 20 162 | 163 | 1000 164 | 165 | 8 166 | 29 167 | 3 168 | 169 | 170 | 171 | 5 172 | 0 173 | 174 | 5 175 | 1 176 | 177 | 20 178 | 179 | 1000 180 | 181 | 8 182 | 29 183 | 3 184 | 185 | 186 | 187 | 188 | 189 | 190 | -1 191 | 192 | 193 | File's Owner 194 | 195 | 196 | -2 197 | 198 | 199 | 200 | 201 | 4 202 | 203 | 204 | 205 | 206 | 7 207 | 208 | 209 | 210 | 211 | 9 212 | 213 | 214 | 215 | 216 | 11 217 | 218 | 219 | 220 | 221 | 222 | 223 | CTDetailViewController 224 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 225 | UIResponder 226 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 227 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 228 | 229 | 230 | 231 | 232 | 233 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 234 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 235 | 236 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 237 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 238 | 239 | 240 | 241 | 242 | 243 | 11 244 | 245 | 246 | 0 247 | IBCocoaTouchFramework 248 | YES 249 | 3 250 | YES 251 | 1919 252 | 253 | 254 | -------------------------------------------------------------------------------- /ios/HelloAPI/en.lproj/CTMasterViewController_iPad.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 1536 5 | 12A206j 6 | 2519 7 | 1172.1 8 | 613.00 9 | 10 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 11 | 1856 12 | 13 | 14 | IBProxyObject 15 | IBUITableView 16 | 17 | 18 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 19 | 20 | 21 | PluginDependencyRecalculationVersion 22 | 23 | 24 | 25 | 26 | IBFilesOwner 27 | IBIPadFramework 28 | 29 | 30 | IBFirstResponder 31 | IBIPadFramework 32 | 33 | 34 | 35 | 274 36 | {{0, 20}, {320, 832}} 37 | 38 | 39 | 40 | 3 41 | MQA 42 | 43 | YES 44 | 45 | 2 46 | 47 | 48 | IBUISplitViewMasterSimulatedSizeMetrics 49 | 50 | YES 51 | 52 | 53 | 54 | 55 | 56 | {320, 852} 57 | {320, 768} 58 | 59 | 60 | IBIPadFramework 61 | Master 62 | IBUISplitViewController 63 | 64 | IBUISplitViewControllerContentSizeLocation 65 | IBUISplitViewControllerContentSizeLocationMaster 66 | 67 | 68 | IBIPadFramework 69 | YES 70 | 1 71 | 0 72 | YES 73 | 44 74 | 22 75 | 22 76 | 77 | 78 | 79 | 80 | 81 | 82 | view 83 | 84 | 85 | 86 | 3 87 | 88 | 89 | 90 | dataSource 91 | 92 | 93 | 94 | 4 95 | 96 | 97 | 98 | delegate 99 | 100 | 101 | 102 | 5 103 | 104 | 105 | 106 | 107 | 108 | 0 109 | 110 | 111 | 112 | 113 | 114 | -1 115 | 116 | 117 | File's Owner 118 | 119 | 120 | -2 121 | 122 | 123 | 124 | 125 | 2 126 | 127 | 128 | 129 | 130 | 131 | 132 | CTMasterViewController 133 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 134 | UIResponder 135 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 136 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 137 | 138 | 139 | 140 | 141 | 142 | 5 143 | 144 | 145 | 0 146 | IBIPadFramework 147 | YES 148 | 3 149 | YES 150 | 1856 151 | 152 | 153 | -------------------------------------------------------------------------------- /ios/HelloAPI/en.lproj/CTMasterViewController_iPhone.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 1536 5 | 12A269 6 | 2835 7 | 1187 8 | 624.00 9 | 10 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 11 | 1919 12 | 13 | 14 | IBProxyObject 15 | IBUITableView 16 | 17 | 18 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 19 | 20 | 21 | PluginDependencyRecalculationVersion 22 | 23 | 24 | 25 | 26 | IBFilesOwner 27 | IBCocoaTouchFramework 28 | 29 | 30 | IBFirstResponder 31 | IBCocoaTouchFramework 32 | 33 | 34 | 35 | 274 36 | {{0, 20}, {320, 548}} 37 | 38 | 39 | 40 | 41 | 3 42 | MQA 43 | 44 | YES 45 | 46 | 47 | IBUIScreenMetrics 48 | 49 | YES 50 | 51 | 52 | 53 | 54 | 55 | {320, 568} 56 | {568, 320} 57 | 58 | 59 | IBCocoaTouchFramework 60 | Retina 4 Full Screen 61 | 2 62 | 63 | IBCocoaTouchFramework 64 | YES 65 | 1 66 | 0 67 | YES 68 | 44 69 | 22 70 | 22 71 | 72 | 73 | 74 | 75 | 76 | 77 | view 78 | 79 | 80 | 81 | 3 82 | 83 | 84 | 85 | dataSource 86 | 87 | 88 | 89 | 4 90 | 91 | 92 | 93 | delegate 94 | 95 | 96 | 97 | 5 98 | 99 | 100 | 101 | 102 | 103 | 0 104 | 105 | 106 | 107 | 108 | 109 | -1 110 | 111 | 112 | File's Owner 113 | 114 | 115 | -2 116 | 117 | 118 | 119 | 120 | 2 121 | 122 | 123 | 124 | 125 | 126 | 127 | CTMasterViewController 128 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 129 | UIResponder 130 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 131 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 132 | 133 | 134 | 135 | 136 | 137 | 5 138 | 139 | 140 | 0 141 | IBCocoaTouchFramework 142 | YES 143 | 3 144 | YES 145 | 1919 146 | 147 | 148 | -------------------------------------------------------------------------------- /ios/HelloAPI/en.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* Localized versions of Info.plist keys */ 2 | 3 | -------------------------------------------------------------------------------- /ios/HelloAPI/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // HelloAPI 4 | // 5 | // Created by Leonard Ehrenfried on 8/20/13. 6 | // Copyright (c) 2013 Commercetools. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | #import "CTAppDelegate.h" 12 | 13 | int main(int argc, char *argv[]) 14 | { 15 | @autoreleasepool { 16 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([CTAppDelegate class])); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /ios/HelloAPI/project.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | clientSecret 6 | 7 | clientId 8 | 9 | projectKey 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /ios/HelloAPITests/HelloAPITests-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | ${EXECUTABLE_NAME} 9 | CFBundleIdentifier 10 | io.sphere.${PRODUCT_NAME:rfc1034identifier} 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundlePackageType 14 | BNDL 15 | CFBundleShortVersionString 16 | 1.0 17 | CFBundleSignature 18 | ???? 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /ios/HelloAPITests/HelloAPITests.h: -------------------------------------------------------------------------------- 1 | // 2 | // HelloAPITests.h 3 | // HelloAPITests 4 | // 5 | // Created by Leonard Ehrenfried on 8/20/13. 6 | // Copyright (c) 2013 Commercetools. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface HelloAPITests : SenTestCase 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /ios/HelloAPITests/HelloAPITests.m: -------------------------------------------------------------------------------- 1 | // 2 | // HelloAPITests.m 3 | // HelloAPITests 4 | // 5 | // Created by Leonard Ehrenfried on 8/20/13. 6 | // Copyright (c) 2013 Commercetools. All rights reserved. 7 | // 8 | 9 | #import "HelloAPITests.h" 10 | 11 | @implementation HelloAPITests 12 | 13 | - (void)setUp 14 | { 15 | [super setUp]; 16 | 17 | // Set-up code here. 18 | } 19 | 20 | - (void)tearDown 21 | { 22 | // Tear-down code here. 23 | 24 | [super tearDown]; 25 | } 26 | 27 | - (void)testExample 28 | { 29 | STFail(@"Unit tests are not implemented yet in HelloAPITests"); 30 | } 31 | 32 | @end 33 | -------------------------------------------------------------------------------- /ios/HelloAPITests/en.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* Localized versions of Info.plist keys */ 2 | 3 | -------------------------------------------------------------------------------- /ios/Podfile: -------------------------------------------------------------------------------- 1 | platform :ios, '6.0' 2 | pod 'Base64', '~> 1.0.1' 3 | pod 'AFNetworking', '~> 1.3.1' 4 | -------------------------------------------------------------------------------- /ios/Podfile.lock: -------------------------------------------------------------------------------- 1 | PODS: 2 | - AFNetworking (1.3.2) 3 | - Base64 (1.0.1) 4 | 5 | DEPENDENCIES: 6 | - AFNetworking (~> 1.3.1) 7 | - Base64 (~> 1.0.1) 8 | 9 | SPEC CHECKSUMS: 10 | AFNetworking: 7f9bcd7c287a75476cd5c61e82fd3380e93e4c54 11 | Base64: eaac9f2088ba659c5db1db960576eb0f2969ebaf 12 | 13 | COCOAPODS: 0.23.0 14 | -------------------------------------------------------------------------------- /ios/README.md: -------------------------------------------------------------------------------- 1 | ###Sample iOS app 2 | 3 | _Fetches the list of products from your project and displays them in a 4 | UITableView_ 5 | 6 | ####Screenshots 7 | 8 | ![alt text](https://github.com/commercetools/sphere-hello-api/raw/master/ios/screenshot-iphone.png) 9 | ![alt text](https://github.com/commercetools/sphere-hello-api/raw/master/ios/screenshot-ipad.png) 10 | 11 | ####Getting it to run 12 | 13 | 1. `cd ios` 14 | 1. Install [Cocoapods](http://cocoapods.org/): `gem install cocoapods` 15 | 1. Install dependencies through cocoapods: `pod install` 16 | 1. Open the workspace that Cocoapods has created in XCode: `open HelloAPI.xcworkspace/` 17 | 1. Edit `HelloApi/project.plist` and insert your project key, client id and client secret (you can get these in the merchant center under Developers > API Clients) 18 | 1. Run the project in the simulator(⌘-R) 19 | -------------------------------------------------------------------------------- /ios/screenshot-ipad.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sphereio/sphere-hello-api/48f85e4f97fd2facaf59c6a481ed8baaa07d4a4e/ios/screenshot-ipad.png -------------------------------------------------------------------------------- /ios/screenshot-iphone.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sphereio/sphere-hello-api/48f85e4f97fd2facaf59c6a481ed8baaa07d4a4e/ios/screenshot-iphone.png -------------------------------------------------------------------------------- /java/README.md: -------------------------------------------------------------------------------- 1 | Java Hello on SPHERE.IO 2 | ======================= 3 | 4 | moved to https://github.com/sphereio/sphere-hello-api-java 5 | -------------------------------------------------------------------------------- /javascript/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | config.json 3 | token.js -------------------------------------------------------------------------------- /javascript/Gruntfile.coffee: -------------------------------------------------------------------------------- 1 | module.exports = (grunt)-> 2 | # project configuration 3 | grunt.initConfig 4 | # load package information 5 | pkg: grunt.file.readJSON 'package.json' 6 | 7 | coffee: 8 | default: 9 | src: "src/hello.coffee" 10 | dest: "src/hello.js" 11 | 12 | # watching for changes 13 | watch: 14 | default: 15 | files: ["Gruntfile.coffe", "src/*.coffee"] 16 | tasks: ["coffee"] 17 | 18 | connect: 19 | default: 20 | options: 21 | port: 3000 22 | base: "./" 23 | 24 | open: 25 | default: 26 | path: "http://localhost:<%= connect.default.options.port %>" 27 | 28 | shell: 29 | options: 30 | stdout: true 31 | stderr: true 32 | failOnError: true 33 | test: 34 | command: "casperjs test src/test.coffee --no-colors" 35 | 36 | # load plugins that provide the tasks defined in the config 37 | grunt.loadNpmTasks "grunt-contrib-coffee" 38 | grunt.loadNpmTasks "grunt-contrib-watch" 39 | grunt.loadNpmTasks "grunt-contrib-connect" 40 | grunt.loadNpmTasks "grunt-open" 41 | grunt.loadNpmTasks "grunt-shell" 42 | 43 | # register tasks 44 | grunt.registerTask "run", ["connect", "open", "watch"] 45 | grunt.registerTask "build", ["coffee"] 46 | grunt.registerTask "default", ["watch"] 47 | grunt.registerTask "test", ["build", "connect", "shell:test"] 48 | -------------------------------------------------------------------------------- /javascript/README.md: -------------------------------------------------------------------------------- 1 | ![SPHERE.IO icon](https://admin.sphere.io/assets/images/sphere_logo_rgb_long.png) 2 | 3 | # Javascript Hello API 4 | 5 | A Javascript example to authenticate your application to [SPHERE.IO](http://sphere.io) and get the products in your project. 6 | 7 | ## Get access token 8 | As CORS are not allowed to the Auth service, we get the `access_token` with a bash script, simply run 9 | 10 | ```bash 11 | $ ./bin/get_token --client_id "${CLIENT_ID}" --client_secret "${CLIENT_SECRET}" --project_key "${PROJECT_KEY}" 12 | ``` 13 | 14 | This will print the credentials into `token.js`, loaded then from HTML page. 15 | 16 | ## Run 17 | 18 | You can run a simple server which will open automatically the page 19 | ```bash 20 | $ grunt run 21 | ``` 22 | -------------------------------------------------------------------------------- /javascript/bin/get_token: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | var fs = require('fs') 4 | var path = require('path') 5 | var request = require('request') 6 | var argv = require('minimist')(process.argv.slice(2)) 7 | 8 | request({ 9 | uri: 'https://' + argv.client_id + ':' + argv.client_secret + '@auth.sphere.io/oauth/token', 10 | json: true, 11 | method: 'POST', 12 | body: 'grant_type=client_credentials&scope=manage_project:' + argv.project_key, 13 | headers: { 14 | 'Content-Type': 'application/x-www-form-urlencoded' 15 | } 16 | }, function(e, r, b) { 17 | if (e) { 18 | console.error(e) 19 | process.exit(1) 20 | } else { 21 | var data = 'var token = { project_key: \'' + argv.project_key + '\', access_token: \'' + b.access_token + '\' }' 22 | fs.writeFileSync(path.join(__dirname + '/../token.js'), data, {encoding: 'utf-8'}) 23 | console.log('Access token generated: ' + b.access_token); 24 | process.exit(0) 25 | } 26 | }) 27 | -------------------------------------------------------------------------------- /javascript/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 24 | 25 | 26 |

27 |

28 |   
29 | 


--------------------------------------------------------------------------------
/javascript/package.json:
--------------------------------------------------------------------------------
 1 | {
 2 |   "name": "sphere-hello-api-js",
 3 |   "description": "First steps to access the API of SPHERE.IO",
 4 |   "version": "0.1.0",
 5 |   "keywords": ["sphere.io", "api", "hello", "javascript", "js"],
 6 |   "author": {
 7 |     "name": "Nicola Molinari",
 8 |     "email": "nicola.molinari@commercetools.de"
 9 |   },
10 |   "private": false,
11 |   "devDependencies": {
12 |     "grunt": "0.4.x",
13 |     "grunt-contrib-coffee": "0.13.0",
14 |     "grunt-contrib-watch": "0.6.1",
15 |     "grunt-contrib-connect": "0.11.2",
16 |     "grunt-open": "0.2.4",
17 |     "grunt-shell": "0.7.0",
18 |     "minimist": "latest",
19 |     "request": "latest",
20 |     "underscore": "latest",
21 |     "underscore-mixins": "latest"
22 |   },
23 |   "engines": {
24 |     "node": "*"
25 |   },
26 |   "scripts": {
27 |     "run": "grunt run",
28 |     "build": "grunt build"
29 |   }
30 | }
31 | 


--------------------------------------------------------------------------------
/javascript/src/hello.coffee:
--------------------------------------------------------------------------------
 1 | (($, window) ->
 2 |   document = window.document
 3 | 
 4 |   class Hello
 5 |     constructor: (options) ->
 6 |       # we assume to have already an `access_token`
 7 |       @_options = options
 8 | 
 9 |     getProducts: (callback) ->
10 |       $.ajax
11 |         url: "https://api.sphere.io/#{@_options.project_key}/product-projections"
12 |         type: "GET"
13 |         headers:
14 |           "Authorization": "Bearer #{@_options.access_token}"
15 |         success: (data, textStatus, jqXHR) =>
16 |           callback(undefined, data)
17 |         error: (xhr, textStatus) => callback(xhr, undefined)
18 | 
19 |   window.Hello = Hello
20 | 
21 | )(jQuery, window)
22 | 


--------------------------------------------------------------------------------
/javascript/src/hello.js:
--------------------------------------------------------------------------------
 1 | (function() {
 2 |   (function($, window) {
 3 |     var Hello, document;
 4 |     document = window.document;
 5 |     Hello = (function() {
 6 |       function Hello(options) {
 7 |         this._options = options;
 8 |       }
 9 | 
10 |       Hello.prototype.getProducts = function(callback) {
11 |         return $.ajax({
12 |           url: "https://api.sphere.io/" + this._options.project_key + "/product-projections",
13 |           type: "GET",
14 |           headers: {
15 |             "Authorization": "Bearer " + this._options.access_token
16 |           },
17 |           success: (function(_this) {
18 |             return function(data, textStatus, jqXHR) {
19 |               return callback(void 0, data);
20 |             };
21 |           })(this),
22 |           error: (function(_this) {
23 |             return function(xhr, textStatus) {
24 |               return callback(xhr, void 0);
25 |             };
26 |           })(this)
27 |         });
28 |       };
29 | 
30 |       return Hello;
31 | 
32 |     })();
33 |     return window.Hello = Hello;
34 |   })(jQuery, window);
35 | 
36 | }).call(this);
37 | 


--------------------------------------------------------------------------------
/javascript/src/test.coffee:
--------------------------------------------------------------------------------
 1 | url = 'http://localhost:3000/'
 2 | 
 3 | casper.test.begin 'Should fetch product projections', (test) ->
 4 |   casper.start url, ->
 5 |     test.assertSelectorHasText '#title', 'Found 5 products'
 6 |   .run -> test.done()
 7 | 
 8 | # Note: if you see following warning it's nothing serious (see here http://stackoverflow.com/a/27083831)
 9 | #   Unsafe JavaScript attempt to access frame with URL about:blank from frame with URL
10 | 


--------------------------------------------------------------------------------
/kotlin/README.md:
--------------------------------------------------------------------------------
1 | see https://github.com/commercetools/commercetools-hello-api-kotlin-jvm-sdk
2 | 


--------------------------------------------------------------------------------
/nodejs/README.md:
--------------------------------------------------------------------------------
1 | See [sphere-hello-api-nodejs](https://github.com/sphereio/sphere-hello-api-nodejs)


--------------------------------------------------------------------------------
/php/README.md:
--------------------------------------------------------------------------------
1 | See [sphere-hello-api-php](https://github.com/sphereio/sphere-hello-api-php)


--------------------------------------------------------------------------------
/python2/README.md:
--------------------------------------------------------------------------------
 1 | Python Hello on SPHERE.IO
 2 | =======================
 3 | 
 4 | A Python example to authenticate your application to [SPHERE.IO](http://sphere.io) and get the number of products in your project.
 5 | 
 6 | ## Install dependencies
 7 | 
 8 | ```bash
 9 | $ pip install -r requirements.txt
10 | ```
11 | 
12 | This operation may needs admin rights.
13 | 
14 | ## Run
15 | 
16 | Add your project key, OAuth client ID and client secret to `config.py`.
17 | 
18 | ```bash
19 | $ ./hello-api
20 | ```
21 | 
22 | 


--------------------------------------------------------------------------------
/python2/config.py:
--------------------------------------------------------------------------------
1 | PROJECT_KEY = "my-project"
2 | CLIENT_ID = "CLIENT_ID"
3 | CLIENT_SECRET = "CLIENT_SECRET"
4 | 


--------------------------------------------------------------------------------
/python2/hello-api:
--------------------------------------------------------------------------------
 1 | #! /usr/bin/env python
 2 | 
 3 | import base64
 4 | import requests
 5 | import config
 6 | 
 7 | def login(client_id, client_secret, project_key):
 8 |     encoded = base64.b64encode("%s:%s" % (client_id, client_secret))
 9 |     headers = { 'Authorization' : "Basic %s" % encoded,
10 |                 'Content-Type'  : 'application/x-www-form-urlencoded' }
11 |     body = "grant_type=client_credentials&scope=manage_project:%s" % project_key
12 |     url = "https://auth.sphere.io/oauth/token"
13 |     r = requests.post(url, data=body, headers=headers)
14 |     if r.status_code is 200:
15 |         return r.json()
16 |     else:
17 |         raise Exception("Failed to get an access token. Are you sure you have added them to config.py?")
18 | 
19 | def list_products(auth, project_key):
20 |     headers = { "Authorization" : "Bearer %s" % auth["access_token"] }
21 |     url = "https://api.sphere.io/%s/product-projections" % project_key
22 |     r = requests.get(url, headers=headers)
23 |     products = r.json()
24 |     for i in products["results"]:
25 |         print i["name"]
26 | 
27 | auth = login(config.CLIENT_ID, config.CLIENT_SECRET, config.PROJECT_KEY)
28 | list_products(auth, config.PROJECT_KEY)
29 | 
30 | 


--------------------------------------------------------------------------------
/python2/requirements.txt:
--------------------------------------------------------------------------------
1 | requests==2.22.0
2 | 


--------------------------------------------------------------------------------
/python3/README.md:
--------------------------------------------------------------------------------
 1 | Python Hello on SPHERE.IO
 2 | =======================
 3 | 
 4 | A Python example to authenticate your application to [SPHERE.IO](http://sphere.io) and get the number of products in your project.
 5 | 
 6 | ## Install dependencies
 7 | 
 8 | ```bash
 9 | $ pip install -r requirements.txt
10 | ```
11 | 
12 | This operation may needs admin rights.
13 | 
14 | ## Run
15 | 
16 | Add your project key, OAuth client ID and client secret to `config.py`.
17 | 
18 | ```bash
19 | $ ./hello-api
20 | ```
21 | 
22 | 


--------------------------------------------------------------------------------
/python3/config.py:
--------------------------------------------------------------------------------
1 | PROJECT_KEY = "my-project"
2 | CLIENT_ID = "CLIENT_ID"
3 | CLIENT_SECRET = "CLIENT_SECRET"
4 | 


--------------------------------------------------------------------------------
/python3/hello-api:
--------------------------------------------------------------------------------
 1 | #! /usr/bin/env python3
 2 | 
 3 | import base64
 4 | import requests
 5 | import config
 6 | 
 7 | def login(client_id, client_secret, project_key):
 8 |     headers = { 'Content-Type' : 'application/x-www-form-urlencoded' }
 9 |     body = "grant_type=client_credentials&scope=manage_project:%s" % project_key
10 |     url = "https://auth.sphere.io/oauth/token"
11 |     auth = (client_id, client_secret)
12 |     r = requests.post(url, data=body, headers=headers, auth=auth)
13 |     if r.status_code is 200:
14 |         return r.json()
15 |     else:
16 |         raise Exception("Failed to get an access token. Are you sure you have added them to config.py?")
17 | 
18 | def list_products(auth, project_key):
19 |     headers = { "Authorization" : "Bearer %s" % auth["access_token"] }
20 |     url = "https://api.sphere.io/%s/product-projections" % project_key
21 |     r = requests.get(url, headers=headers)
22 |     products = r.json()
23 |     for i in products["results"]:
24 |         print(i["name"])
25 | 
26 | auth = login(config.CLIENT_ID, config.CLIENT_SECRET, config.PROJECT_KEY)
27 | list_products(auth, config.PROJECT_KEY)
28 | 
29 | 


--------------------------------------------------------------------------------
/python3/requirements.txt:
--------------------------------------------------------------------------------
1 | requests==2.22.0
2 | 


--------------------------------------------------------------------------------
/renovate.json:
--------------------------------------------------------------------------------
 1 | {
 2 |   "extends": [
 3 |     "config:base",
 4 |     ":preserveSemverRanges",
 5 |     ":automergeMinor",
 6 |     "group:allNonMajor",
 7 |     ":prHourlyLimitNone",
 8 |     ":prConcurrentLimitNone",
 9 |     ":automergeBranchMergeCommit",
10 |     ":enableVulnerabilityAlerts",
11 |     "schedule:monthly"
12 |   ],
13 |   "major": {
14 |     "enabled": false
15 |   }
16 | }
17 | 


--------------------------------------------------------------------------------
/ruby/.gitignore:
--------------------------------------------------------------------------------
1 | Gemfile.lock
2 | config.yaml
3 | 


--------------------------------------------------------------------------------
/ruby/Gemfile:
--------------------------------------------------------------------------------
1 | source 'https://rubygems.org'
2 | gem "excon", "~> 0.20.1"
3 | gem "json", "~> 1.7.7"
4 | 


--------------------------------------------------------------------------------
/ruby/README.md:
--------------------------------------------------------------------------------
 1 | Ruby Hello on SPHERE.IO
 2 | =======================
 3 | 
 4 | A Ruby example to authenticate your application to [SPHERE.IO](http://sphere.io) and get the number of products in your project.
 5 | 
 6 | ## Run
 7 | 
 8 | More infos on the small script, please run:
 9 | ```bash
10 | $ ./hello-api --help
11 | ```
12 | 
13 | To pass your credentials via configuration file, please adjust the `config.yaml` file.
14 | 


--------------------------------------------------------------------------------
/ruby/config.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | client_id: "cliend_id"
3 | client_secret: "client_secret"
4 | project_key: "project_key"
5 | 


--------------------------------------------------------------------------------
/ruby/hello-api:
--------------------------------------------------------------------------------
 1 | #!/usr/bin/env ruby
 2 | 
 3 | require 'yaml'
 4 | require 'optparse'
 5 | require 'base64'
 6 | require 'excon'
 7 | require 'json'
 8 | require_relative 'lib/login'
 9 | 
10 | def get_products(token, project_key)
11 |   headers = { 'Authorization' => "Bearer #{token}" }
12 |   res = Excon.get "https://api.sphere.io/#{project_key}/product-projections", :headers => headers
13 |   j = JSON.parse res.body
14 |   puts j['total']
15 | end
16 | 
17 | options = {}
18 | optparse = OptionParser.new do |opts|
19 |   opts.on '-c', '--client_id CLIENT_ID', "Client ID of your sphere project" do |c|
20 |     options['client_id'] = c
21 |   end
22 |   opts.on '-s', '--client_secret CLIENT_SECRET', "Client secret of your sphere project" do |c|
23 |     options['client_secret'] = c
24 |   end
25 |   opts.on '-p', '--project_key PROJEXT_KEY', "Key of your sphere project" do |c|
26 |     options['project_key'] = c
27 |   end
28 |   opts.on '-f', '--config_file YAML_FILE', "YAML file that contains the other 3 arguments" do |c|
29 |     options[:config_file] = c
30 |   end
31 |   opts.on '-h', '--help', 'Display this screen' do
32 |     puts opts
33 |     exit
34 |   end
35 | end
36 | optparse.parse!
37 | 
38 | if options[:config_file]
39 |   raise "Can't open config file '#{options[:config_file]}'." unless File.file? options[:config_file]
40 |   c = YAML.load IO.read options[:config_file]
41 |   options.merge! c
42 | end
43 | 
44 | token = SphereIO.login options['client_id'], options['client_secret'], options['project_key']
45 | get_products token, options['project_key']
46 | 


--------------------------------------------------------------------------------
/ruby/lib/login.rb:
--------------------------------------------------------------------------------
 1 | require 'base64'
 2 | require 'excon'
 3 | require 'json'
 4 | 
 5 | module SphereIO
 6 | 
 7 |   def self.login(client_id, client_secret, project_key)
 8 |     encoded = Base64.urlsafe_encode64 "#{client_id}:#{client_secret}"
 9 |     headers = { 'Authorization' => "Basic #{encoded}", 'Content-Type' => 'application/x-www-form-urlencoded' }
10 |     body = "grant_type=client_credentials&scope=manage_project:#{project_key}"
11 |     res = Excon.post 'https://auth.sphere.io/oauth/token', :headers => headers, :body => body
12 |     raise "Problems on getting access token from auth.sphere.io: #{res.body}" unless res.status == 200
13 |     JSON.parse(res.body)['access_token']
14 |   end
15 | 
16 | end
17 | 


--------------------------------------------------------------------------------
/rust/.gitignore:
--------------------------------------------------------------------------------
1 | target
2 | Cargo.lock
3 | .idea
4 | *.iml
5 | 


--------------------------------------------------------------------------------
/rust/Cargo.toml:
--------------------------------------------------------------------------------
 1 | [package]
 2 | name = "commercetools"
 3 | version = "0.1.0"
 4 | authors = ["Yann Simon "]
 5 | edition = "2018"
 6 | 
 7 | [dependencies]
 8 | reqwest = "0.9"
 9 | http = "0.1"
10 | chrono = "0.4"
11 | log = "0.4"
12 | failure = "0.1"
13 | failure_derive = "0.1"
14 | 
15 | serde = "1.0"
16 | serde_derive = "1.0"
17 | serde_json = "1.0"
18 | 
19 | [dev-dependencies]
20 | env_logger = "0.6"
21 | hyper = "0.10"
22 | 
23 | [dev-dependencies.clap]
24 | version = "2.9"
25 | default-features = false
26 | features = [ "suggestions", "color" ]
27 | 


--------------------------------------------------------------------------------
/rust/HACKING.md:
--------------------------------------------------------------------------------
 1 | 
 2 | 
 3 | ### Continuous testing:
 4 | 
 5 | Install [cargo watch](https://github.com/passcod/cargo-watch) 
 6 | 
 7 | ```
 8 | cargo install cargo-watch
 9 | ```
10 | 
11 | and then:
12 | 
13 | ```
14 | cargo watch test
15 | ```
16 | 


--------------------------------------------------------------------------------
/rust/README.md:
--------------------------------------------------------------------------------
  1 | # Minimal Rust project to access the [commercetools platform](http://dev.commercetools.com/) API.
  2 | 
  3 | This project contains:
  4 | 
  5 | - a mini-library `commercetools` that could evolve into a real SDK in the future
  6 | - examples using the mini-library
  7 | 
  8 | ## Sphere library
  9 | 
 10 | The `commercetools` library contains the module [`commercetools::auth`](/rust/src/auth.rs), used to retrieve an [access token](http://dev.commercetools.com/http-api-authorization.html) to use the API.
 11 | 
 12 | This library follows the Rust standard:
 13 | 
 14 | - unit tests are found next to the implementation.
 15 | - integration tests are found in ['/tests'](/rust/tests).
 16 | - code is formatted with [rustfmt](https://github.com/rust-lang-nursery/rustfmt).
 17 | 
 18 | ## Prerequisites
 19 | 
 20 | [Rust](https://www.rust-lang.org/) and [Cargo](https://crates.io/install) must be installed. We advise you to use [rustup](https://github.com/rust-lang-nursery/rustup.rs) to install them.
 21 | 
 22 | ## Hack
 23 | ### Run the tests
 24 | ```
 25 | cargo test
 26 | ```
 27 | 
 28 | ### Generate the documentation
 29 | ```
 30 | cargo doc
 31 | ```
 32 | The documentation is available in `target/doc/commercetools`.
 33 | 
 34 | ### Format the code
 35 | 
 36 | - Install [`rustfmt`](https://github.com/rust-lang/rustfmt) (once)
 37 | 
 38 |         rustup component add rustfmt
 39 | 
 40 | - Format the code with:
 41 | 
 42 |         cargo fmt
 43 | 
 44 | 
 45 | ### Lint
 46 | 
 47 | - Install [`clippy`](https://github.com/rust-lang/rust-clippy/) (once)
 48 | 
 49 |         rustup component add clippy
 50 | 
 51 | - Runs the linter
 52 | 
 53 |         cargo clippy
 54 | 
 55 | 
 56 | ## Example [fetch_products](/rust/examples/fetch_products.rs)
 57 | ### Run the example
 58 | 
 59 | Help:
 60 | ```
 61 | cargo run --example fetch_products -- --help
 62 | ```
 63 | 
 64 | Usage:
 65 | ```
 66 | cargo run --example fetch_products --   
 67 | ```
 68 | 
 69 | To output some logs, [configure the `RUST_LOG` environment variable](http://doc.rust-lang.org/log/env_logger/index.html)
 70 | 
 71 | Example: to enable all logs for the `auth` module:
 72 | ```
 73 | RUST_LOG=commercetools::auth cargo run --example fetch_products --   
 74 | ```
 75 | 
 76 | ### Build a release for this example
 77 | 
 78 | Create an executable from an example:
 79 | ```
 80 | cargo build --example fetch_products
 81 | ```
 82 | 
 83 | Run the executable
 84 | ```
 85 | ./target/debug/examples/fetch_products   
 86 | ```
 87 | 
 88 | ## Use the library from another Rust application
 89 | 
 90 | The `commercetools` library is not published to https://crates.io/ so you must link it locally.
 91 | 
 92 | Example of a `Cargo.toml`:
 93 | ```
 94 | [package]
 95 | name = "my-rust-app"
 96 | version = "0.1.0"
 97 | authors = ["My name "]
 98 | 
 99 | [dependencies]
100 | reqwest = "0.9"
101 | serde = "0.9"
102 | serde_derive = "0.9"
103 | serde_json = "0.9"
104 | 
105 | [dependencies.commercetools]
106 | path = ""
107 | ```
108 | 
109 | ## Technical choices
110 | ### Current version
111 | 
112 | The `commercetools` library uses:
113 | 
114 | - [reqwest](https://docs.rs/reqwest) as http client.
115 | - [serde_json](https://docs.serde.rs/serde_json/) as JSON encoding / decoding parser.
116 | - [log](https://doc.rust-lang.org/log) as logging facade.
117 | - [failure](https://docs.rs/failure) to create errors with stack traces.
118 | 
119 | ### Roadmap
120 | 
121 | - move from blocking IO to non-blocking IO. The next major version of [hyper](http://hyper.rs/hyper/master/hyper/client/index.html) will allow that.
122 | 


--------------------------------------------------------------------------------
/rust/examples/fetch_products.rs:
--------------------------------------------------------------------------------
  1 | #[macro_use]
  2 | extern crate serde_derive;
  3 | 
  4 | use clap::{App, Arg};
  5 | use commercetools::client::CtpClient;
  6 | use commercetools::region::Region;
  7 | use std::collections::HashMap;
  8 | use std::str::FromStr;
  9 | 
 10 | #[allow(non_snake_case)]
 11 | #[derive(Debug, Deserialize)]
 12 | pub struct Reference {
 13 |     pub typeId: String,
 14 |     pub id: String,
 15 | }
 16 | 
 17 | #[allow(non_snake_case)]
 18 | #[derive(Debug, Deserialize)]
 19 | pub struct ProductVariant {
 20 |     pub id: u64,
 21 |     pub sku: Option,
 22 | }
 23 | 
 24 | #[allow(non_snake_case)]
 25 | #[derive(Debug, Deserialize)]
 26 | pub struct ProductData {
 27 |     pub name: HashMap,
 28 |     pub categories: Vec,
 29 |     pub description: Option>,
 30 |     pub slug: HashMap,
 31 |     pub metaTitle: Option>,
 32 |     pub metaDescription: Option>,
 33 |     pub metaKeywords: Option>,
 34 |     pub masterVariant: ProductVariant,
 35 | }
 36 | 
 37 | #[allow(non_snake_case)]
 38 | #[derive(Debug, Deserialize)]
 39 | pub struct ProductCatalogData {
 40 |     pub published: bool,
 41 |     pub hasStagedChanges: bool,
 42 |     pub current: ProductData,
 43 |     pub staged: ProductData,
 44 | }
 45 | 
 46 | #[allow(non_snake_case)]
 47 | #[derive(Debug, Deserialize)]
 48 | pub struct Product {
 49 |     pub id: String,
 50 |     pub version: u64,
 51 |     pub createdAt: String,
 52 |     pub lastModifiedAt: String,
 53 |     pub masterData: ProductCatalogData,
 54 | }
 55 | 
 56 | #[allow(non_snake_case)]
 57 | #[derive(Debug, Deserialize)]
 58 | pub struct Review {
 59 |     pub id: String,
 60 |     pub version: u64,
 61 |     pub createdAt: String,
 62 |     pub lastModifiedAt: String,
 63 |     pub text: Option,
 64 | }
 65 | 
 66 | fn main() {
 67 |     env_logger::init();
 68 |     let matches = App::new("sphere")
 69 |         .version("1.0")
 70 |         .author("Yann Simon ")
 71 |         .args_from_usage(
 72 |             " 'project key' \n\
 73 |               'client ID' \n\
 74 |               'client secret' \n\
 75 |              --region=[Europe|NorthAmerica] 'region to use (default to Europe)'",
 76 |         )
 77 |         .arg(
 78 |             Arg::with_name("permissions")
 79 |                 .short("p")
 80 |                 .long("permission")
 81 |                 .help("permissions (default to manage_project)")
 82 |                 .multiple(true)
 83 |                 .takes_value(true),
 84 |         )
 85 |         .get_matches();
 86 | 
 87 |     let project_key = matches.value_of("PROJECT_KEY").unwrap();
 88 |     let client_id = matches.value_of("CLIENT_ID").unwrap();
 89 |     let client_secret = matches.value_of("CLIENT_SECRET").unwrap();
 90 |     let region = matches
 91 |         .value_of("region")
 92 |         .map(|s| Region::from_str(s).unwrap())
 93 |         .unwrap_or(Region::Europe);
 94 |     let permissions: Vec<&str> = if matches.is_present("permissions") {
 95 |         matches.values_of("permissions").unwrap().collect()
 96 |     } else {
 97 |         vec!["manage_project"]
 98 |     };
 99 | 
100 |     let mut ctp_client = CtpClient::new(®ion, project_key, client_id, client_secret)
101 |         .with_permissions(&permissions);
102 | 
103 |     // simple GET call
104 |     let mut products = ctp_client.get("/products?limit=1").unwrap();
105 |     println!("\nProducts: {}", products.body_as_string().unwrap());
106 | 
107 |     // paged result of products
108 |     let products2 = ctp_client.list::("products").unwrap();
109 |     println!(
110 |         "\nList of product ids: {:?}",
111 |         products2
112 |             .results
113 |             .iter()
114 |             .map(|p| &p.id)
115 |             .collect::>()
116 |     );
117 | 
118 |     println!("\nFirst product: {:?}", &products2.results.first());
119 | 
120 |     // read reviews
121 |     let mut reviews = ctp_client.get("/reviews?limit=1").unwrap();
122 |     println!("\nReviews: {}", reviews.body_as_string().unwrap());
123 | 
124 |     let create = permissions
125 |         .iter()
126 |         .any(|&p| p == "manage_project" || p == "manage_products");
127 |     if create {
128 |         // create and delete a review
129 |         let create_review = r#"
130 |         {
131 |           "text": "my review"
132 |         }
133 |         "#;
134 |         let mut review_call = ctp_client.post("/reviews", create_review).unwrap();
135 |         let review = review_call.body_as::().unwrap();
136 |         println!("\n[{}] New Review: {:?}", &review_call.status(), review);
137 | 
138 |         let url = format!("/reviews/{}?version={}", review.id, review.version);
139 |         let mut deleted_review = ctp_client.delete(&url).unwrap();
140 |         println!(
141 |             "\n[{}] Deleted Review: {:?}",
142 |             &deleted_review.status(),
143 |             deleted_review.body_as_string().unwrap()
144 |         );
145 |     }
146 | 
147 |     // read products IDs with a Graph QL query
148 |     let query = r#"
149 |     {
150 |       products {
151 |         results {
152 |           id
153 |         }
154 |       }
155 |     }
156 |     "#;
157 |     let mut graphql = ctp_client.graphql(query).unwrap();
158 |     println!("\nGraphQL: {}", graphql.body_as_string().unwrap());
159 | }
160 | 


--------------------------------------------------------------------------------
/rust/rustfmt.toml:
--------------------------------------------------------------------------------
1 | reorder_imports = true
2 | 


--------------------------------------------------------------------------------
/rust/src/auth.rs:
--------------------------------------------------------------------------------
  1 | use chrono::{DateTime, Duration, Utc};
  2 | 
  3 | use http::header::CONTENT_LENGTH;
  4 | use reqwest::{Client, StatusCode};
  5 | use serde_json;
  6 | use std::fmt;
  7 | use std::io::Read;
  8 | 
  9 | /// access token
 10 | #[derive(Debug, Clone)]
 11 | pub struct Token {
 12 |     pub bearer_token: Vec,
 13 |     expires_at: DateTime,
 14 | }
 15 | 
 16 | impl fmt::Display for Token {
 17 |     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
 18 |         let token = String::from_utf8(self.bearer_token.clone()).map_err(|e| {
 19 |             error!("{}", e);
 20 |             fmt::Error::default()
 21 |         })?;
 22 |         write!(
 23 |             f,
 24 |             "Token: access_token = {}, expires_at = {}",
 25 |             token, self.expires_at
 26 |         )
 27 |     }
 28 | }
 29 | 
 30 | impl Token {
 31 |     pub fn new(bearer_token: Vec, expires_in_s: i64) -> Token {
 32 |         let duration = Duration::seconds(expires_in_s);
 33 |         Token {
 34 |             bearer_token,
 35 |             expires_at: Utc::now() + duration,
 36 |         }
 37 |     }
 38 | 
 39 |     pub fn is_valid_with_margin(&self, now: DateTime, margin: Duration) -> bool {
 40 |         debug!(
 41 |             "check if now ({}) is valid for expiration date {} with a margin of {}",
 42 |             now, self.expires_at, margin
 43 |         );
 44 |         now + margin < self.expires_at
 45 |     }
 46 | 
 47 |     pub fn is_valid(&self) -> bool {
 48 |         self.is_valid_with_margin(Utc::now(), Duration::seconds(30))
 49 |     }
 50 | }
 51 | 
 52 | // internal data structure to read response from API
 53 | #[derive(Deserialize, Debug)]
 54 | struct TokenFromApi {
 55 |     access_token: String,
 56 |     expires_in: i64,
 57 | }
 58 | 
 59 | /// retrieve an [OAuth token](http://dev.commercetools.com/http-api-authorization.html)
 60 | /// for the commercetools API
 61 | pub fn retrieve_token(
 62 |     client: &Client,
 63 |     auth_url: &str,
 64 |     project_key: &str,
 65 |     client_id: &str,
 66 |     client_secret: &str,
 67 |     permissions: &[&str],
 68 | ) -> crate::Result {
 69 |     info!(
 70 |         "retrieving a new OAuth token from '{}' for project '{}' with client '{}'",
 71 |         auth_url, project_key, client_id
 72 |     );
 73 | 
 74 |     let scope = permissions
 75 |         .iter()
 76 |         .map(|&p| format!("{}:{}", p, project_key))
 77 |         .collect::>()
 78 |         .join(" ");
 79 | 
 80 |     let url = format!(
 81 |         "{}/oauth/token?grant_type=client_credentials&scope={}",
 82 |         auth_url, scope
 83 |     );
 84 | 
 85 |     debug!("Trying to retrieve token with url '{}'", url);
 86 |     let mut res = client
 87 |         .post(&url)
 88 |         .header(CONTENT_LENGTH, "0")
 89 |         .basic_auth(client_id.to_owned(), Some(client_secret.to_owned()))
 90 |         .send()?;
 91 | 
 92 |     let mut body = String::new();
 93 |     res.read_to_string(&mut body)?;
 94 | 
 95 |     if res.status() != StatusCode::OK {
 96 |         let err = crate::UnexpectedStatus::new("expected OK".to_string(), format!("{:?}", res));
 97 |         Err(err)?
 98 |     } else {
 99 |         debug!("Response from '{}': {}", url, body);
100 |         let token_from_api = serde_json::from_str::(&body)?;
101 |         let bearer_token = String::from("Bearer ") + token_from_api.access_token.as_str();
102 |         Ok(Token::new(
103 |             bearer_token.into_bytes(),
104 |             token_from_api.expires_in,
105 |         ))
106 |     }
107 | }
108 | 
109 | #[cfg(test)]
110 | mod tests {
111 |     use super::*;
112 | 
113 |     #[test]
114 |     fn token_is_valid_before_expiration_date() {
115 |         let token = Token::new(vec![], 60);
116 |         assert!(token.is_valid());
117 |     }
118 | 
119 |     #[test]
120 |     fn token_is_not_valid_after_expiration_date() {
121 |         let token = Token::new(vec![], 60);
122 |         let now = Utc::now() + Duration::minutes(2);
123 |         assert!(!token.is_valid_with_margin(now, Duration::seconds(0)));
124 |     }
125 | 
126 |     #[test]
127 |     fn token_is_not_valid_in_margin() {
128 |         let token = Token::new(vec![], 60);
129 |         let now = Utc::now() + Duration::seconds(50);
130 |         assert!(!token.is_valid_with_margin(now, Duration::seconds(20)));
131 |     }
132 | }
133 | 


--------------------------------------------------------------------------------
/rust/src/client.rs:
--------------------------------------------------------------------------------
  1 | use serde::de::DeserializeOwned;
  2 | 
  3 | use reqwest::header::{HeaderMap, HeaderValue, AUTHORIZATION};
  4 | use reqwest::{Client, Method, RequestBuilder, Response, StatusCode};
  5 | use serde_json;
  6 | use std::io::Read;
  7 | 
  8 | /// a commercetools client
  9 | pub struct CtpClient<'a> {
 10 |     api_url: &'a str,
 11 |     auth_url: &'a str,
 12 |     project_key: &'a str,
 13 |     client_id: &'a str,
 14 |     client_secret: &'a str,
 15 |     permissions: Vec<&'a str>,
 16 |     client: Client,
 17 |     token: Option,
 18 | }
 19 | 
 20 | #[derive(Debug)]
 21 | pub struct CtpResponse {
 22 |     pub http_response: Response,
 23 | }
 24 | 
 25 | impl CtpResponse {
 26 |     pub fn new(http_response: Response) -> CtpResponse {
 27 |         CtpResponse { http_response }
 28 |     }
 29 | 
 30 |     pub fn status(&self) -> StatusCode {
 31 |         self.http_response.status()
 32 |     }
 33 | 
 34 |     pub fn body_as_string(&mut self) -> crate::Result {
 35 |         let mut body = String::new();
 36 |         self.http_response.read_to_string(&mut body)?;
 37 |         Ok(body)
 38 |     }
 39 | 
 40 |     pub fn body_as(&mut self) -> crate::Result {
 41 |         let body = self.body_as_string()?;
 42 |         Ok(serde_json::from_str::(&body)?)
 43 |     }
 44 | }
 45 | 
 46 | #[derive(Debug, Deserialize)]
 47 | pub struct PagedQueryResult {
 48 |     pub offset: u64,
 49 |     pub count: u64,
 50 |     pub total: Option,
 51 |     pub results: Vec,
 52 | }
 53 | 
 54 | #[derive(Debug, Serialize)]
 55 | pub struct GraphQLQuery<'a> {
 56 |     pub query: &'a str,
 57 | }
 58 | 
 59 | impl<'a> CtpClient<'a> {
 60 |     /// Returns a commercetools client for the given arguments
 61 |     ///
 62 |     /// # Arguments
 63 |     ///
 64 |     /// * `region` - the world region the client should use
 65 |     /// * `project_key` - project key
 66 |     /// * `client_id` - client id
 67 |     /// * `client_secret` - client secret
 68 |     ///
 69 |     /// # Examples
 70 |     ///
 71 |     /// ```
 72 |     /// use commercetools::region::Region;
 73 |     /// use commercetools::client::CtpClient;
 74 |     ///
 75 |     /// let region = Region::Europe;
 76 |     /// let client = CtpClient::new(®ion, "my project key", "my client id", "my client secret");
 77 |     /// ```
 78 |     pub fn new(
 79 |         region: ®,
 80 |         project_key: &'a str,
 81 |         client_id: &'a str,
 82 |         client_secret: &'a str,
 83 |     ) -> CtpClient<'a>
 84 |     where
 85 |         REG: crate::HasApiUrl<'a> + crate::HasAuthUrl<'a>,
 86 |     {
 87 |         let client = Client::new();
 88 | 
 89 |         CtpClient {
 90 |             api_url: region.api_url(),
 91 |             auth_url: region.auth_url(),
 92 |             project_key,
 93 |             client_id,
 94 |             client_secret,
 95 |             permissions: vec!["manage_project"],
 96 |             client,
 97 |             token: None,
 98 |         }
 99 |     }
100 | 
101 |     pub fn with_auth_url(mut self, auth_url: &'a str) -> CtpClient<'a> {
102 |         self.auth_url = auth_url;
103 |         self
104 |     }
105 | 
106 |     pub fn with_api_url(mut self, api_url: &'a str) -> CtpClient<'a> {
107 |         self.api_url = api_url;
108 |         self
109 |     }
110 | 
111 |     pub fn with_permissions(mut self, permissions: &[&'a str]) -> CtpClient<'a> {
112 |         self.permissions = permissions.to_vec();
113 |         self
114 |     }
115 | 
116 |     // TODO (YaSi): avoid cloning the String on each call
117 |     pub fn get_token(&mut self) -> crate::Result> {
118 |         if let Some(ref token) = self.token {
119 |             if token.is_valid() {
120 |                 return Ok(token.bearer_token.clone());
121 |             }
122 |         }
123 | 
124 |         let new_token = super::auth::retrieve_token(
125 |             &self.client,
126 |             self.auth_url,
127 |             self.project_key,
128 |             self.client_id,
129 |             self.client_secret,
130 |             &self.permissions,
131 |         )?;
132 |         self.token = Some(new_token.clone());
133 |         Ok(new_token.bearer_token)
134 |     }
135 | 
136 |     pub fn list(
137 |         &mut self,
138 |         resource: &str,
139 |     ) -> crate::Result> {
140 |         let url = format!("/{}?withTotal=false", resource);
141 |         let body = self.get(&url)?.body_as_string()?;
142 |         Ok(serde_json::from_str::>(&body)?)
143 |     }
144 | 
145 |     pub fn get(&mut self, uri: &str) -> crate::Result {
146 |         let method = Method::GET;
147 |         self.request(method, uri).and_then(send)
148 |     }
149 | 
150 |     pub fn post(&mut self, uri: &str, body: &'static str) -> crate::Result {
151 |         let method = Method::POST;
152 |         self.request(method, uri)
153 |             .map(|r| r.body(body))
154 |             .and_then(send)
155 |     }
156 | 
157 |     pub fn delete(&mut self, uri: &str) -> crate::Result {
158 |         let method = Method::DELETE;
159 |         self.request(method, uri).and_then(send)
160 |     }
161 | 
162 |     /// sends a [GraphQL](http://graphql.org/) query
163 |     /// To test the query, use:
164 |     ///
165 |     /// - in Europe: https://impex.sphere.io/graphiql
166 |     /// - in US: https://impex.commercetools.co/graphiql
167 |     pub fn graphql(&mut self, query: &str) -> crate::Result {
168 |         let body = serde_json::to_string(&GraphQLQuery { query })?;
169 | 
170 |         let method = Method::POST;
171 |         self.request(method, "/graphql")
172 |             .map(|r| r.body(body))
173 |             .and_then(send)
174 |     }
175 | 
176 |     pub fn request(&mut self, method: Method, uri: &str) -> crate::Result {
177 |         let bearer_token = self.get_token()?;
178 |         let mut headers = HeaderMap::new();
179 |         let bearer_token_value = HeaderValue::from_bytes(bearer_token.as_slice())?;
180 |         let _ = headers.insert(AUTHORIZATION, bearer_token_value);
181 |         let uri = format!("{}/{}{}", self.api_url, self.project_key, uri);
182 |         let client = &self.client;
183 |         Ok(client.request(method, &uri).headers(headers))
184 |     }
185 | }
186 | 
187 | fn send(r: RequestBuilder) -> crate::Result {
188 |     Ok(r.send().map(CtpResponse::new)?)
189 | }
190 | 
191 | #[cfg(test)]
192 | mod tests {
193 |     use super::super::region::Region;
194 |     use super::*;
195 | 
196 |     #[test]
197 |     fn new_client() {
198 |         CtpClient::new(&Region::Europe, "project_key", "client_id", "client_secret");
199 |         CtpClient::new(
200 |             &Region::NorthAmerica,
201 |             "project_key",
202 |             "client_id",
203 |             "client_secret",
204 |         );
205 |     }
206 | 
207 |     #[test]
208 |     fn new_client_with_customized_url() {
209 |         CtpClient::new(&Region::Europe, "project_key", "client_id", "client_secret")
210 |             .with_api_url("my_api_url");
211 | 
212 |         CtpClient::new(&Region::Europe, "project_key", "client_id", "client_secret")
213 |             .with_auth_url("my_auth_url");
214 | 
215 |         CtpClient::new(&Region::Europe, "project_key", "client_id", "client_secret")
216 |             .with_api_url("my_api_url")
217 |             .with_auth_url("my_auth_url");
218 |     }
219 | }
220 | 


--------------------------------------------------------------------------------
/rust/src/errors.rs:
--------------------------------------------------------------------------------
 1 | use failure::*;
 2 | use std::result;
 3 | 
 4 | pub type Result = result::Result;
 5 | 
 6 | // use pattern https://boats.gitlab.io/failure/custom-fail.html
 7 | 
 8 | #[derive(Fail, Debug)]
 9 | #[fail(
10 |     display = "unexpected http status: {}. Response: '{:?}'",
11 |     msg, response
12 | )]
13 | pub struct UnexpectedStatus {
14 |     msg: String,
15 |     response: String,
16 | }
17 | 
18 | impl UnexpectedStatus {
19 |     pub fn new(msg: String, response: String) -> UnexpectedStatus {
20 |         UnexpectedStatus { msg, response }
21 |     }
22 | }
23 | 


--------------------------------------------------------------------------------
/rust/src/lib.rs:
--------------------------------------------------------------------------------
 1 | #![recursion_limit = "1024"]
 2 | 
 3 | #[macro_use]
 4 | extern crate serde_derive;
 5 | 
 6 | #[macro_use]
 7 | extern crate log;
 8 | 
 9 | pub use crate::auth::Token;
10 | pub use crate::errors::*;
11 | pub use crate::region::*;
12 | 
13 | pub mod auth;
14 | pub mod client;
15 | mod errors;
16 | pub mod region;
17 | 


--------------------------------------------------------------------------------
/rust/src/region.rs:
--------------------------------------------------------------------------------
 1 | use std::str::FromStr;
 2 | 
 3 | pub trait HasAuthUrl<'a> {
 4 |     fn auth_url(&self) -> &'a str;
 5 | }
 6 | 
 7 | pub trait HasApiUrl<'a> {
 8 |     fn api_url(&self) -> &'a str;
 9 | }
10 | 
11 | #[derive(PartialEq, Eq)]
12 | /// World region for which the commercetools platform has data-centers
13 | pub enum Region {
14 |     Europe,
15 |     NorthAmerica,
16 | }
17 | 
18 | impl FromStr for Region {
19 |     type Err = String;
20 |     fn from_str(s: &str) -> Result {
21 |         match s.to_string().to_lowercase().as_ref() {
22 |             "europe" => Ok(Region::Europe),
23 |             "northamerica" => Ok(Region::NorthAmerica),
24 |             _ => Err(format!(
25 |                 "Region '{}' not recognized. Valid values: 'Europe', 'NorthAmerica'.",
26 |                 s
27 |             )),
28 |         }
29 |     }
30 | }
31 | 
32 | impl<'a> HasAuthUrl<'a> for Region {
33 |     /// Returns the [auth url](http://dev.commercetools.com/http-api-authorization.html#hosts)
34 |     /// for this region
35 |     fn auth_url(&self) -> &'a str {
36 |         match *self {
37 |             Region::Europe => "https://auth.sphere.io",
38 |             Region::NorthAmerica => "https://auth.commercetools.co",
39 |         }
40 |     }
41 | }
42 | 
43 | impl<'a> HasApiUrl<'a> for Region {
44 |     /// Returns the [api url](http://dev.commercetools.com/http-api.html#hosts) for this region
45 |     fn api_url(&self) -> &'a str {
46 |         match *self {
47 |             Region::Europe => "https://api.sphere.io",
48 |             Region::NorthAmerica => "https://api.commercetools.co",
49 |         }
50 |     }
51 | }
52 | 
53 | #[cfg(test)]
54 | mod tests {
55 |     use super::*;
56 |     use std::str::FromStr;
57 | 
58 |     #[test]
59 |     fn region_from_string() {
60 |         assert!(Region::from_str("Europe") == Ok(Region::Europe));
61 |         assert!(Region::from_str("europe") == Ok(Region::Europe));
62 |         assert!(Region::from_str("NorthAmerica") == Ok(Region::NorthAmerica));
63 |         assert!(Region::from_str("northAmeriCA") == Ok(Region::NorthAmerica));
64 |     }
65 | 
66 |     #[test]
67 |     fn unparsable_region_err() {
68 |         assert!(
69 |             Region::from_str("India")
70 |                 == Result::Err(
71 |                     "Region 'India' not recognized. Valid values: 'Europe', \
72 |                      'NorthAmerica'."
73 |                         .to_string()
74 |                 )
75 |         );
76 |     }
77 | }
78 | 


--------------------------------------------------------------------------------
/rust/tests/auth.rs:
--------------------------------------------------------------------------------
 1 | extern crate commercetools;
 2 | extern crate hyper;
 3 | 
 4 | use hyper::server::{Handler, Request, Response, Server};
 5 | 
 6 | fn with_server(handle: H, test: &Fn(String) -> R) -> R {
 7 |     let mut server = Server::http("localhost:0").unwrap().handle(handle).unwrap();
 8 |     let url = format!("http://localhost:{}", server.socket.port());
 9 |     let result = test(url);
10 |     server.close().unwrap();
11 |     result
12 | }
13 | 
14 | #[test]
15 | fn auth_can_extract_oauth_token() {
16 |     fn handle(_: Request, res: Response) {
17 |         res.send(b"{\"access_token\": \"test\", \"expires_in\": 234}")
18 |             .unwrap();
19 |     }
20 | 
21 |     with_server(handle, &|url| {
22 |         let client = reqwest::Client::new();
23 |         let token = commercetools::auth::retrieve_token(
24 |             &client,
25 |             &url,
26 |             "project_key",
27 |             "client_id",
28 |             "client_secret",
29 |             &["permission"],
30 |         );
31 |         assert!(token.is_ok(), "token = {:?}", token);
32 |     });
33 | }
34 | 


--------------------------------------------------------------------------------
/scala/.gitignore:
--------------------------------------------------------------------------------
1 | .idea
2 | .idea_modules
3 | target
4 | lib
5 | classes
6 | *.iml
7 | 


--------------------------------------------------------------------------------
/scala/README.md:
--------------------------------------------------------------------------------
 1 | # Scala Hello on SPHERE.IO
 2 | 
 3 | A scala example to authenticate your application to [SPHERE.IO](http://sphere.io) and get the number of products 
 4 | in your project.
 5 | 
 6 | ## Run
 7 | 
 8 | The following steps assume a current [sbt](http://www.scala-sbt.org/) installation on your machine.
 9 |   
10 |  1. `git clone git://github.com/commercetools/sphere-hello-api.git`
11 |  2. `cd scala`
12 |  3. Put your sphere credentials to the `scala/src/main/resources/application.conf` configuration file.
13 |  4. Execute ```$ sbt run```
14 | 
15 | 


--------------------------------------------------------------------------------
/scala/build.sbt:
--------------------------------------------------------------------------------
 1 | name := "sphere-hello-api"
 2 | 
 3 | description := "An example application that authenticates and access project data using SPHERE.IO API"
 4 | 
 5 | scalaVersion := "2.12.8"
 6 | 
 7 | libraryDependencies ++=
 8 |   "org.dispatchhttp" %% "dispatch-core" % "0.14.0" ::
 9 |   "net.liftweb" %% "lift-json" % "3.1.1" ::
10 |   "com.typesafe" % "config" % "1.3.3" ::
11 |   "ch.qos.logback" % "logback-classic" % "1.2.3" ::
12 |   Nil
13 | 


--------------------------------------------------------------------------------
/scala/project/build.properties:
--------------------------------------------------------------------------------
1 | sbt.version=1.2.8
2 | 


--------------------------------------------------------------------------------
/scala/src/main/resources/application.conf:
--------------------------------------------------------------------------------
1 | sphere-hello {
2 |   clientId=""
3 |   clientSecret=""
4 |   projectKey=""
5 | }
6 | 


--------------------------------------------------------------------------------
/scala/src/main/resources/logback.xml:
--------------------------------------------------------------------------------
 1 | 
 2 | 
 3 |     
 4 |         
 6 |         
 7 |             %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
 8 |         
 9 |     
10 | 
11 |     
12 | 
13 |     
14 |         
15 |     
16 | 


--------------------------------------------------------------------------------
/scala/src/main/scala/SphereHello.scala:
--------------------------------------------------------------------------------
 1 | import java.util.Base64
 2 | 
 3 | import scala.concurrent.ExecutionContext.Implicits.global
 4 | import scala.concurrent.{Await, Future}
 5 | import scala.concurrent.duration.Duration
 6 | import com.typesafe.config._
 7 | import dispatch._
 8 | import net.liftweb.json._
 9 | import org.asynchttpclient.{DefaultAsyncHttpClientConfig, Response}
10 | 
11 | object SphereHello extends App {
12 |   val ApiUrl = "https://api.sphere.io/"
13 |   val AuthApiUrl = "https://auth.sphere.io/oauth/token"
14 | 
15 |   //see configuration file scala/src/main/resources/application.conf
16 |   val conf = ConfigFactory.load()
17 |   val clientId = conf.getString("sphere-hello.clientId")
18 |   val clientSecret = conf.getString("sphere-hello.clientSecret")
19 |   val projectKey = conf.getString("sphere-hello.projectKey")
20 |   
21 |   val h = new Http(new DefaultAsyncHttpClientConfig.Builder())
22 | 
23 |   def prettyResponseBody(resp: Response) =
24 |     parseOpt(resp.getResponseBody) map (json => prettyRender(json)) getOrElse resp.getResponseBody
25 | 
26 |   /** @return oauth access token */
27 |   def login(clientId: String, clientSecret: String, projectKey: String): Future[String] = {
28 |     val encoded = Base64.getEncoder.encode(s"$clientId:$clientSecret".getBytes)
29 |     h(url(AuthApiUrl).POST
30 |       .setHeader("Authorization", s"Basic $encoded")
31 |       .setHeader("Content-Type", "application/x-www-form-urlencoded")
32 |       .setBody(s"grant_type=client_credentials&scope=manage_project:$projectKey")
33 |     ).map(rsp => (rsp.getStatusCode, parseOpt(rsp.getResponseBody) map (_ \ "access_token")) match {
34 |       case (200, Some(JString(s))) => s
35 |       case (status, _) =>
36 |         throw new IllegalStateException("Auth response does not contain 'access_token'. " +
37 |           s"HTTP status: $status. ${prettyResponseBody(rsp)}")
38 |     })
39 |   }
40 |   
41 |   /** Issues a query to get all products, see [[http://sphere.io/dev/HTTP_API_Projects_Products.html#product-projections-by-query]].
42 |     * @return PagedQueryResult
43 |     *         with the results array of ProductProjection JSON. */
44 |   def getProducts(oauthToken: String): Future[Response] =
45 |     h(url(s"$ApiUrl$projectKey/product-projections").setHeader("Authorization", s"Bearer $oauthToken"))
46 | 
47 |   try {
48 |     val f = for {
49 |       token <- login(clientId, clientSecret, projectKey)
50 |       productResp <- getProducts(token)
51 |     } yield (productResp.getStatusCode, parseOpt(productResp.getResponseBody) map (_ \ "total")) match {
52 |         case (200, Some(JInt(total))) => total
53 |         case (status, _) =>
54 |           throw new IllegalStateException("Product query response is invalid ot does not contain 'total'. " +
55 |             s"HTTP status $status. ${prettyResponseBody(productResp)}")
56 |       }
57 | 
58 |     val nrOfProducts = Await.result(f, Duration.Inf)
59 | 
60 |     println("Number of products: " + nrOfProducts)
61 |   } finally {
62 |     h.shutdown()
63 |   }
64 | }


--------------------------------------------------------------------------------