hash-blue 0.1 → 0.2

Sign up to get free protection for your applications and to get access to all the features.
data/Gemfile CHANGED
@@ -3,8 +3,6 @@ source "http://rubygems.org"
3
3
  # Specify your gem's dependencies in hash-blue.gemspec
4
4
  gemspec
5
5
 
6
- gem 'json'
7
-
8
6
  group :development, :test do
9
7
  gem 'rspec'
10
8
  end
data/README.md CHANGED
@@ -1,8 +1,8 @@
1
- O2 Labs has exposed the power of #blue to developers via a simple REST & JSON based API, combined with oAuth2 to developers who can create new ways for users to manage their texts and add combine the ubiquity of SMS with their applications, users simply grant an application access to their messages stream or just certain messages.
1
+ O2 Labs has exposed the power of \#blue to developers via a simple REST & JSON based API, combined with oAuth2 to developers who can create new ways for users to manage their texts and add combine the ubiquity of SMS with their applications, users simply grant an application access to their messages stream or just certain messages.
2
2
 
3
- _#_blue is not a service designed for users to text into applications rather it is aimed at enriching the users existing text experience by building on top of their day to day text use.
3
+ \#blue is not a service designed for users to text into applications rather it is aimed at enriching the users existing text experience by building on top of their day to day text use.
4
4
 
5
- This gem provides a smooth access to _#_blue API.
5
+ This gem provides a smooth access to \#blue API.
6
6
 
7
7
  # How to install
8
8
 
@@ -10,30 +10,63 @@ This gem provides a smooth access to _#_blue API.
10
10
 
11
11
  # Getting started
12
12
 
13
- There're three main entities in _#_blue:
13
+ There're three main entities in \#blue:
14
14
 
15
15
  * message: models a SMS sent/received by the user
16
16
  * contact: friend's list including phone number, name and email address.
17
17
  * account: describes the user account
18
18
 
19
- _#_blue client design is based on ActiveRecord model.
19
+ \#blue client design is based on ActiveRecord model.
20
20
 
21
- ## Retrieve a valid user token
21
+ ## Retrieve a valid user token using OAuth 2.0
22
22
 
23
- _#_blue API is based on oAuth secure mechanism so before using the API the user must grant permissions to your application. Follow the instructions on [the HashBlue documentation](https://api.hashblue.com/doc/Authentication)
23
+ \#blue API is based on oAuth secure mechanism so before using the API the user must grant permissions to your application. Follow the instructions on [the HashBlue documentation](https://api.hashblue.com/doc/Authentication)
24
24
 
25
- ### First step. Redirect user to HashBlue authorization page
25
+ You can either use the Rails Engine or create your own logic.
26
+
27
+ ### Use the embedded Rails Engine
28
+
29
+ * Insert in your rails application Gemfile the dependency hash-blue
30
+ gem 'hash-blue'
31
+
32
+ * Two new endpoints are created (check running ''bundle install'' and ''rake routes''):
33
+
34
+ \# this method redirects to hashblue web page to start the oAuth process
35
+
36
+ /hashblue/index
37
+ \# this method gets the Oauth response, asks for a valid access token and sends the data
38
+
39
+ /hashblue/code
40
+
41
+ * Configure in an application initializer your specific data (i.e. config/initializer/hashblue.rb)
42
+
43
+ Rails.application.config.hashblue.client_id = <app_client_id>
44
+ Rails.application.config.hashblue.client_secret = <app_client_secret>
45
+ \# Internal redirection to handle the HashBlue response. You'll receive a GET request to that action
46
+ \# after OAuth mechanism with user access token info: :access_token, :expires_in, :refresh_token
47
+ Rails.application.config.hashblue.forward_action = <controller#action>
48
+
49
+ ### Create the logic to handle the OAuth mechanism
50
+
51
+ #### First step. Redirect user to HashBlue authorization page
26
52
 
27
53
  redirect_to "https://hashblue.com/oauth/authorize?client_id=<app_client_id>&redirect_uri=<your_callback_url>"
28
54
 
29
- ### Second step. Get access token
55
+ #### Second step. Get access token
30
56
 
31
57
  uri = URI.parse("https://hashblue.com")
32
58
  rest = Net::HTTP.new(uri.host, uri.port)
33
59
  rest.use_ssl = true
34
60
  code = <code_from_first_step>
35
61
 
36
- query = "client_id=<app_client_id>&client_secret=<app_client_secret>&grant_type=authorization_code&code=#{code}&redirect_uri=<your_callback_url>"
62
+ params = {
63
+ :client_id => <app_client_id>,
64
+ :client_secret => <app_client_secret>,
65
+ :grant_type => <authorization_code>,
66
+ :code => code,
67
+ :redirect_uri => <your_callback_url>
68
+ }
69
+ query = params.collect { |k, v| "#{k}=#{v.to_s}" }.join("&"))
37
70
  access_token = rest.post( "/oauth/access_token?#{query}", nil)
38
71
 
39
72
  ## Configure the client with a valid access token
@@ -50,6 +83,18 @@ _#_blue API is based on oAuth secure mechanism so before using the API the user
50
83
  ### Retrieve a specific message
51
84
 
52
85
  message = HashBlue::Message.find(<valid_message_id>)
86
+
87
+ ### Retrieve the first message
88
+
89
+ message = HashBlue::Message.find(:first)
90
+
91
+ ### Retrieve messages since January 14th, 2011
92
+
93
+ messages = HashBlue::Message.find({:since => "2011-01-14T14:30Z")
94
+
95
+ ### Retrieve messages from 20 to 25
96
+
97
+ messages = HashBlue::Message.find({:first => 20, :count => 5)
53
98
 
54
99
  ### Retrieve a contact messages
55
100
 
@@ -93,6 +138,17 @@ _#_blue API is based on oAuth secure mechanism so before using the API the user
93
138
 
94
139
  HashBlue::Account.find
95
140
 
141
+ # Version 0.2 features
142
+
143
+ - Rails Engine: includes OAuth 2.0 support
144
+ - Message filtering: enables :first, {:since => date}, {:first => index, :count => number}
145
+
146
+ # TODO
147
+ - Enhance pagination mechanism for messages and contacts
148
+ - Search by time: test the date format. Support both a string and a Date/Time with valid ISO 8601 format
149
+ - Check q parameter in searches
150
+ - Use ActiveSupport instead of json_pure
151
+
96
152
  # Author
97
153
 
98
154
  Juan de Bravo
@@ -0,0 +1,91 @@
1
+ require 'oauth/signature/hmac/sha1'
2
+ require 'oauth/client/helper'
3
+ require 'net/https'
4
+
5
+ #
6
+ # O2 Labs has exposed the power of #blue to developers via a simple REST & JSON based API,
7
+ # enabling new ways for users to manage their texts and add combine the ubiquity of SMS
8
+ # with their applications, users simply grant an application access to their messages stream
9
+ # or just certain messages.
10
+ #
11
+ # Juan de Bravo (juandebravo@gmail.com)
12
+ # Ruby sensei at The Lab (http://thelab.o2.com)
13
+ #
14
+
15
+ class HashblueController < ApplicationController
16
+
17
+ # parameters required in both OAuth steps
18
+ DEFAULT_PARAMS = {
19
+ :client_id => Rails.application.config.hashblue.client_id
20
+ }
21
+
22
+ # OAuth step1: redirect to HashBlue endpoint with the application idenfitifer and the redirect uri
23
+ def index
24
+ hb_params = {
25
+ :redirect_uri => redirect_uri
26
+ }
27
+ hb_params.merge!(DEFAULT_PARAMS)
28
+
29
+ redirect_to "#{endpoint}/oauth/authorize?".concat(hb_params.collect { |k, v| "#{k}=#{v.to_s}" }.join("&"))
30
+ end
31
+
32
+ # OAuth step2: retrieve the code from HashBlue, ask for a valid access token and
33
+ # forward to the user defined uri
34
+ def code
35
+ # This code is retrieved from HashBlue
36
+ code = params[:code]
37
+
38
+ hb_params = {
39
+ :redirect_uri => redirect_uri,
40
+ :client_secret => Rails.application.config.hashblue.client_secret,
41
+ :grant_type => "authorization_code",
42
+ :code => code
43
+ }
44
+ hb_params.merge!(DEFAULT_PARAMS)
45
+
46
+ response = rest.post( "/oauth/access_token?".concat(hb_params.collect { |k, v| "#{k}=#{v.to_s}" }.join("&")), nil)
47
+
48
+ if response.code.eql?("200")
49
+ response = ActiveSupport::JSON.decode(response.body)
50
+
51
+ if response.has_key?("access_token")
52
+ Rails.application.config.hashblue.forward_action.nil? and raise RuntimeError, "Invalid forward_action value"
53
+
54
+ url = Rails.application.config.hashblue.forward_action.split("#")
55
+ url.length == 2 or raise RuntimeError, "Invalid forward_action value"
56
+ redirect_to ({
57
+ :controller => url.first,
58
+ :action => url.last,
59
+ :access_token => response["access_token"],
60
+ :expires_in => response["expires_in"],
61
+ :refresh_token => response["refresh_token"]
62
+ })
63
+ elsif response.has_key?("error")
64
+ logger.error "Error while accessing to HashBlue #{response['error']}"
65
+ raise RuntimeError, response['error']
66
+ end
67
+ else
68
+ logger.error "Error #{response.code} while accessing to HashBlue #{response.body}"
69
+ raise RuntimeError, "Unable to access to hashblue"
70
+ end
71
+ end
72
+
73
+ # rest client to HashBlue endpoint
74
+ def rest
75
+ @@rest ||= (uri = URI.parse(endpoint)
76
+ rest = Net::HTTP.new(uri.host, uri.port)
77
+ rest.use_ssl = true
78
+ rest)
79
+ end
80
+
81
+ # HashBlue endpoint
82
+ def endpoint
83
+ Rails.application.config.hashblue.uri
84
+ end
85
+
86
+ def redirect_uri
87
+ "#{request.protocol}#{request.host_with_port}/hashblue/code"
88
+ end
89
+
90
+
91
+ end
data/config/routes.rb ADDED
@@ -0,0 +1,8 @@
1
+
2
+ Rails.application.routes.draw do |map|
3
+
4
+ get "hashblue/index"
5
+
6
+ get "hashblue/code"
7
+
8
+ end
data/hash-blue.gemspec CHANGED
@@ -8,7 +8,7 @@ Gem::Specification.new do |s|
8
8
  s.platform = Gem::Platform::RUBY
9
9
  s.authors = ["Juan de Bravo"]
10
10
  s.email = ["juandebravo@gmail.com"]
11
- s.homepage = "https://api.hashblue.com/doc/"
11
+ s.homepage = "https://github.com/juandebravo/hash-blue"
12
12
  s.summary = %q{This gem provides a smooth access to _#_blue API.}
13
13
  s.description = %q{O2 Labs has exposed the power of #blue to developers via a
14
14
  simple REST & JSON based API, combined with oAuth2 to developers who can
@@ -25,4 +25,6 @@ Gem::Specification.new do |s|
25
25
  s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
26
26
  s.require_paths = ["lib"]
27
27
 
28
+ s.add_dependency("json_pure" , ">= 1.4.3")
29
+
28
30
  end
data/lib/hash-blue.rb CHANGED
@@ -3,6 +3,8 @@ require 'hash_blue/contact'
3
3
  require 'hash_blue/message'
4
4
  require 'hash_blue/account'
5
5
 
6
+ require 'hash_blue/engine' if defined?(Rails)
7
+
6
8
  #
7
9
  # O2 Labs has exposed the power of #blue to developers via a simple REST & JSON based API,
8
10
  # enabling new ways for users to manage their texts and add combine the ubiquity of SMS
@@ -0,0 +1,49 @@
1
+ require 'rails'
2
+ require 'hash_blue/engine_config'
3
+
4
+ #
5
+ # O2 Labs has exposed the power of #blue to developers via a simple REST & JSON based API,
6
+ # enabling new ways for users to manage their texts and add combine the ubiquity of SMS
7
+ # with their applications, users simply grant an application access to their messages stream
8
+ # or just certain messages.
9
+ #
10
+ # Juan de Bravo (juandebravo@gmail.com)
11
+ # Ruby sensei at The Lab (http://thelab.o2.com)
12
+ #
13
+
14
+ module HashBlue
15
+ #
16
+ # This class defines the HashBlue Rails Engine to handle OAuth authentication.
17
+ # The Engine defines two new routes to handle each of the OAuth steps
18
+ # 1.- forward the user request to HashBlue server
19
+ # 2.- get the oauth code, request a valid access token and forward the token info to a user defined action
20
+ #
21
+ # How to configure HashBlue Engine
22
+ #
23
+ # :uri => HashBlue API endpoint
24
+ # :client_id => token that identifies your application in OAuth mechanism
25
+ # :client_secret => token that secures your communication in OAuth mechanism
26
+ # :forward_action => controller#action where hashblue#code action will redirect the user token data:
27
+ # - :access_token
28
+ # - :expires_in
29
+ # - :refresh_token
30
+ #
31
+ # These configuration can be included in an application initializer, i.e. config/initializers/hashblue.rb
32
+ #
33
+ # Rails.application.config.hashblue.client_id = "<client_id>"
34
+ # Rails.application.config.hashblue.client_secret = "<client_secret"
35
+ # Rails.application.config.hashblue.forward_action = "controller#action" that will receive the user token data
36
+ #
37
+
38
+ class Engine < Rails::Engine
39
+
40
+ # we need to create the hashblue config hash before loading the application initializer
41
+ initializer :hashblue, {:before => :load_config_initializers} do |app|
42
+
43
+ app.config.hashblue = HashBlue::EngineConfig.new
44
+ # HashBlue API endpoint
45
+ app.config.hashblue.uri = "https://hashblue.com"
46
+ end
47
+
48
+ end
49
+ end
@@ -0,0 +1,18 @@
1
+ #
2
+ # O2 Labs has exposed the power of #blue to developers via a simple REST & JSON based API,
3
+ # enabling new ways for users to manage their texts and add combine the ubiquity of SMS
4
+ # with their applications, users simply grant an application access to their messages stream
5
+ # or just certain messages.
6
+ #
7
+ # Juan de Bravo (juandebravo@gmail.com)
8
+ # Ruby sensei at The Lab (http://thelab.o2.com)
9
+ #
10
+
11
+ module HashBlue
12
+ # Array of elements that should be configured
13
+ # By default, :uri endpoint is configured in the Engine. The rest of parameters are client specific
14
+ hashblue_config = [:uri, :client_id, :client_secret, :forward_action]
15
+
16
+ class EngineConfig < Struct.new(*hashblue_config)
17
+ end
18
+ end
@@ -83,6 +83,10 @@ module HashBlue
83
83
  # @param arg:
84
84
  # => nil => retrieve all messages
85
85
  # => :all => retrieve all messages
86
+ # => :first => retrieve the first message
87
+ # => {:since => ISO 8601 format} => retrieve messages since the
88
+ # specified data (i.e. 2011-01-14T14:30Z)
89
+ # => {:first => index, :count => count} => retrieve count messages from index first
86
90
  # => {:contact => <contact_id>} => retrieve a specific contact messages
87
91
  # => id => retrieve a specific message using a valid unique identifier
88
92
 
@@ -92,14 +96,26 @@ module HashBlue
92
96
  elsif arg.is_a? Symbol
93
97
  if arg.eql?(:all)
94
98
  messages = get "/messages"
99
+ elsif arg.eql?(:first)
100
+ messages = get "/messages?per_page=1"
95
101
  else
96
102
  raise ArgumentError, "Invalid argument #{arg}"
97
103
  end
98
104
  elsif arg.is_a? String or arg.is_a? Fixnum
99
105
  messages = get "/messages/#{arg}"
100
106
  elsif arg.is_a? Hash
101
- arg.has_key?(:contact) or raise ArgumentError, "Invalid argument #{arg}"
102
- messages = get "/contacts/#{arg[:contact]}/messages"
107
+ if arg.has_key?(:contact)
108
+ messages = get "/contacts/#{arg[:contact]}/messages"
109
+ elsif arg.has_key?(:since)
110
+ arg[:since].is_a?(String) or arg[:since].is_a?
111
+ messages = get "/messages?since=#{arg[:since]}"
112
+ elsif arg.has_key?(:first)
113
+ messages = get "/messages?page=2&per_page=#{arg[:first]}"
114
+ else
115
+ raise ArgumentError, "Invalid argument #{arg}"
116
+ end
117
+ else
118
+ raise ArgumentError, "Invalid argument #{arg}"
103
119
  end
104
120
  parse_response(messages)
105
121
  end
@@ -9,5 +9,5 @@
9
9
  #
10
10
 
11
11
  module HashBlue
12
- VERSION = "0.1"
12
+ VERSION = "0.2"
13
13
  end
data/spec/account_spec.rb CHANGED
@@ -2,7 +2,6 @@ $:.unshift File.join(File.dirname(__FILE__),'..','lib')
2
2
 
3
3
  require 'hash-blue'
4
4
  require 'webmock/rspec'
5
- require 'json'
6
5
 
7
6
  describe HashBlue::Account do
8
7
  before(:all) do
data/spec/contact_spec.rb CHANGED
@@ -2,7 +2,6 @@ $:.unshift File.join(File.dirname(__FILE__),'..','lib')
2
2
 
3
3
  require 'hash-blue'
4
4
  require 'webmock/rspec'
5
- require 'json'
6
5
 
7
6
  describe HashBlue::Contact do
8
7
  before(:all) do
data/spec/message_spec.rb CHANGED
@@ -2,7 +2,6 @@ $:.unshift File.join(File.dirname(__FILE__),'..','lib')
2
2
 
3
3
  require 'hash-blue'
4
4
  require 'webmock/rspec'
5
- require 'json'
6
5
 
7
6
  describe HashBlue::Message do
8
7
  before(:all) do
@@ -28,6 +27,60 @@ describe HashBlue::Message do
28
27
  message.contact.email.should eql("mike@foo.com")
29
28
  end
30
29
  end
30
+
31
+ context "find messages" do
32
+ it "should return a list of messages" do
33
+ stub_request(:get, "https://api.hashblue.com/messages").
34
+ with(:headers => {'Accept'=>'*/*', 'Authorization'=>'OAuth XXXXX'}).
35
+ to_return(:status => 200, :body => '{"messages":[{"uri":"https://api.hashblue.com/messages/foo","timestamp":"2011-05-09T21:43:52Z","sent":true,"contact":{"name":"Mike","uri":"https://api.hashblue.com/contacts/mike","messages":"https://api.hashblue.com/contacts/mike/messages","phone_number":"07711223344","msisdn":"447711223344","email":"mike@foo.com"},"content":"test","favourite":false}, {"uri":"https://api.hashblue.com/messages/bar","timestamp":"2011-05-09T21:43:52Z","sent":true,"contact":{"name":"Mike","uri":"https://api.hashblue.com/contacts/mike","messages":"https://api.hashblue.com/contacts/mike/messages","phone_number":"07711223344","msisdn":"447711223344","email":"mike@foo.com"},"content":"this is another test","favourite":true}]}', :headers => {})
36
+
37
+ message = HashBlue::Message.find()
38
+ message.should be_an_instance_of(Array)
39
+ message.should respond_to(:length)
40
+ message.length.should eql(2)
41
+ message[0].should be_an_instance_of(HashBlue::Message)
42
+ message[1].should be_an_instance_of(HashBlue::Message)
43
+ end
44
+
45
+ it "should return the first message when paramter is :first" do
46
+ stub_request(:get, "https://api.hashblue.com/messages?per_page=1").
47
+ with(:headers => {'Accept'=>'*/*', 'Authorization'=>'OAuth XXXXX'}).
48
+ to_return(:status => 200, :body => '{"messages":[{"uri":"https://api.hashblue.com/messages/foo","timestamp":"2011-05-09T21:43:52Z","sent":true,"contact":{"name":"Mike","uri":"https://api.hashblue.com/contacts/mike","messages":"https://api.hashblue.com/contacts/mike/messages","phone_number":"07711223344","msisdn":"447711223344","email":"mike@foo.com"},"content":"test","favourite":false}]}', :headers => {})
49
+
50
+ message = HashBlue::Message.find(:first)
51
+ message.should be_an_instance_of(Array)
52
+ message.should respond_to(:length)
53
+ message.length.should eql(1)
54
+ message[0].should be_an_instance_of(HashBlue::Message)
55
+ end
56
+
57
+ it "should request messages since a specific date when parameter :since defined" do
58
+ date = "2011-01-14T14:30Z"
59
+ stub_request(:get, "https://api.hashblue.com/messages?since=#{date}").
60
+ with(:headers => {'Accept'=>'*/*', 'Authorization'=>'OAuth XXXXX'}).
61
+ to_return(:status => 200, :body => '{"messages":[{"uri":"https://api.hashblue.com/messages/foo","timestamp":"2011-05-09T21:43:52Z","sent":true,"contact":{"name":"Mike","uri":"https://api.hashblue.com/contacts/mike","messages":"https://api.hashblue.com/contacts/mike/messages","phone_number":"07711223344","msisdn":"447711223344","email":"mike@foo.com"},"content":"test","favourite":false}]}', :headers => {})
62
+
63
+ message = HashBlue::Message.find({:since => date})
64
+ message.should be_an_instance_of(Array)
65
+ message.should respond_to(:length)
66
+ message.length.should eql(1)
67
+ message[0].should be_an_instance_of(HashBlue::Message)
68
+ end
69
+
70
+ it "should request messages since a specific index when parameter {:first} defined" do
71
+ first = 15
72
+ stub_request(:get, "https://api.hashblue.com/messages?page=2&per_page=#{first}").
73
+ with(:headers => {'Accept'=>'*/*', 'Authorization'=>'OAuth XXXXX'}).
74
+ to_return(:status => 200, :body => '{"messages":[{"uri":"https://api.hashblue.com/messages/foo","timestamp":"2011-05-09T21:43:52Z","sent":true,"contact":{"name":"Mike","uri":"https://api.hashblue.com/contacts/mike","messages":"https://api.hashblue.com/contacts/mike/messages","phone_number":"07711223344","msisdn":"447711223344","email":"mike@foo.com"},"content":"test","favourite":false}]}', :headers => {})
75
+
76
+ message = HashBlue::Message.find({:first => first})
77
+ message.should be_an_instance_of(Array)
78
+ message.should respond_to(:length)
79
+ message.length.should eql(1)
80
+ message[0].should be_an_instance_of(HashBlue::Message)
81
+ end
82
+
83
+ end
31
84
 
32
85
  context "create a new message" do
33
86
  it "should create a message successfully when phone_number and content provided" do
metadata CHANGED
@@ -2,7 +2,7 @@
2
2
  name: hash-blue
3
3
  version: !ruby/object:Gem::Version
4
4
  prerelease:
5
- version: "0.1"
5
+ version: "0.2"
6
6
  platform: ruby
7
7
  authors:
8
8
  - Juan de Bravo
@@ -10,10 +10,20 @@ autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
12
 
13
- date: 2011-05-10 00:00:00 +02:00
13
+ date: 2011-06-16 00:00:00 +03:00
14
14
  default_executable:
15
- dependencies: []
16
-
15
+ dependencies:
16
+ - !ruby/object:Gem::Dependency
17
+ name: json_pure
18
+ prerelease: false
19
+ requirement: &id001 !ruby/object:Gem::Requirement
20
+ none: false
21
+ requirements:
22
+ - - ">="
23
+ - !ruby/object:Gem::Version
24
+ version: 1.4.3
25
+ type: :runtime
26
+ version_requirements: *id001
17
27
  description: |-
18
28
  O2 Labs has exposed the power of #blue to developers via a
19
29
  simple REST & JSON based API, combined with oAuth2 to developers who can
@@ -33,18 +43,22 @@ files:
33
43
  - LICENSE.LGPLv3
34
44
  - README.md
35
45
  - Rakefile
46
+ - app/controllers/hashblue_controller.rb
47
+ - config/routes.rb
36
48
  - hash-blue.gemspec
37
49
  - lib/hash-blue.rb
38
50
  - lib/hash_blue/account.rb
39
51
  - lib/hash_blue/client.rb
40
52
  - lib/hash_blue/contact.rb
53
+ - lib/hash_blue/engine.rb
54
+ - lib/hash_blue/engine_config.rb
41
55
  - lib/hash_blue/message.rb
42
56
  - lib/hash_blue/version.rb
43
57
  - spec/account_spec.rb
44
58
  - spec/contact_spec.rb
45
59
  - spec/message_spec.rb
46
60
  has_rdoc: true
47
- homepage: https://api.hashblue.com/doc/
61
+ homepage: https://github.com/juandebravo/hash-blue
48
62
  licenses: []
49
63
 
50
64
  post_install_message: