geotrigger 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 1681ff89f1fb5fa48cee8fb34b31de586e2ca57b
4
+ data.tar.gz: c4e1f585cc211d2a40e6ddadf9043ae36a831271
5
+ SHA512:
6
+ metadata.gz: a76125f1e937a2a6dffb38e98a966034adc6dab207743c1dc23b091897ec6f7d606ac1841c678a5922dcd0823c142a704ac0a2a56197d5f34b9ddc3fd29c8d2c
7
+ data.tar.gz: cdf2862f6dce564353b9f9f363729a504a75da4f1ae15c6557b1496103d44ac728f040cfe1e304da1eaa9dd1f2b1f845cace0641d3313697f470b8e3d7654f8b
data/.gitignore ADDED
@@ -0,0 +1,3 @@
1
+ Gemfile.lock
2
+ config.yml
3
+ geotrigger-0.0.1.gem
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gem 'httpclient'
4
+ gem 'timecop'
data/README.md ADDED
@@ -0,0 +1,4 @@
1
+ geotrigger-ruby
2
+ ===============
3
+
4
+ a small ruby client for https://developers.arcgis.com/en/geotrigger-service/.
@@ -0,0 +1,18 @@
1
+ # -*- encoding: utf-8 -*-
2
+ require File.expand_path('../lib/geotrigger/version', __FILE__)
3
+
4
+ Gem::Specification.new do |gem|
5
+ gem.authors = ["Kenichi Nakamura"]
6
+ gem.email = ["kenichi.nakamura@gmail.com"]
7
+ gem.description = gem.summary = "A small ruby client for Esri's Geotrigger service"
8
+ gem.homepage = "https://github.com/esripdx/geotrigger-ruby"
9
+ gem.files = `git ls-files | grep -Ev '^(myapp|examples)'`.split("\n")
10
+ gem.test_files = `git ls-files -- spec/*`.split("\n")
11
+ gem.name = "geotrigger"
12
+ gem.require_paths = ["lib"]
13
+ gem.version = Geotrigger::VERSION
14
+ gem.license = 'apache'
15
+
16
+ gem.add_dependency 'httpclient'
17
+ gem.add_development_dependency 'timecop'
18
+ end
data/lib/ext/string.rb ADDED
@@ -0,0 +1,26 @@
1
+ class String
2
+
3
+ alias_method :blank?, :empty?
4
+
5
+ # these are pretty much ripped from:
6
+ # https://github.com/rails/rails/blob/master/activesupport/lib/active_support/inflector/methods.rb
7
+ #
8
+ def camelcase
9
+ string = self.sub(/^(?:(?=\b|[A-Z_])|\w)/) { $&.downcase }
10
+ string.gsub!(/(?:_|(\/))([a-z\d]*)/i) { "#{$1}#{$2.capitalize}" }
11
+ string.gsub!('/', '::')
12
+ string
13
+ end
14
+
15
+ def underscore
16
+ acronym_regex = /(?=a)b/
17
+ word = self.gsub('::', '/')
18
+ word.gsub!(/(?:([A-Za-z\d])|^)(#{acronym_regex})(?=\b|[^a-z])/) { "#{$1}#{$1 && '_'}#{$2.downcase}" }
19
+ word.gsub!(/([A-Z\d]+)([A-Z][a-z])/,'\1_\2')
20
+ word.gsub!(/([a-z\d])([A-Z])/,'\1_\2')
21
+ word.tr!("-", "_")
22
+ word.downcase!
23
+ word
24
+ end
25
+
26
+ end
data/lib/geotrigger.rb ADDED
@@ -0,0 +1,23 @@
1
+ require 'forwardable'
2
+ require 'httpclient'; class HTTPClient; def inspect; to_s; end; end
3
+ require 'json'
4
+
5
+ module Geotrigger
6
+ class AGOError < StandardError; end
7
+ class GeotriggerError < StandardError
8
+ attr_accessor :code, :headers, :message, :params
9
+ end
10
+ end
11
+
12
+ lib = File.expand_path '../..', __FILE__
13
+ $:.push lib unless $:.include? lib
14
+ require 'ext/string'
15
+
16
+ require 'geotrigger/ago/session'
17
+ require 'geotrigger/session'
18
+ require 'geotrigger/model'
19
+
20
+ require 'geotrigger/application'
21
+ require 'geotrigger/device'
22
+ require 'geotrigger/tag'
23
+ require 'geotrigger/trigger'
@@ -0,0 +1,145 @@
1
+ module Geotrigger
2
+ module AGO
3
+ class Session
4
+ extend ::Forwardable
5
+ def_delegators :@impl, :access_token, :access_token=, :ago_data, :device_data, :refresh_token
6
+
7
+ AGO_BASE_URL = (ENV.key?('AGO_BASE_URL') ?
8
+ (ENV['AGO_BASE_URL'] + '%s') :
9
+ 'https://www.arcgis.com/sharing/%s').freeze
10
+
11
+ def initialize opts = {}
12
+ @hc = HTTPClient.new
13
+ @impl = case opts[:type] || :application
14
+ when :application
15
+ Application.new self, opts
16
+ when :device
17
+ Device.new self, opts
18
+ else
19
+ raise ArgumentError 'unknown type'
20
+ end
21
+ end
22
+
23
+ def type
24
+ case @impl
25
+ when Application
26
+ :application
27
+ when Device
28
+ :device
29
+ end
30
+ end
31
+
32
+ # http the specified method to the specified path with the given params.
33
+ # json parse the response body or raise errors.
34
+ #
35
+ def hc meth, path, params
36
+ r = @hc.__send__ meth, AGO_BASE_URL % path, params.merge(f: 'json')
37
+ raise AGOError.new r.body unless r.status == 200
38
+ h = JSON.parse r.body
39
+ raise AGOError.new r.body if h['error']
40
+ h
41
+ end
42
+
43
+ module ExpirySet
44
+
45
+ TOKEN_EXPIRY_BUFFER = 10
46
+
47
+ def wrap_token_retrieval &block
48
+ yield
49
+ expires_at = Time.now.to_i + @ago_data['expires_in']
50
+ @ago_data[:expires_at] = Time.at expires_at - TOKEN_EXPIRY_BUFFER
51
+ @ago_data
52
+ end
53
+
54
+ end
55
+
56
+ class Application
57
+ include ExpirySet
58
+ extend ::Forwardable
59
+ def_delegator :@session, :hc
60
+
61
+ attr_reader :ago_data
62
+
63
+ def initialize session, opts = {}
64
+ @session, @client_id, @client_secret =
65
+ session, opts[:client_id], opts[:client_secret]
66
+ end
67
+
68
+ def access_token
69
+ fetch_access_token if @ago_data.nil? or
70
+ (not @ago_data[:expires_at].nil? and
71
+ Time.now >= @ago_data[:expires_at])
72
+ @ago_data['access_token']
73
+ end
74
+
75
+ private
76
+
77
+ def fetch_access_token
78
+ wrap_token_retrieval do
79
+ @ago_data = hc :post, 'oauth2/token',
80
+ client_id: @client_id,
81
+ client_secret: @client_secret,
82
+ grant_type: 'client_credentials'
83
+ end
84
+ end
85
+
86
+ end
87
+
88
+ class Device
89
+ include ExpirySet
90
+ extend Forwardable
91
+ def_delegator :@session, :hc
92
+
93
+ attr_accessor :refresh_token
94
+ attr_reader :ago_data
95
+
96
+ def initialize session, opts = {}
97
+ @session, @client_id, @refresh_token =
98
+ session, opts[:client_id], opts[:refresh_token]
99
+ end
100
+
101
+ def access_token
102
+ if @ago_data.nil?
103
+ if @refresh_token.nil?
104
+ register
105
+ else
106
+ refresh_access_token
107
+ end
108
+ elsif not @ago_data[:expires_at].nil? and Time.now >= @ago_data[:expires_at]
109
+ refresh_access_token
110
+ end
111
+ @ago_data['access_token']
112
+ end
113
+
114
+ def device_data
115
+ @device_data ||= hc(:get, 'portals/self', token: access_token)['deviceInfo']
116
+ end
117
+
118
+ private
119
+
120
+ def register
121
+ wrap_token_retrieval do
122
+ data = hc :post, 'oauth2/registerDevice', client_id: @client_id, expiration: -1
123
+ @ago_data = {
124
+ 'access_token' => data['deviceToken']['access_token'],
125
+ 'expires_in' => data['deviceToken']['expires_in']
126
+ }
127
+ @device_data = data['device']
128
+ @refresh_token = data['deviceToken']['refresh_token']
129
+ end
130
+ end
131
+
132
+ def refresh_access_token
133
+ wrap_token_retrieval do
134
+ @ago_data = hc :post, 'oauth2/token',
135
+ client_id: @client_id,
136
+ refresh_token: @refresh_token,
137
+ grant_type: 'refresh_token'
138
+ end
139
+ end
140
+
141
+ end
142
+
143
+ end
144
+ end
145
+ end
@@ -0,0 +1,27 @@
1
+ module Geotrigger
2
+
3
+ class Application < Model
4
+
5
+ def permissions
6
+ post 'application/permissions'
7
+ end
8
+
9
+ def permissions= perms
10
+ post 'application/permissions/update', perms
11
+ end
12
+
13
+ def devices params = {}
14
+ post_list 'devices', params
15
+ end
16
+
17
+ def tags params = {}
18
+ post_list 'tags', params
19
+ end
20
+
21
+ def triggers params = {}
22
+ post_list 'triggers', params
23
+ end
24
+
25
+ end
26
+
27
+ end
@@ -0,0 +1,50 @@
1
+ module Geotrigger
2
+
3
+ class Device < Model
4
+ include Taggable
5
+
6
+ def initialize opts = {}
7
+ super opts
8
+ case session.type
9
+ when :application
10
+ if opts[:device_id] and @data.nil?
11
+ grok_self_from post('device/list', deviceIds: opts[:device_id]), opts[:device_id]
12
+ end
13
+ when :device
14
+ if @data.nil?
15
+ grok_self_from post('device/list'), opts[:device_id] || :first
16
+ end
17
+ end
18
+ end
19
+
20
+ def default_tag
21
+ 'device:%s' % deviceId
22
+ end
23
+
24
+ def post_update
25
+ post_data = @data.dup
26
+ case @session.type
27
+ when :application
28
+ post_data['deviceIds'] = post_data.delete 'deviceId'
29
+ when :device
30
+ post_data.delete 'deviceId'
31
+ end
32
+ post_data.delete 'tags'
33
+ post_data.delete 'lastSeen'
34
+
35
+ grok_self_from post 'device/update', post_data
36
+ self
37
+ end
38
+ alias_method :save, :post_update
39
+
40
+ def grok_self_from data, id = nil
41
+ if id == :first
42
+ @data = data['devices'].first
43
+ else
44
+ @data = data['devices'].select {|t| t['deviceId'] == (id || @data['deviceId'])}.first
45
+ end
46
+ end
47
+
48
+ end
49
+
50
+ end
@@ -0,0 +1,84 @@
1
+ module Geotrigger
2
+
3
+ class Model
4
+
5
+ class StateError < StandardError; end
6
+
7
+ extend Forwardable
8
+ def_delegator :@session, :post
9
+
10
+ attr_accessor :data
11
+ attr_reader :session
12
+
13
+ def self.from_api data, session
14
+ i = self.new session: session
15
+ i.data = data
16
+ return i
17
+ end
18
+
19
+ def initialize opts = {}
20
+ @session = opts[:session] || Session.new(opts)
21
+ end
22
+
23
+ def post_list models, params = {}, default_params = {}
24
+ model = models.sub /s$/, ''
25
+ params = default_params.merge params
26
+ post(model + '/list', params)[models].map do |data|
27
+ Geotrigger.const_get(model.capitalize).from_api data, @session
28
+ end
29
+ end
30
+
31
+ def method_missing meth, *args
32
+ meth_s = meth.to_s
33
+ if meth_s =~ /=$/ and args.length == 1
34
+ key = meth_s.sub(/=$/,'').camelcase
35
+ if @data and @data.key? key
36
+ @data[key] = args[0]
37
+ else
38
+ super meth, *args
39
+ end
40
+ else
41
+ key = meth_s.camelcase
42
+ if @data and @data.key? key
43
+ @data[key]
44
+ else
45
+ super meth, *args
46
+ end
47
+ end
48
+ end
49
+
50
+ def == obj
51
+ if Model === obj
52
+ self.data == obj.data
53
+ else
54
+ false
55
+ end
56
+ end
57
+
58
+ module Taggable
59
+
60
+ def tags params = {}
61
+ post_list 'tags', params, tags: @data['tags']
62
+ end
63
+
64
+ def add_tags *names
65
+ @data['addTags'] = names.flatten
66
+ end
67
+
68
+ def remove_tags *names
69
+ names = names.flatten
70
+ raise ArgumentError.new "default tag prohibited" if names.include? default_tag
71
+ @data['removeTags'] = names
72
+ end
73
+
74
+ def tags= *names
75
+ names = names.flatten
76
+ raise ArgumentError.new "default tag required" unless names.include? default_tag
77
+ @data['setTags'] = names
78
+ end
79
+
80
+ end
81
+
82
+ end
83
+
84
+ end
@@ -0,0 +1,57 @@
1
+ module Geotrigger
2
+
3
+ class Session
4
+ extend Forwardable
5
+ def_delegator :@ago, :type
6
+
7
+ BASE_URL = (ENV.key?('GT_BASE_URL') ?
8
+ (ENV['GT_BASE_URL'] + '%s') :
9
+ 'https://geotrigger.arcgis.com/%s').freeze
10
+
11
+ attr_writer :access_token
12
+
13
+ def initialize opts = {}
14
+ @ago = AGO::Session.new opts
15
+ @hc = HTTPClient.new
16
+ end
17
+
18
+ def access_token
19
+ @access_token || @ago.access_token
20
+ end
21
+
22
+ def headers
23
+ {
24
+ 'Content-Type' => 'application/json',
25
+ 'Authorization' => "Bearer #{access_token}"
26
+ }
27
+ end
28
+
29
+ def post path, params = {}
30
+ r = @hc.post BASE_URL % path, params.to_json, headers
31
+ raise GeotriggerError.new r.body unless r.status == 200
32
+ h = JSON.parse r.body
33
+ raise_error h['error'] if h['error']
34
+ h
35
+ end
36
+
37
+ def raise_error error
38
+ ge = GeotriggerError.new error['message']
39
+ ge.code = error['code']
40
+ ge.headers = error['headers']
41
+ ge.message = error['message']
42
+ ge.params = error['params']
43
+ jj error
44
+ raise ge
45
+ end
46
+
47
+ def device?
48
+ type == :device
49
+ end
50
+
51
+ def application?
52
+ type == :application
53
+ end
54
+
55
+ end
56
+
57
+ end
@@ -0,0 +1,47 @@
1
+ module Geotrigger
2
+
3
+ class Tag < Model
4
+
5
+ def self.create session, opts
6
+ t = ::Geotrigger::Tag.new session: session
7
+ t.data = opts
8
+ t.post_create
9
+ end
10
+
11
+ def initialize opts = {}
12
+ super opts
13
+ if opts[:name] and @data.nil?
14
+ grok_self_from post('tag/list', tags: opts[:name]), opts[:name]
15
+ end
16
+ end
17
+
18
+ def triggers params = {}
19
+ post_list 'triggers', params, tags: name
20
+ end
21
+
22
+ def devices params = {}
23
+ post_list 'devices', params, tags: name
24
+ end
25
+
26
+ def post_create
27
+ post_data = @data.dup
28
+ grok_self_from post('tag/permissions', post_data), @data[:tags]
29
+ self
30
+ end
31
+
32
+ def post_update
33
+ raise StateError.new 'device access_token prohibited' if @session.device?
34
+ post_data = @data.dup
35
+ post_data['tags'] = post_data.delete 'name'
36
+ grok_self_from post 'tag/permissions', post_data
37
+ self
38
+ end
39
+ alias_method :save, :post_update
40
+
41
+ def grok_self_from data, name = nil
42
+ @data = data['tags'].select {|t| t['name'] == (name || @data['name'])}.first
43
+ end
44
+
45
+ end
46
+
47
+ end
@@ -0,0 +1,45 @@
1
+ module Geotrigger
2
+
3
+ class Trigger < Model
4
+ include Taggable
5
+
6
+ def self.create session, opts
7
+ t = Trigger.new session: session
8
+ t.data = opts
9
+ t.post_create
10
+ end
11
+
12
+ def initialize opts = {}
13
+ super opts
14
+ if opts[:trigger_id] and @data.nil?
15
+ grok_self_from post('trigger/list', triggerIds: opts[:trigger_id]), opts[:trigger_id]
16
+ end
17
+ end
18
+
19
+ def default_tag
20
+ 'trigger:%s' % triggerId
21
+ end
22
+
23
+ def post_create
24
+ post_data = @data.dup
25
+ @data = post 'trigger/create', post_data
26
+ self
27
+ end
28
+
29
+ def post_update opts = {}
30
+ post_data = @data.dup
31
+ post_data['triggerIds'] = post_data.delete 'triggerId'
32
+ post_data.delete 'tags'
33
+
34
+ grok_self_from post 'trigger/update', post_data.merge(opts)
35
+ self
36
+ end
37
+ alias_method :save, :post_update
38
+
39
+ def grok_self_from data, id = nil
40
+ @data = data['triggers'].select {|t| t['triggerId'] == (id || @data['triggerId'])}.first
41
+ end
42
+
43
+ end
44
+
45
+ end
@@ -0,0 +1,3 @@
1
+ module Geotrigger
2
+ VERSION = '0.0.2'
3
+ end
@@ -0,0 +1,3 @@
1
+ :client_id: xxx
2
+ :client_secret: yyy
3
+ :refresh_token: zzz
@@ -0,0 +1,61 @@
1
+ require_relative '../helper'
2
+
3
+ describe Geotrigger::Application do
4
+
5
+ PERMS = 'deviceList',
6
+ 'deviceLocation',
7
+ 'deviceTagging',
8
+ 'deviceToken',
9
+ 'discoverableDevice',
10
+ 'discoverableApplication',
11
+ 'triggerApply',
12
+ 'triggerDelete',
13
+ 'triggerHistory',
14
+ 'triggerList',
15
+ 'triggerUpdate'
16
+
17
+ let :app do
18
+ Geotrigger::Application.new client_id: CONF[:client_id],
19
+ client_secret: CONF[:client_secret]
20
+ end
21
+
22
+ it 'fetches permissions' do
23
+ ps = app.permissions
24
+ ps.should_not be nil
25
+ ps.should be_a Hash
26
+ ps.keys.should include *PERMS
27
+ end
28
+
29
+ it 'sets permissions' do
30
+ PERMS.each do |p|
31
+ ps = app.permissions
32
+ _ps = ps.merge p => !ps[p]
33
+ app.permissions = _ps
34
+ __ps = app.permissions
35
+ __ps.should eq ps.merge(p => !ps[p])
36
+ app.permissions = ps
37
+ end
38
+ end
39
+
40
+ it 'fetches devices' do
41
+ ds = app.devices
42
+ ds.should_not be nil
43
+ ds.should be_a Array
44
+ ds.first.should be_a Geotrigger::Device unless ds.empty?
45
+ end
46
+
47
+ it 'fetches tags' do
48
+ ts = app.tags
49
+ ts.should_not be nil
50
+ ts.should be_a Array
51
+ ts.first.should be_a Geotrigger::Tag unless ts.empty?
52
+ end
53
+
54
+ it 'fetches triggers' do
55
+ ts = app.triggers
56
+ ts.should_not be nil
57
+ ts.should be_a Array
58
+ ts.first.should be_a Geotrigger::Trigger unless ts.empty?
59
+ end
60
+
61
+ end
@@ -0,0 +1,81 @@
1
+ require_relative '../helper'
2
+
3
+ describe Geotrigger::Device do
4
+
5
+ let :dev do
6
+ s = GT::AGO::Session.new client_id: CONF[:client_id],
7
+ type: :device
8
+
9
+ # can't use this because GT doesn't know it yet
10
+ #
11
+ ago_did = s.device_data['deviceId']
12
+
13
+ # make a call to GT so it learns of new device
14
+ #
15
+ at = s.access_token
16
+ r = HTTPClient.new.get Geotrigger::Session::BASE_URL % 'device/list',
17
+ nil,
18
+ 'Authorization' => "Bearer #{at}"
19
+
20
+ gt_did = JSON.parse(r.body)['devices'][0]['deviceId']
21
+
22
+ # assert ids are the same
23
+ #
24
+ ago_did.should eq gt_did
25
+
26
+ GT::Device.new client_id: CONF[:client_id],
27
+ client_secret: CONF[:client_secret],
28
+ device_id: ago_did
29
+ end
30
+
31
+ it 'fetches tags' do
32
+ ts = dev.tags
33
+ ts.should_not be nil
34
+ ts.should be_a Array
35
+ ts.first.should be_a GT::Tag
36
+ ts.first.name.should eq dev.default_tag
37
+ end
38
+
39
+ it 'knows the default tag' do
40
+ dev.default_tag =~ /^device:\S+$/
41
+ end
42
+
43
+ it 'updates' do
44
+ dev.properties = {'foo' => 'bar'}
45
+ dev.trackingProfile = 'adaptive'
46
+ dev.save
47
+ dev.properties.should eq({'foo' => 'bar'})
48
+ dev.trackingProfile.should eq 'adaptive'
49
+ end
50
+
51
+ it 'adds tags' do
52
+ ts = dev.tags
53
+ ts.length.should eq 1
54
+ dev.add_tags 'foo', 'bar'
55
+ dev.save
56
+ ts = dev.tags
57
+ ts.length.should eq 3
58
+ end
59
+
60
+ it 'sets tags' do
61
+ ts = dev.tags
62
+ ts.length.should eq 1
63
+ dev.tags = dev.default_tag, 'fu', 'bat'
64
+ dev.save
65
+ ts = dev.tags
66
+ ts.length.should eq 3
67
+ end
68
+
69
+ it 'removes tags' do
70
+ dev.tags = dev.default_tag, 'fizz', 'buzz'
71
+ dev.save
72
+ sleep 3
73
+ ts = dev.tags
74
+ ts.length.should eq 3
75
+ dev.remove_tags 'fizz', 'buzz'
76
+ dev.save
77
+ ts = dev.tags
78
+ ts.length.should eq 1
79
+ end
80
+
81
+ end
@@ -0,0 +1,108 @@
1
+ require_relative '../helper'
2
+
3
+ describe Geotrigger::AGO::Session do
4
+
5
+ def session_should_be_ok agos
6
+ agos.access_token.should_not be nil
7
+ agos.ago_data.should_not be nil
8
+ agos.ago_data.keys.should include 'access_token', 'expires_in', :expires_at
9
+ (agos.ago_data[:expires_at] > Time.now).should be true
10
+ end
11
+
12
+ it 'fetches an access token for client credentials' do
13
+ session_should_be_ok Geotrigger::AGO::Session.new client_id: CONF[:client_id],
14
+ client_secret: CONF[:client_secret]
15
+ end
16
+
17
+ it 'fetches access and refresh tokens for client id' do
18
+ session_should_be_ok Geotrigger::AGO::Session.new client_id: CONF[:client_id],
19
+ type: :device
20
+ end
21
+
22
+ it 'fetches access token for client id and refresh token' do
23
+ session_should_be_ok Geotrigger::AGO::Session.new client_id: CONF[:client_id],
24
+ refresh_token: CONF[:refresh_token],
25
+ type: :device
26
+ end
27
+
28
+ it 'updates an expired access token with client credentials' do
29
+ agos = Geotrigger::AGO::Session.new client_id: CONF[:client_id],
30
+ client_secret: CONF[:client_secret]
31
+ at = agos.access_token
32
+ Timecop.travel agos.ago_data[:expires_at] do
33
+ _at = agos.access_token
34
+ session_should_be_ok agos
35
+ at.should_not eq _at
36
+ end
37
+ end
38
+
39
+ it 'updates an expired access token without given refresh token' do
40
+ agos = Geotrigger::AGO::Session.new client_id: CONF[:client_id],
41
+ type: :device
42
+ at = agos.access_token
43
+ Timecop.travel agos.ago_data[:expires_at] do
44
+ _at = agos.access_token
45
+ session_should_be_ok agos
46
+ at.should_not eq _at
47
+ end
48
+ end
49
+
50
+ it 'updates an expired access token given refresh token' do
51
+ agos = Geotrigger::AGO::Session.new client_id: CONF[:client_id],
52
+ refresh_token: CONF[:refresh_token],
53
+ type: :device
54
+ at = agos.access_token
55
+ Timecop.travel agos.ago_data[:expires_at] do
56
+ _at = agos.access_token
57
+ session_should_be_ok agos
58
+ at.should_not eq _at
59
+ end
60
+ end
61
+
62
+ end
63
+
64
+ describe Geotrigger::Session do
65
+
66
+ it 'fetches an access token for client credentials' do
67
+ s = Geotrigger::Session.new client_id: CONF[:client_id],
68
+ client_secret: CONF[:client_secret]
69
+ s.access_token.should_not be nil
70
+ end
71
+
72
+ it 'fetches an access token for client id' do
73
+ s = Geotrigger::Session.new client_id: CONF[:client_id],
74
+ type: :device
75
+ s.access_token.should_not be nil
76
+ end
77
+
78
+ it 'uses a given access token' do
79
+ s = Geotrigger::Session.new client_id: CONF[:client_id],
80
+ client_secret: CONF[:client_secret]
81
+ s.access_token = 'foo'
82
+ s.access_token.should eq 'foo'
83
+ end
84
+
85
+ it 'uses a given refresh token' do
86
+ s = Geotrigger::Session.new client_id: CONF[:client_id],
87
+ refresh_token: CONF[:refresh_token],
88
+ type: :device
89
+ s.access_token.should_not be nil
90
+ end
91
+
92
+ it 'knows what type it is' do
93
+ s = Geotrigger::Session.new client_id: CONF[:client_id],
94
+ client_secret: CONF[:client_secret]
95
+ s.application?.should be true
96
+ s.device?.should be false
97
+ s = Geotrigger::Session.new client_id: CONF[:client_id],
98
+ type: :device
99
+ s.application?.should be false
100
+ s.device?.should be true
101
+ end
102
+
103
+ it 'raises errors correctly' do
104
+ s = Geotrigger::Session.new
105
+ ->{ s.post 'application/permissions' }.should raise_error
106
+ end
107
+
108
+ end
@@ -0,0 +1,106 @@
1
+ require_relative '../helper'
2
+
3
+ describe Geotrigger::Tag do
4
+
5
+ TAG_PERMS = 'deviceList',
6
+ 'deviceLocation',
7
+ 'deviceTagging',
8
+ 'deviceToken',
9
+ 'discoverable',
10
+ 'triggerApply',
11
+ 'triggerDelete',
12
+ 'triggerHistory',
13
+ 'triggerList',
14
+ 'triggerUpdate'
15
+
16
+ let :session do
17
+ Geotrigger::Session.new client_id: CONF[:client_id],
18
+ client_secret: CONF[:client_secret]
19
+ end
20
+
21
+ let :tag do
22
+ GT::Tag.create session, tags: "foo#{Time.now.to_i}"
23
+ end
24
+
25
+ let :dev do
26
+ s = GT::AGO::Session.new client_id: CONF[:client_id],
27
+ type: :device
28
+
29
+ # can't use this because GT doesn't know it yet
30
+ #
31
+ ago_did = s.device_data['deviceId']
32
+
33
+ # make a call to GT so it learns of new device
34
+ #
35
+ at = s.access_token
36
+ r = HTTPClient.new.get Geotrigger::Session::BASE_URL % 'device/list',
37
+ nil,
38
+ 'Authorization' => "Bearer #{at}"
39
+
40
+ gt_did = JSON.parse(r.body)['devices'][0]['deviceId']
41
+
42
+ # assert ids are the same
43
+ #
44
+ ago_did.should eq gt_did
45
+
46
+ GT::Device.new client_id: CONF[:client_id],
47
+ client_secret: CONF[:client_secret],
48
+ device_id: ago_did
49
+ end
50
+
51
+ let :trigger_opts do
52
+ {
53
+ 'condition' => {
54
+ 'direction' => 'enter',
55
+ 'geo' => {
56
+ 'latitude' => 45.5165,
57
+ 'longitude' => -122.6764,
58
+ 'distance' => 100
59
+ }
60
+ },
61
+ 'action' => {
62
+ 'trackingProfile' => 'adaptive'
63
+ }
64
+ }
65
+ end
66
+
67
+ let :trigger do
68
+ GT::Trigger.create session, trigger_opts
69
+ end
70
+
71
+ it 'creates a tag' do
72
+ t = tag
73
+ t.name.should match /^foo/
74
+ TAG_PERMS.each {|p| t.__send__(p).should_not be nil}
75
+ end
76
+
77
+ it 'fetches triggers' do
78
+ t = tag
79
+ trig = trigger
80
+ trig.add_tags t.name
81
+ trig.save
82
+ t.triggers.first.data.should eq trig.data
83
+ end
84
+
85
+ it 'fetches devices' do
86
+ t = tag
87
+ d = dev
88
+ d.add_tags t.name
89
+ d.save
90
+ t.devices.first.device_id.should eq d.device_id
91
+ end
92
+
93
+ it 'updates permissions' do
94
+ t = tag
95
+ t.name.should match /^foo/
96
+ t_data = t.data.dup
97
+ TAG_PERMS.each do |p|
98
+ t.data[p] = !t_data[p]
99
+ doid = t.data.object_id
100
+ t.save
101
+ t.data.object_id.should_not eq doid
102
+ t.data[p].should eq !t_data[p]
103
+ end
104
+ end
105
+
106
+ end
@@ -0,0 +1,88 @@
1
+ require_relative '../helper'
2
+
3
+ describe Geotrigger::Trigger do
4
+
5
+ let :session do
6
+ Geotrigger::Session.new client_id: CONF[:client_id],
7
+ client_secret: CONF[:client_secret]
8
+ end
9
+
10
+ let :opts do
11
+ {
12
+ 'condition' => {
13
+ 'direction' => 'enter',
14
+ 'geo' => {
15
+ 'latitude' => 45.5165,
16
+ 'longitude' => -122.6764,
17
+ 'distance' => 100
18
+ }
19
+ },
20
+ 'action' => {
21
+ 'trackingProfile' => 'adaptive'
22
+ }
23
+ }
24
+ end
25
+
26
+ let :trigger do
27
+ GT::Trigger.create session, opts
28
+ end
29
+
30
+ it 'should create a trigger' do
31
+ t = trigger
32
+ t.trigger_id.should_not be nil
33
+ t.condition.should eq opts['condition']
34
+ t.action.should eq opts['action']
35
+ end
36
+
37
+ it 'fetches tags' do
38
+ ts = trigger.tags
39
+ ts.should_not be nil
40
+ ts.should be_a Array
41
+ ts.first.should be_a GT::Tag
42
+ ts.first.name.should eq trigger.default_tag
43
+ end
44
+
45
+ it 'knows the default tag' do
46
+ trigger.default_tag =~ /^trigger:\S+$/
47
+ end
48
+
49
+ it 'updates' do
50
+ trigger.properties = {'foo' => 'bar'}
51
+ trigger.action['trackingProfile'] = 'adaptive'
52
+ trigger.save
53
+ trigger.properties.should eq({'foo' => 'bar'})
54
+ trigger.action['trackingProfile'].should eq 'adaptive'
55
+ end
56
+
57
+ it 'adds tags' do
58
+ ts = trigger.tags
59
+ ts.length.should eq 1
60
+ trigger.add_tags 'foo', 'bar'
61
+ trigger.save
62
+ ts = trigger.tags
63
+ ts.length.should eq 3
64
+ end
65
+
66
+ it 'sets tags' do
67
+ ts = trigger.tags
68
+ ts.length.should eq 1
69
+ trigger.tags = trigger.default_tag, 'fu', 'bat'
70
+ trigger.save
71
+ ts = trigger.tags
72
+ ts.length.should eq 3
73
+ end
74
+
75
+ it 'removes tags' do
76
+ trigger.tags = trigger.default_tag, 'fizz', 'buzz'
77
+ trigger.save
78
+ sleep 3
79
+ ts = trigger.tags
80
+ ts.length.should eq 3
81
+ trigger.remove_tags 'fizz', 'buzz'
82
+ trigger.save
83
+ ts = trigger.tags
84
+ ts.length.should eq 1
85
+ end
86
+
87
+
88
+ end
data/spec/helper.rb ADDED
@@ -0,0 +1,8 @@
1
+ lib = File.expand_path '../..', __FILE__
2
+ $:.unshift lib unless $:.include? lib
3
+
4
+ require 'yaml'
5
+ CONF = YAML.load_file File.expand_path '../config.yml', __FILE__
6
+
7
+ require 'timecop'
8
+ require 'geotrigger'
metadata ADDED
@@ -0,0 +1,100 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: geotrigger
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.2
5
+ platform: ruby
6
+ authors:
7
+ - Kenichi Nakamura
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2013-11-26 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: httpclient
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - '>='
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - '>='
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: timecop
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - '>='
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - '>='
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ description: A small ruby client for Esri's Geotrigger service
42
+ email:
43
+ - kenichi.nakamura@gmail.com
44
+ executables: []
45
+ extensions: []
46
+ extra_rdoc_files: []
47
+ files:
48
+ - .gitignore
49
+ - Gemfile
50
+ - README.md
51
+ - geotrigger.gemspec
52
+ - lib/ext/string.rb
53
+ - lib/geotrigger.rb
54
+ - lib/geotrigger/ago/session.rb
55
+ - lib/geotrigger/application.rb
56
+ - lib/geotrigger/device.rb
57
+ - lib/geotrigger/model.rb
58
+ - lib/geotrigger/session.rb
59
+ - lib/geotrigger/tag.rb
60
+ - lib/geotrigger/trigger.rb
61
+ - lib/geotrigger/version.rb
62
+ - spec/config.yml.example
63
+ - spec/geotrigger/application_spec.rb
64
+ - spec/geotrigger/device_spec.rb
65
+ - spec/geotrigger/geotrigger_spec.rb
66
+ - spec/geotrigger/tag_spec.rb
67
+ - spec/geotrigger/trigger_spec.rb
68
+ - spec/helper.rb
69
+ homepage: https://github.com/esripdx/geotrigger-ruby
70
+ licenses:
71
+ - apache
72
+ metadata: {}
73
+ post_install_message:
74
+ rdoc_options: []
75
+ require_paths:
76
+ - lib
77
+ required_ruby_version: !ruby/object:Gem::Requirement
78
+ requirements:
79
+ - - '>='
80
+ - !ruby/object:Gem::Version
81
+ version: '0'
82
+ required_rubygems_version: !ruby/object:Gem::Requirement
83
+ requirements:
84
+ - - '>='
85
+ - !ruby/object:Gem::Version
86
+ version: '0'
87
+ requirements: []
88
+ rubyforge_project:
89
+ rubygems_version: 2.0.3
90
+ signing_key:
91
+ specification_version: 4
92
+ summary: A small ruby client for Esri's Geotrigger service
93
+ test_files:
94
+ - spec/config.yml.example
95
+ - spec/geotrigger/application_spec.rb
96
+ - spec/geotrigger/device_spec.rb
97
+ - spec/geotrigger/geotrigger_spec.rb
98
+ - spec/geotrigger/tag_spec.rb
99
+ - spec/geotrigger/trigger_spec.rb
100
+ - spec/helper.rb