geotrigger 0.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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