vkontakte_api 1.0.4 → 1.1

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/CHANGELOG.md CHANGED
@@ -1,3 +1,10 @@
1
+ ## 1.1 (18.12.2012)
2
+
3
+ * Передача `redirect_uri` при получении токена
4
+ * Методы для работы с правами и сроком жизни токена
5
+ * Логгирование тела POST-запроса
6
+ * POST-запросы по умолчанию
7
+
1
8
  ## 1.0.4 (22.09.2012)
2
9
 
3
10
  * Пространство имен `orders`
data/Guardfile ADDED
@@ -0,0 +1,7 @@
1
+ guard 'rspec' do
2
+ watch(%r{^spec/.+_spec\.rb$})
3
+ watch(%r{^lib/(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" }
4
+ watch('spec/spec_helper.rb') { 'spec' }
5
+ end
6
+
7
+ notification :terminal_notifier, activate: 'com.googlecode.iTerm2'
data/README.md CHANGED
@@ -136,6 +136,41 @@ VkontakteApi.authorization_url(type: :client, scope: [:friends, :photos])
136
136
  @vk = VkontakteApi.authorize(type: :app_server)
137
137
  ```
138
138
 
139
+ ### Прочее
140
+
141
+ Если клиент API (объект класса `VkontakteApi::Client`) был создан с помощью метода `VkontakteApi.authorize`, он будет содержать информацию об id текущего пользователя (`user_id`) и о времени истечения токена (`expires_at`). Получить их можно с помощью соответствующих методов:
142
+
143
+ ``` ruby
144
+ vk = VkontakteApi.authorize(code: 'c1493e81f69fce1b43')
145
+ # => #<VkontakteApi::Client:0x007fa578f00ad0>
146
+ vk.user_id # => 628985
147
+ vk.expires_at # => 2012-12-18 23:22:55 +0400
148
+ # можно проверить, истекло ли время жизни токена
149
+ vk.expired? # => false
150
+ ```
151
+
152
+ Также можно получить список прав доступа, которые дает данный токен, в виде, аналогичном формату параметра `scope` в авторизации:
153
+
154
+ ``` ruby
155
+ vk.scope # => [:friends, :groups]
156
+ ```
157
+
158
+ Это работает на основе метода `getUserSettings`, причем результат запоминается после первого обращения.
159
+
160
+ Чтобы создать короткий синоним `VK` для модуля `VkontakteApi`, достаточно вызвать метод `VkontakteApi.register_alias`:
161
+
162
+ ``` ruby
163
+ VkontakteApi.register_alias
164
+ VK::Client.new # => #<VkontakteApi::Client:0x007fa578d6d948>
165
+ ```
166
+
167
+ При необходимости можно удалить синоним методом `VkontakteApi.unregister_alias`:
168
+
169
+ ``` ruby
170
+ VK.unregister_alias
171
+ VK # => NameError: uninitialized constant VK
172
+ ```
173
+
139
174
  ### Обработка ошибок
140
175
 
141
176
  Если ВКонтакте API возвращает ошибку, выбрасывается исключение класса `VkontakteApi::Error`.
@@ -179,7 +214,7 @@ VkontakteApi.configure do |config|
179
214
  # faraday-адаптер для сетевых запросов
180
215
  config.adapter = :net_http
181
216
  # HTTP-метод для вызова методов API (:get или :post)
182
- config.http_verb = :get
217
+ config.http_verb = :post
183
218
  # параметры для faraday-соединения
184
219
  config.faraday_options = {
185
220
  ssl: {
@@ -198,14 +233,11 @@ VkontakteApi.configure do |config|
198
233
  config.log_errors = true # ошибки
199
234
  config.log_responses = false # удачные ответы
200
235
  end
201
-
202
- # создание короткого алиаса VK для модуля VkontakteApi
203
- VkontakteApi.register_alias
204
236
  ```
205
237
 
206
238
  По умолчанию для HTTP-запросов используется `Net::HTTP`; можно выбрать [любой другой адаптер](https://github.com/technoweenie/faraday/blob/master/lib/faraday/adapter.rb), поддерживаемый `faraday`.
207
239
 
208
- ВКонтакте [позволяет](http://vk.com/developers.php?oid=-1&p=%D0%92%D1%8B%D0%BF%D0%BE%D0%BB%D0%BD%D0%B5%D0%BD%D0%B8%D0%B5_%D0%B7%D0%B0%D0%BF%D1%80%D0%BE%D1%81%D0%BE%D0%B2_%D0%BA_API) использовать как `GET`-, так и `POST`-запросы при вызове методов API. По умолчанию `vkontakte_api` использует `GET`, но в настройке `http_verb` можно указать `:post`, чтобы совершать `POST`-запросы.
240
+ ВКонтакте [позволяет](http://vk.com/developers.php?oid=-1&p=%D0%92%D1%8B%D0%BF%D0%BE%D0%BB%D0%BD%D0%B5%D0%BD%D0%B8%D0%B5_%D0%B7%D0%B0%D0%BF%D1%80%D0%BE%D1%81%D0%BE%D0%B2_%D0%BA_API) использовать как `GET`-, так и `POST`-запросы при вызове методов API. По умолчанию `vkontakte_api` использует `POST`, но в настройке `http_verb` можно указать `:get`, чтобы совершать `GET`-запросы.
209
241
 
210
242
  При необходимости можно указать параметры для faraday-соединения - например, параметры прокси-сервера или путь к SSL-сертификатам.
211
243
 
@@ -225,7 +257,8 @@ $ rails generate vkontakte_api:install
225
257
  ## Roadmap
226
258
 
227
259
  * метод, возвращающий права текущего токена в читабельной форме (используя `getUserSettings` и кэшируя результат)
228
- * сохранение параметра `expires_in` токена в объекте `VkontakteApi::Client` после авторизации через `VkontakteApi.authorize`
260
+ * сохранение параметра `expires_at` токена в объекте `VkontakteApi::Client` после авторизации через `VkontakteApi.authorize`
261
+ * метод `VkontakteApi::Client#offline?`, проверяющий, является ли токен бесконечным, используя значение `VkontakteApi::Client#expires_at`
229
262
  * `POST`-запросы по умолчанию
230
263
  * логгирование тела `POST`-запроса
231
264
 
@@ -45,12 +45,14 @@ module VkontakteApi
45
45
  def authorize(options = {})
46
46
  type = options.delete(:type) || :site
47
47
 
48
+ options[:redirect_uri] ||= VkontakteApi.redirect_uri
49
+
48
50
  case type
49
51
  when :site
50
52
  code = options.delete(:code)
51
- token = client.auth_code.get_token(code)
53
+ token = client.auth_code.get_token(code, options)
52
54
  when :app_server
53
- token = client.client_credentials.get_token({}, OPTIONS[:client_credentials])
55
+ token = client.client_credentials.get_token(options, OPTIONS[:client_credentials].dup)
54
56
  else
55
57
  raise ArgumentError, "Unknown authorization type #{type.inspect}"
56
58
  end
@@ -3,22 +3,48 @@ module VkontakteApi
3
3
  class Client
4
4
  include Resolver
5
5
 
6
+ # Access rights and their respective number representation.
7
+ SCOPE = {
8
+ :notify => 1,
9
+ :friends => 2,
10
+ :photos => 4,
11
+ :audio => 8,
12
+ :video => 16,
13
+ :offers => 32,
14
+ :questions => 64,
15
+ :pages => 128,
16
+ :status => 1024,
17
+ :notes => 2048,
18
+ :messages => 4096,
19
+ :wall => 8192,
20
+ :ads => 32768,
21
+ :docs => 131072,
22
+ :groups => 262144,
23
+ :notifications => 524288,
24
+ :stats => 1048576
25
+ }
26
+
6
27
  # An access token needed by authorized requests.
7
28
  # @return [String]
8
29
  attr_reader :token
9
30
  # Current user id.
10
31
  # @return [Integer]
11
32
  attr_reader :user_id
33
+ # Token expiration time
34
+ # @return [Time]
35
+ attr_reader :expires_at
12
36
 
13
37
  # A new API client.
14
38
  # If given an `OAuth2::AccessToken` instance, it extracts and keeps
15
- # the token string and the user id; otherwise it just stores the given token.
39
+ # the token string, the user id and the expiration time;
40
+ # otherwise it just stores the given token.
16
41
  # @param [String, OAuth2::AccessToken] token An access token.
17
42
  def initialize(token = nil)
18
43
  if token.respond_to?(:token) && token.respond_to?(:params)
19
44
  # token is an OAuth2::AccessToken
20
- @token = token.token
21
- @user_id = token.params['user_id']
45
+ @token = token.token
46
+ @user_id = token.params['user_id']
47
+ @expires_at = Time.at(token.expires_at) unless token.expires_at.nil?
22
48
  else
23
49
  # token is a String or nil
24
50
  @token = token
@@ -29,5 +55,23 @@ module VkontakteApi
29
55
  def authorized?
30
56
  !@token.nil?
31
57
  end
58
+
59
+ # Did the token already expire.
60
+ def expired?
61
+ @expires_at && @expires_at < Time.now
62
+ end
63
+
64
+ # Access rights of this token.
65
+ # @return [Array] An array of symbols representing the access rights.
66
+ def scope
67
+ SCOPE.reject do |access_scope, mask|
68
+ (settings & mask).zero?
69
+ end.keys
70
+ end
71
+
72
+ private
73
+ def settings
74
+ @settings ||= self.get_user_settings
75
+ end
32
76
  end
33
77
  end
@@ -29,7 +29,7 @@ module VkontakteApi
29
29
  DEFAULT_ADAPTER = Faraday.default_adapter
30
30
 
31
31
  # Default HTTP verb for API methods.
32
- DEFAULT_HTTP_VERB = :get
32
+ DEFAULT_HTTP_VERB = :post
33
33
 
34
34
  # Logger default options.
35
35
  DEFAULT_LOGGER_OPTIONS = {
@@ -15,6 +15,7 @@ module VkontakteApi
15
15
  def call(env)
16
16
  if VkontakteApi.log_requests?
17
17
  @logger.debug "#{env[:method].to_s.upcase} #{env[:url].to_s}"
18
+ @logger.debug "body: #{env[:body].inspect}" unless env[:method] == :get
18
19
  end
19
20
 
20
21
  super
@@ -1,4 +1,4 @@
1
1
  module VkontakteApi
2
2
  # Library version.
3
- VERSION = '1.0.4'
3
+ VERSION = '1.1'
4
4
  end
@@ -8,7 +8,7 @@ describe VkontakteApi::API do
8
8
  builder.response :mashify
9
9
  builder.response :oj, :preserve_raw => true
10
10
  builder.adapter :test do |stub|
11
- stub.get('/apiMethod') do
11
+ stub.post('/apiMethod') do
12
12
  [200, {}, Oj.dump(@result)]
13
13
  end
14
14
  end
@@ -13,8 +13,8 @@ describe VkontakteApi::Authorization do
13
13
  @token = stub("Token")
14
14
 
15
15
  @auth_code = stub("Authorization code strategy", :get_token => @token, :authorize_url => @url)
16
- @implicit = stub("Implicit strategy", :authorize_url => @url)
17
- @client_credentials = stub("Client credentials strategy", :get_token => @token)
16
+ @implicit = stub("Implicit strategy", :authorize_url => @url)
17
+ @client_credentials = stub("Client credentials strategy", :get_token => @token)
18
18
 
19
19
  @client = stub("OAuth2::Client instance", :auth_code => @auth_code, :implicit => @implicit, :client_credentials => @client_credentials)
20
20
  OAuth2::Client.stub(:new).and_return(@client)
@@ -70,14 +70,14 @@ describe VkontakteApi::Authorization do
70
70
  end
71
71
 
72
72
  it "gets the token" do
73
- @auth_code.should_receive(:get_token).with(@code)
73
+ @auth_code.should_receive(:get_token).with(@code, {:redirect_uri => @redirect_uri})
74
74
  @auth.authorize(:type => :site, :code => @code)
75
75
  end
76
76
  end
77
77
 
78
78
  context "with an app_server type" do
79
79
  it "gets the token" do
80
- @client_credentials.should_receive(:get_token).with({}, subject::OPTIONS[:client_credentials])
80
+ @client_credentials.should_receive(:get_token).with({:redirect_uri => @redirect_uri}, subject::OPTIONS[:client_credentials])
81
81
  @auth.authorize(:type => :app_server)
82
82
  end
83
83
  end
@@ -4,7 +4,12 @@ describe VkontakteApi::Client do
4
4
  before(:each) do
5
5
  @user_id = stub("User id")
6
6
  @string_token = stub("Access token as a String")
7
- @oauth2_token = stub("Access token as an OAuth2::AccessToken", :token => @string_token, :params => {'user_id' => @user_id})
7
+ @expires_at = Time.now - 2 * 60 * 60 # 2.hours.ago
8
+
9
+ @oauth2_token = stub("Access token as an OAuth2::AccessToken")
10
+ @oauth2_token.stub(:token).and_return(@string_token)
11
+ @oauth2_token.stub(:params).and_return('user_id' => @user_id)
12
+ @oauth2_token.stub(:expires_at).and_return(@expires_at)
8
13
  end
9
14
 
10
15
  describe "#initialize" do
@@ -28,6 +33,9 @@ describe VkontakteApi::Client do
28
33
  client = VkontakteApi::Client.new(@oauth2_token)
29
34
  client.token.should == @string_token
30
35
  client.user_id.should == @user_id
36
+
37
+ client.expires_at.should be_a(Time)
38
+ client.expires_at.should be < Time.now
31
39
  end
32
40
  end
33
41
  end
@@ -46,4 +54,62 @@ describe VkontakteApi::Client do
46
54
  end
47
55
  end
48
56
  end
57
+
58
+ describe "#expired?" do
59
+ context "with an expired token" do
60
+ before(:each) do
61
+ @client = VkontakteApi::Client.new(@oauth2_token)
62
+ end
63
+
64
+ it "returns true" do
65
+ @client.should be_expired
66
+ end
67
+ end
68
+
69
+ context "with an actual token" do
70
+ before(:each) do
71
+ @oauth2_token.stub(:expires_at).and_return(Time.now + 2 * 24 * 60 * 60) # 2.days.from_now
72
+ @client = VkontakteApi::Client.new(@oauth2_token)
73
+ end
74
+
75
+ it "returns false" do
76
+ @client.should_not be_expired
77
+ end
78
+ end
79
+
80
+ context "with a String token" do
81
+ before(:each) do
82
+ @client = VkontakteApi::Client.new(@string_token)
83
+ end
84
+
85
+ it "returns false" do
86
+ @client.should_not be_expired
87
+ end
88
+ end
89
+ end
90
+
91
+ describe "#scope" do
92
+ before(:each) do
93
+ @client = VkontakteApi::Client.new
94
+ @client.stub(:get_user_settings).and_return(865310)
95
+ end
96
+
97
+ it "returns an array of access rights" do
98
+ scopes_array = @client.scope
99
+
100
+ [
101
+ :friends,
102
+ :photos,
103
+ :audio,
104
+ :video,
105
+ :status,
106
+ :messages,
107
+ :wall,
108
+ :groups,
109
+ :notifications
110
+ ].each do |access_scope|
111
+ scopes_array.should include(access_scope)
112
+ end
113
+ end
114
+ end
49
115
  end
@@ -6,6 +6,7 @@ describe VkontakteApi::Logger do
6
6
  @fail_response = Oj.dump('error' => 404)
7
7
 
8
8
  @connection = Faraday.new(:url => 'http://example.com') do |builder|
9
+ builder.request :url_encoded
9
10
  builder.response :vk_logger
10
11
  builder.response :mashify
11
12
  builder.response :oj, :preserve_raw => true
@@ -14,6 +15,9 @@ describe VkontakteApi::Logger do
14
15
  stub.get('/success') do
15
16
  [200, {}, @success_response]
16
17
  end
18
+ stub.post('/success') do
19
+ [200, {}, @success_response]
20
+ end
17
21
  stub.get('/fail') do
18
22
  [200, {}, @fail_response]
19
23
  end
@@ -33,10 +37,18 @@ describe VkontakteApi::Logger do
33
37
  VkontakteApi.log_requests = true
34
38
  end
35
39
 
36
- it "logs the request" do
40
+ it "logs the request URL" do
37
41
  @logger.should_receive(:debug).with('GET http://example.com/success')
38
42
  @connection.get('/success')
39
43
  end
44
+
45
+ context "with a POST request" do
46
+ it "logs the request URL and the request body" do
47
+ @logger.should_receive(:debug).with('POST http://example.com/success')
48
+ @logger.should_receive(:debug).with('body: "param=1"')
49
+ @connection.post('/success', :param => 1)
50
+ end
51
+ end
40
52
  end
41
53
 
42
54
  context "without VkontakteApi.log_requests?" do
@@ -24,6 +24,9 @@ Gem::Specification.new do |s|
24
24
 
25
25
  s.add_development_dependency 'rake'
26
26
  s.add_development_dependency 'rspec'
27
+ s.add_development_dependency 'guard-rspec'
28
+ s.add_development_dependency 'rb-fsevent', '~> 0.9.1'
29
+ s.add_development_dependency 'terminal-notifier-guard'
27
30
  s.add_development_dependency 'pry'
28
31
  s.add_development_dependency 'awesome_print'
29
32
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: vkontakte_api
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.4
4
+ version: '1.1'
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-09-21 00:00:00.000000000 Z
12
+ date: 2012-12-17 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: faraday
@@ -123,6 +123,54 @@ dependencies:
123
123
  - - ! '>='
124
124
  - !ruby/object:Gem::Version
125
125
  version: '0'
126
+ - !ruby/object:Gem::Dependency
127
+ name: guard-rspec
128
+ requirement: !ruby/object:Gem::Requirement
129
+ none: false
130
+ requirements:
131
+ - - ! '>='
132
+ - !ruby/object:Gem::Version
133
+ version: '0'
134
+ type: :development
135
+ prerelease: false
136
+ version_requirements: !ruby/object:Gem::Requirement
137
+ none: false
138
+ requirements:
139
+ - - ! '>='
140
+ - !ruby/object:Gem::Version
141
+ version: '0'
142
+ - !ruby/object:Gem::Dependency
143
+ name: rb-fsevent
144
+ requirement: !ruby/object:Gem::Requirement
145
+ none: false
146
+ requirements:
147
+ - - ~>
148
+ - !ruby/object:Gem::Version
149
+ version: 0.9.1
150
+ type: :development
151
+ prerelease: false
152
+ version_requirements: !ruby/object:Gem::Requirement
153
+ none: false
154
+ requirements:
155
+ - - ~>
156
+ - !ruby/object:Gem::Version
157
+ version: 0.9.1
158
+ - !ruby/object:Gem::Dependency
159
+ name: terminal-notifier-guard
160
+ requirement: !ruby/object:Gem::Requirement
161
+ none: false
162
+ requirements:
163
+ - - ! '>='
164
+ - !ruby/object:Gem::Version
165
+ version: '0'
166
+ type: :development
167
+ prerelease: false
168
+ version_requirements: !ruby/object:Gem::Requirement
169
+ none: false
170
+ requirements:
171
+ - - ! '>='
172
+ - !ruby/object:Gem::Version
173
+ version: '0'
126
174
  - !ruby/object:Gem::Dependency
127
175
  name: pry
128
176
  requirement: !ruby/object:Gem::Requirement
@@ -170,6 +218,7 @@ files:
170
218
  - .yardopts
171
219
  - CHANGELOG.md
172
220
  - Gemfile
221
+ - Guardfile
173
222
  - MIT-LICENSE
174
223
  - README.md
175
224
  - Rakefile