ruby_desk 0.4.1 → 0.5.0
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.
- data/README.rdoc +4 -0
- data/VERSION +1 -1
- data/lib/ruby_desk/connector.rb +29 -9
- data/lib/ruby_desk/provider.rb +3 -5
- data/lib/ruby_desk/snapshot.rb +2 -6
- data/lib/ruby_desk/team_room.rb +4 -5
- data/lib/ruby_desk/time_report.rb +7 -4
- data/lib/ruby_desk.rb +10 -0
- data/test/test_ruby_desk.rb +27 -24
- data/test/timereport_error.json +2 -0
- metadata +3 -2
data/README.rdoc
CHANGED
@@ -2,6 +2,10 @@
|
|
2
2
|
|
3
3
|
A gem built by BadrIT (www.badrit.com) that works as an interface for oDesk APIs. It can be used for both desktop and web applications
|
4
4
|
|
5
|
+
== Using RubyDesk with Rails
|
6
|
+
If you want to use oDesk APIs with Rails applications you may better use ror_desk.
|
7
|
+
ror_desk is a plugin built on Ruby Desk and makes it much easier to use with Rails.
|
8
|
+
|
5
9
|
== Example
|
6
10
|
Initialize with your api key
|
7
11
|
rd = RubyDesk::Connector.new(api_key, api_secret)
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.5.0
|
data/lib/ruby_desk/connector.rb
CHANGED
@@ -2,6 +2,8 @@ require 'digest/md5'
|
|
2
2
|
require 'uri'
|
3
3
|
require 'net/http'
|
4
4
|
require 'net/https'
|
5
|
+
require 'rexml/document'
|
6
|
+
require 'json'
|
5
7
|
|
6
8
|
module RubyDesk
|
7
9
|
class Connector
|
@@ -22,6 +24,7 @@ module RubyDesk
|
|
22
24
|
|
23
25
|
# Sign the given parameters and returns the signature
|
24
26
|
def sign(params)
|
27
|
+
RubyDesk.logger.info "Params to sign: #{params.inspect}"
|
25
28
|
# sort parameters by its names (keys)
|
26
29
|
sorted_params = params.sort { |a, b| a.to_s <=> b.to_s}
|
27
30
|
|
@@ -65,6 +68,10 @@ module RubyDesk
|
|
65
68
|
'Content-Type' => 'application/x-www-form-urlencoded'
|
66
69
|
}
|
67
70
|
|
71
|
+
RubyDesk.logger.info "URL: #{api_call[:url]}"
|
72
|
+
RubyDesk.logger.info "method: #{api_call[:method]}"
|
73
|
+
RubyDesk.logger.info "Params: #{data}"
|
74
|
+
|
68
75
|
case api_call[:method]
|
69
76
|
when :get, 'get' then
|
70
77
|
resp, data = http.request(Net::HTTP::Get.new(url.path+"?"+data, headers))
|
@@ -74,13 +81,29 @@ module RubyDesk
|
|
74
81
|
resp, data = http.request(Net::HTTP::Delete.new(url.path, headers), data)
|
75
82
|
end
|
76
83
|
|
77
|
-
|
84
|
+
RubyDesk.logger.info "Response code: #{resp.code}"
|
85
|
+
RubyDesk.logger.info "Returned data: #{data}"
|
86
|
+
|
87
|
+
case resp.code
|
88
|
+
when "200" then return data
|
89
|
+
when "401" then raise RubyDesk::UnauthorizedError, data
|
90
|
+
when "500" then raise RubyDesk::ServerError, data
|
91
|
+
end
|
92
|
+
|
78
93
|
end
|
79
94
|
|
80
95
|
# Prepares an API call with the given arguments then invokes it and returns its body
|
81
96
|
def prepare_and_invoke_api_call(path, options = {})
|
82
97
|
api_call = prepare_api_call(path, options)
|
83
|
-
invoke_api_call(api_call)
|
98
|
+
data = invoke_api_call(api_call)
|
99
|
+
|
100
|
+
parsed_data = case options[:format]
|
101
|
+
when 'json' then JSON.parse(data)
|
102
|
+
when 'xml' then REXML::Document.new(data)
|
103
|
+
else JSON.parse(data) rescue REXML::Document.new(data) rescue data
|
104
|
+
end
|
105
|
+
RubyDesk.logger.info "Parsed data: #{parsed_data.inspect}"
|
106
|
+
return parsed_data
|
84
107
|
end
|
85
108
|
|
86
109
|
# Returns the URL that authenticates the application for the current user
|
@@ -107,10 +130,9 @@ module RubyDesk
|
|
107
130
|
# Return Data
|
108
131
|
# * token
|
109
132
|
def get_token
|
110
|
-
|
133
|
+
json = prepare_and_invoke_api_call 'auth/v1/keys/tokens',
|
111
134
|
:params=>{:frob=>@frob, :api_key=>@api_key}, :method=>:post,
|
112
135
|
:auth=>false
|
113
|
-
json = JSON.parse(response)
|
114
136
|
@api_token = json['token']
|
115
137
|
end
|
116
138
|
|
@@ -123,9 +145,8 @@ module RubyDesk
|
|
123
145
|
# * frob
|
124
146
|
|
125
147
|
def get_frob
|
126
|
-
|
148
|
+
json = prepare_and_invoke_api_call 'auth/v1/keys/frobs',
|
127
149
|
:params=>{:api_key=>@api_key}, :method=>:post, :auth=>false
|
128
|
-
json = JSON.parse(response)
|
129
150
|
@frob = json['frob']
|
130
151
|
end
|
131
152
|
|
@@ -140,9 +161,8 @@ module RubyDesk
|
|
140
161
|
#
|
141
162
|
# * token
|
142
163
|
def check_token
|
143
|
-
prepare_and_invoke_api_call 'auth/v1/keys/token', :method=>:get
|
144
|
-
|
145
|
-
# TODO what to make with results?
|
164
|
+
json = prepare_and_invoke_api_call 'auth/v1/keys/token', :method=>:get
|
165
|
+
# TODO what to do with results?
|
146
166
|
return json
|
147
167
|
end
|
148
168
|
|
data/lib/ruby_desk/provider.rb
CHANGED
@@ -116,11 +116,10 @@ class RubyDesk::Provider < RubyDesk::OdeskEntity
|
|
116
116
|
if options.respond_to? :to_str
|
117
117
|
return search(connector, :q=>options.to_str)
|
118
118
|
end
|
119
|
-
|
119
|
+
json = connector.prepare_and_invoke_api_call(
|
120
120
|
'profiles/v1/search/providers', :method=>:get,
|
121
121
|
:auth=>false, :sign=>false)
|
122
|
-
|
123
|
-
json = JSON.parse(response)
|
122
|
+
|
124
123
|
providers = []
|
125
124
|
[json['providers']['provider']].flatten.each do |provider|
|
126
125
|
providers << self.new(provider)
|
@@ -130,9 +129,8 @@ class RubyDesk::Provider < RubyDesk::OdeskEntity
|
|
130
129
|
|
131
130
|
def get_profile(connector, id, options={})
|
132
131
|
brief = options.delete :brief || false
|
133
|
-
|
132
|
+
json = connector.prepare_and_invoke_api_call(
|
134
133
|
"profiles/v1/providers/#{id}" + (brief ? "/brief" : ""), :method=>:get)
|
135
|
-
json = JSON.parse(response)
|
136
134
|
return self.new(json['profile'])
|
137
135
|
end
|
138
136
|
end
|
data/lib/ruby_desk/snapshot.rb
CHANGED
@@ -9,10 +9,9 @@ class RubyDesk::Snapshot < RubyDesk::OdeskEntity
|
|
9
9
|
attribute :user, :class=>RubyDesk::User
|
10
10
|
|
11
11
|
def self.work_diary(connector, company_id, user_id, date = nil, timezone = "mine")
|
12
|
-
|
12
|
+
json = connector.prepare_and_invoke_api_call(
|
13
13
|
"team/v1/workdiaries/#{company_id}/#{user_id}" + (date ? "/"+date : ""),
|
14
14
|
:params=>{:timezone=>timezone}, :method=>:get)
|
15
|
-
json = JSON.parse(response)
|
16
15
|
|
17
16
|
return nil unless json['snapshots']['snapshot']
|
18
17
|
[json['snapshots']['snapshot']].flatten.map do |snapshot|
|
@@ -28,13 +27,10 @@ class RubyDesk::Snapshot < RubyDesk::OdeskEntity
|
|
28
27
|
when Array then timestamp.map{|t| t.strftime("%Y%m%d")}.join(";")
|
29
28
|
end
|
30
29
|
# Invoke API call
|
31
|
-
|
30
|
+
json = connector.prepare_and_invoke_api_call(
|
32
31
|
"team/v1/workdiaries/#{company_id}/#{user_id}" +
|
33
32
|
(timestamp_param ? "/#{timestamp_param}" : ""), :method=>:get)
|
34
33
|
|
35
|
-
# Parse result in json format
|
36
|
-
json = JSON.parse(response)
|
37
|
-
|
38
34
|
# Generate ruby objects for each snapshot
|
39
35
|
[json['snapshot']].flatten.map do |snapshot|
|
40
36
|
self.new(snapshot)
|
data/lib/ruby_desk/team_room.rb
CHANGED
@@ -4,10 +4,9 @@ class RubyDesk::TeamRoom
|
|
4
4
|
|
5
5
|
class << self
|
6
6
|
def get_teamrooms(connector)
|
7
|
-
|
7
|
+
json = connector.prepare_and_invoke_api_call 'team/v1/teamrooms',
|
8
8
|
:method=>:get
|
9
|
-
|
10
|
-
json = JSON.parse(response)
|
9
|
+
|
11
10
|
team_rooms = []
|
12
11
|
[json['teamrooms']['teamroom']].flatten.each do |teamroom|
|
13
12
|
# Append this TeamRoom to array
|
@@ -28,9 +27,9 @@ class RubyDesk::TeamRoom
|
|
28
27
|
end
|
29
28
|
|
30
29
|
def snapshot(connector, online='now')
|
31
|
-
|
30
|
+
json = connector.prepare_and_invoke_api_call "team/v1/teamrooms/#{self.id}",
|
32
31
|
:params=>{:online=>online}, :method=>:get
|
33
|
-
|
32
|
+
|
34
33
|
RubyDesk::Snapshot.new(json['teamroom']['snapshot'])
|
35
34
|
end
|
36
35
|
|
@@ -54,11 +54,12 @@ class RubyDesk::TimeReport
|
|
54
54
|
call_url << "/hours" if options[:hours]
|
55
55
|
|
56
56
|
gds_query = build_query(options)
|
57
|
-
|
57
|
+
json = connector.prepare_and_invoke_api_call(call_url, :method=>:get,
|
58
58
|
:base_url=>RubyDesk::Connector::ODESK_GDS_URL, :format=>nil,
|
59
59
|
:params=>{:tq=>URI.escape(gds_query," ,%&=./"), :tqx=>"out:json"})
|
60
60
|
|
61
|
-
json
|
61
|
+
raise RubyDesk::Error, json['errors'].inspect if json['status'] == "error"
|
62
|
+
|
62
63
|
columns = [json['table']['cols']].flatten
|
63
64
|
rows = [json['table']['rows']].flatten.map do |row_data|
|
64
65
|
row = {}
|
@@ -73,7 +74,8 @@ class RubyDesk::TimeReport
|
|
73
74
|
|
74
75
|
def self.build_query(options)
|
75
76
|
gds_query = ""
|
76
|
-
gds_query << "SELECT " << options[:select]
|
77
|
+
gds_query << "SELECT " << (options[:select].respond_to?(:join)?
|
78
|
+
options[:select].join(",") : options[:select])
|
77
79
|
if options[:conditions]
|
78
80
|
gds_query << " WHERE "
|
79
81
|
combined = options[:conditions].map do |field, condition|
|
@@ -83,10 +85,11 @@ class RubyDesk::TimeReport
|
|
83
85
|
"#{field}=#{value_to_str(condition)}"
|
84
86
|
when Array then
|
85
87
|
condition.map{|v| "#{field}=#{value_to_str(v)}"}.join(" OR ")
|
86
|
-
when Range
|
88
|
+
when Range then
|
87
89
|
"#{field}>=#{value_to_str(condition.first)} AND #{field}" +
|
88
90
|
(condition.exclude_end? ? "<" : "<=") +
|
89
91
|
value_to_str(condition.last)
|
92
|
+
else raise "Invalid condition for field: #{field}"
|
90
93
|
end +
|
91
94
|
")"
|
92
95
|
end
|
data/lib/ruby_desk.rb
CHANGED
@@ -1,8 +1,18 @@
|
|
1
1
|
require 'rubygems'
|
2
2
|
require 'json'
|
3
|
+
require 'logger'
|
3
4
|
|
4
5
|
module RubyDesk
|
5
6
|
class Error < RuntimeError; end;
|
7
|
+
class UnauthorizedError < Error; end;
|
8
|
+
class ServerError < Error; end;
|
9
|
+
|
10
|
+
class << self
|
11
|
+
attr_accessor :logger
|
12
|
+
end
|
13
|
+
|
14
|
+
self.logger = Logger.new(STDERR)
|
15
|
+
self.logger.sev_threshold = Logger::FATAL
|
6
16
|
end
|
7
17
|
|
8
18
|
# This first file is required by other files
|
data/test/test_ruby_desk.rb
CHANGED
@@ -2,6 +2,17 @@ require 'helper'
|
|
2
2
|
require 'date'
|
3
3
|
|
4
4
|
class TestRubyDesk < Test::Unit::TestCase
|
5
|
+
|
6
|
+
def dummy_connector(result_filename)
|
7
|
+
connector = RubyDesk::Connector.new('824d225a889aca186c55ac49a6b23957',
|
8
|
+
'984aa36db13fff5c')
|
9
|
+
connector.instance_variable_set '@result_filename', result_filename
|
10
|
+
def connector.invoke_api_call(*args)
|
11
|
+
File.read(File.join(File.dirname(__FILE__), @result_filename))
|
12
|
+
end if result_filename
|
13
|
+
return connector
|
14
|
+
end
|
15
|
+
|
5
16
|
def test_sign
|
6
17
|
connector = RubyDesk::Connector.new('824d225a889aca186c55ac49a6b23957',
|
7
18
|
'984aa36db13fff5c')
|
@@ -32,10 +43,7 @@ class TestRubyDesk < Test::Unit::TestCase
|
|
32
43
|
end
|
33
44
|
|
34
45
|
def test_provider_search
|
35
|
-
connector =
|
36
|
-
def connector.prepare_and_invoke_api_call(*args)
|
37
|
-
File.read(File.join(File.dirname(__FILE__), 'providers.json'))
|
38
|
-
end
|
46
|
+
connector = dummy_connector('providers.json')
|
39
47
|
|
40
48
|
providers = RubyDesk::Provider.search(connector, 'rails')
|
41
49
|
|
@@ -46,10 +54,7 @@ class TestRubyDesk < Test::Unit::TestCase
|
|
46
54
|
end
|
47
55
|
|
48
56
|
def test_get_profile
|
49
|
-
connector =
|
50
|
-
def connector.prepare_and_invoke_api_call(*args)
|
51
|
-
File.read(File.join(File.dirname(__FILE__), 'profile.json'))
|
52
|
-
end
|
57
|
+
connector = dummy_connector('profile.json')
|
53
58
|
|
54
59
|
profile = RubyDesk::Provider.get_profile(connector, 'aseldawy')
|
55
60
|
|
@@ -59,10 +64,7 @@ class TestRubyDesk < Test::Unit::TestCase
|
|
59
64
|
end
|
60
65
|
|
61
66
|
def test_team_rooms
|
62
|
-
connector =
|
63
|
-
def connector.prepare_and_invoke_api_call(*args)
|
64
|
-
File.read(File.join(File.dirname(__FILE__), 'teamrooms.json'))
|
65
|
-
end
|
67
|
+
connector = dummy_connector('teamrooms.json')
|
66
68
|
|
67
69
|
teamrooms = RubyDesk::TeamRoom.get_teamrooms(connector)
|
68
70
|
|
@@ -71,10 +73,7 @@ class TestRubyDesk < Test::Unit::TestCase
|
|
71
73
|
end
|
72
74
|
|
73
75
|
def test_workdiary
|
74
|
-
connector =
|
75
|
-
def connector.prepare_and_invoke_api_call(*args)
|
76
|
-
File.read(File.join(File.dirname(__FILE__), 'workdiary.json'))
|
77
|
-
end
|
76
|
+
connector = dummy_connector('workdiary.json')
|
78
77
|
|
79
78
|
snapshots = RubyDesk::Snapshot.work_diary(connector, 'techunlimited',
|
80
79
|
'aseldawy')
|
@@ -83,10 +82,7 @@ class TestRubyDesk < Test::Unit::TestCase
|
|
83
82
|
end
|
84
83
|
|
85
84
|
def test_snapshot
|
86
|
-
connector =
|
87
|
-
def connector.prepare_and_invoke_api_call(*args)
|
88
|
-
File.read(File.join(File.dirname(__FILE__), 'snapshot.json'))
|
89
|
-
end
|
85
|
+
connector = dummy_connector('snapshot.json')
|
90
86
|
|
91
87
|
snapshots = RubyDesk::Snapshot.snapshot_details(connector, 'techunlimited',
|
92
88
|
'aseldawy', Time.now)
|
@@ -107,6 +103,8 @@ class TestRubyDesk < Test::Unit::TestCase
|
|
107
103
|
"SELECT worked_on WHERE (provider_id>=1 AND provider_id<=3)"],
|
108
104
|
[{:select=>"worked_on", :conditions=>{:provider_id=>1...3}},
|
109
105
|
"SELECT worked_on WHERE (provider_id>=1 AND provider_id<3)"],
|
106
|
+
[{:select=>["worked_on", "hours"]},
|
107
|
+
"SELECT worked_on,hours"],
|
110
108
|
]
|
111
109
|
test_data.each do |options, query|
|
112
110
|
assert query.include?(RubyDesk::TimeReport.build_query(options))
|
@@ -114,10 +112,7 @@ class TestRubyDesk < Test::Unit::TestCase
|
|
114
112
|
end
|
115
113
|
|
116
114
|
def test_timreport
|
117
|
-
connector =
|
118
|
-
def connector.prepare_and_invoke_api_call(*args)
|
119
|
-
File.read(File.join(File.dirname(__FILE__), 'timereport.json'))
|
120
|
-
end
|
115
|
+
connector = dummy_connector('timereport.json')
|
121
116
|
|
122
117
|
timereport = RubyDesk::TimeReport.find(connector,
|
123
118
|
:select=>"worked_on, sum(hours), provider_id")
|
@@ -127,5 +122,13 @@ class TestRubyDesk < Test::Unit::TestCase
|
|
127
122
|
assert timereport.first['hours'].is_a?(Numeric)
|
128
123
|
end
|
129
124
|
|
125
|
+
def test_timreport_error
|
126
|
+
assert_raises RubyDesk::Error do
|
127
|
+
connector = dummy_connector('timereport_error.json')
|
128
|
+
timereport = RubyDesk::TimeReport.find(connector,
|
129
|
+
:select=>"worked_on, sum(hours), provider_id")
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
130
133
|
end
|
131
134
|
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ruby_desk
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.5.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ahmed ElDawy
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2010-01-
|
12
|
+
date: 2010-01-21 00:00:00 +02:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
@@ -51,6 +51,7 @@ files:
|
|
51
51
|
- test/teamrooms.json
|
52
52
|
- test/test_ruby_desk.rb
|
53
53
|
- test/timereport.json
|
54
|
+
- test/timereport_error.json
|
54
55
|
- test/workdiary.json
|
55
56
|
has_rdoc: true
|
56
57
|
homepage: http://github.com/aseldawy/ruby_desk
|