vkontakte_api 0.2.1 → 1.0.rc

Sign up to get free protection for your applications and to get access to all the features.
Files changed (42) hide show
  1. data/.rspec +1 -0
  2. data/.travis.yml +1 -0
  3. data/.yardopts +1 -1
  4. data/CHANGELOG.md +23 -0
  5. data/README.md +136 -61
  6. data/lib/generators/vkontakte_api/install/USAGE +2 -0
  7. data/lib/generators/vkontakte_api/install/install_generator.rb +9 -0
  8. data/lib/generators/vkontakte_api/install/templates/initializer.rb +22 -0
  9. data/lib/vkontakte_api/api.rb +27 -39
  10. data/lib/vkontakte_api/authorization.rb +66 -0
  11. data/lib/vkontakte_api/client.rb +14 -12
  12. data/lib/vkontakte_api/configuration.rb +22 -4
  13. data/lib/vkontakte_api/error.rb +15 -7
  14. data/lib/vkontakte_api/logger.rb +35 -0
  15. data/lib/vkontakte_api/method.rb +40 -0
  16. data/lib/vkontakte_api/namespace.rb +7 -0
  17. data/lib/vkontakte_api/resolvable.rb +20 -0
  18. data/lib/vkontakte_api/resolver.rb +18 -103
  19. data/lib/vkontakte_api/result.rb +48 -0
  20. data/lib/vkontakte_api/uploading.rb +29 -0
  21. data/lib/vkontakte_api/utils.rb +28 -0
  22. data/lib/vkontakte_api/version.rb +2 -1
  23. data/lib/vkontakte_api.rb +14 -3
  24. data/spec/integration_spec.rb +84 -0
  25. data/spec/spec_helper.rb +18 -0
  26. data/spec/vkontakte_api/api_spec.rb +39 -58
  27. data/spec/vkontakte_api/authorization_spec.rb +111 -0
  28. data/spec/vkontakte_api/client_spec.rb +17 -24
  29. data/spec/vkontakte_api/configuration_spec.rb +5 -0
  30. data/spec/vkontakte_api/error_spec.rb +30 -10
  31. data/spec/vkontakte_api/logger_spec.rb +88 -0
  32. data/spec/vkontakte_api/method_spec.rb +59 -0
  33. data/spec/vkontakte_api/namespace_spec.rb +5 -0
  34. data/spec/vkontakte_api/resolvable_spec.rb +21 -0
  35. data/spec/vkontakte_api/resolver_spec.rb +58 -141
  36. data/spec/vkontakte_api/result_spec.rb +115 -0
  37. data/spec/vkontakte_api/uploading_spec.rb +46 -0
  38. data/spec/vkontakte_api/utils_spec.rb +47 -0
  39. data/spec/vkontakte_api_spec.rb +4 -0
  40. data/vkontakte_api.gemspec +6 -5
  41. metadata +119 -38
  42. data/README.ru.md +0 -115
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --color --format=documentation
data/.travis.yml CHANGED
@@ -2,3 +2,4 @@ rvm:
2
2
  - 1.8.7
3
3
  - 1.9.2
4
4
  - 1.9.3
5
+ - ruby-head
data/.yardopts CHANGED
@@ -1,3 +1,3 @@
1
- --files README.md,README.ru.md
1
+ --files README.md
2
2
  --markup markdown
3
3
  --markup-provider redcarpet
data/CHANGELOG.md ADDED
@@ -0,0 +1,23 @@
1
+ ## 1.0 (в разработке)
2
+
3
+ * rails-генератор конфиг-файла
4
+ * Загрузка файлов на сервера ВКонтакте
5
+ * Авторизация
6
+ * Переход на JSON-парсер `Oj`
7
+ * Результаты методов в виде `Hashie::Mash`
8
+ * Настраиваемый логгер
9
+
10
+ ## 0.2.1 (31.03.2012)
11
+
12
+ * Пространство имен `stats`
13
+
14
+ ## 0.2 (11.03.2012)
15
+
16
+ * Подчищенные неавторизованные запросы
17
+ * Документация кода (`YARD`)
18
+ * Поддержка аргументов-массивов
19
+ * Обновленный список пространств имен
20
+
21
+ ## 0.1 (31.01.2012)
22
+
23
+ * Первая стабильная версия
data/README.md CHANGED
@@ -1,115 +1,190 @@
1
- # vkontakte_api [![Build Status](https://secure.travis-ci.org/7even/vkontakte_api.png)](http://travis-ci.org/7even/vkontakte_api)
1
+ ## vkontakte_api [![Build Status](https://secure.travis-ci.org/7even/vkontakte_api.png)](http://travis-ci.org/7even/vkontakte_api) [![Dependency Status](https://gemnasium.com/7even/vkontakte_api.png)](https://gemnasium.com/7even/vkontakte_api) [![Code Climate](https://codeclimate.com/badge.png)](https://codeclimate.com/github/7even/vkontakte_api)
2
2
 
3
- `vkontakte_api` is a Ruby wrapper for VKontakte API. It allows you to call all API methods in the simplest possible way.
3
+ `vkontakte_api` - ruby-адаптер для ВКонтакте API. Он позволяет вызывать методы API, загружать файлы на сервера ВКонтакте, а также поддерживает все 3 доступных способа авторизации (при этом позволяя использовать стороннее решение).
4
4
 
5
- Below is the English version of the readme. Russian version is located [here](https://github.com/7even/vkontakte_api/blob/master/README.ru.md).
5
+ ## Установка
6
6
 
7
- ## Installation
7
+ ``` ruby
8
+ # Gemfile
9
+ gem 'vkontakte_api', '~> 1.0.rc'
10
+ ```
8
11
 
9
- ``` bash
10
- gem install vkontakte_api
12
+ или просто
13
+
14
+ ``` sh
15
+ $ gem install vkontakte_api
11
16
  ```
12
17
 
13
- ## Usage
18
+ ## Использование
14
19
 
15
- Default HTTP request library is `Net::HTTP`. You can set any other adapter supported by `faraday` in the configure block like so:
20
+ ### Вызов методов
16
21
 
17
22
  ``` ruby
18
- VkontakteApi.configure do |config|
19
- config.adapter = :net_http
23
+ # создаем клиент
24
+ @vk = VkontakteApi::Client.new
25
+ # и вызываем методы API
26
+ @vk.users.get(uid: 1)
27
+
28
+ # в ruby принято использовать snake_case в названиях методов,
29
+ # поэтому likes.getList становится likes.get_list
30
+ @vk.likes.get_list
31
+ # также названия методов, которые возвращают '1' или '0',
32
+ # заканчиваются на '?', а возвращаемые значения приводятся
33
+ # к true или false
34
+ @vk.is_app_user? # => false
35
+
36
+ # если ВКонтакте ожидает получить параметр в виде списка,
37
+ # разделенного запятыми, то его можно передать массивом
38
+ users = @vk.users.get(uids: [1, 2, 3])
39
+
40
+ # большинство методов возвращает структуры Hashie::Mash
41
+ # и массивы из них
42
+ users.first.uid # => 1
43
+ users.first.first_name # => "Павел"
44
+ users.first.last_name # => "Дуров"
45
+ users.first.online? # => true
46
+
47
+ # если метод, возвращающий массив, вызывается с блоком,
48
+ # то блок будет выполнен для каждого элемента,
49
+ # и метод вернет обработанный массив
50
+ fields = [:first_name, :last_name, :screen_name]
51
+ @vk.friends.get(fields: fields) do |friend|
52
+ "#{friend.first_name} '#{friend.screen_name}' #{friend.last_name}"
20
53
  end
54
+ # => ["Павел 'durov' Дуров"]
21
55
  ```
22
56
 
23
- All requests are sent via `VkontakteApi::Client` instance.
57
+ ### Загрузка файлов
58
+
59
+ Загрузка файлов на сервера ВКонтакте осуществляется в несколько этапов: сначала вызывается метод API, возвращающий URL для загрузки, затем происходит сама загрузка файлов, и после этого в некоторых случаях нужно вызвать другой метод API, передав в параметрах данные, возвращенные сервером после предыдущего запроса. Вызываемые методы API зависят от типа загружаемых файлов и описаны в [соответствующем разделе документации](http://vk.com/developers.php?oid=-1&p=%D0%9F%D1%80%D0%BE%D1%86%D0%B5%D1%81%D1%81_%D0%B7%D0%B0%D0%B3%D1%80%D1%83%D0%B7%D0%BA%D0%B8_%D1%84%D0%B0%D0%B9%D0%BB%D0%BE%D0%B2_%D0%BD%D0%B0_%D1%81%D0%B5%D1%80%D0%B2%D0%B5%D1%80_%D0%92%D0%9A%D0%BE%D0%BD%D1%82%D0%B0%D0%BA%D1%82%D0%B5).
60
+
61
+ Файлы передаются в формате хэша, где ключом является название параметра в запросе (указано в документации, например для загрузки фото на стену это будет `photo`), а значением - массив из 2 строк: полный путь к файлу и его MIME-тип:
24
62
 
25
63
  ``` ruby
26
- @app = VkontakteApi::Client.new
64
+ url = 'http://cs303110.vkontakte.ru/upload.php?act=do_add'
65
+ VkontakteApi.upload(url: url, photo: ['/path/to/file.jpg', 'image/jpeg'])
27
66
  ```
28
67
 
29
- To create a client able to perform authorized requests you need to pass an access token.
68
+ Метод вернет ответ сервера ВКонтакте, преобразованный в `Hashie::Mash`; его можно использовать при вызове метода API на последнем этапе процесса загрузки.
69
+
70
+ ### Авторизация
71
+
72
+ Для вызова большинства методов требуется токен доступа (access token). Чтобы получить его, можно использовать авторизацию, встроенную в `vkontakte_api`, либо положиться на какой-то другой механизм (например, [OmniAuth](https://github.com/intridea/omniauth)). В последнем случае в результате авторизации будет получен токен, который нужно будет передать в `VkontakteApi::Client.new`.
73
+
74
+ Для работы с ВКонтакте API предусмотрено 3 типа авторизации: для сайтов, для клиентских приложений (мобильных либо десктопных, имеющих доступ к управлению браузером) и специальный тип авторизации серверов приложений для вызова административных методов без авторизации самого пользователя. Более подробно они описаны [тут](http://vk.com/developers.php?oid=-1&p=%D0%90%D0%B2%D1%82%D0%BE%D1%80%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D1%8F); рассмотрим, как работать с ними средствами `vkontakte_api`.
75
+
76
+ Для авторизации необходимо задать параметры `app_id` (ID приложения), `app_secret` (защищенный ключ) и `redirect_uri` (адрес, куда пользователь будет направлен после предоставления прав приложению) в настройках `VkontakteApi.configure`. Более подробно о конфигурировании `vkontakte_api` см. далее в соответствующем разделе.
77
+
78
+ ##### Сайт
79
+
80
+ Авторизация сайтов проходит в 2 шага: сначала пользователь перенаправляется на страницу ВКонтакте для подтверждения запрошенных у него прав сайта на доступ к его данным. Со списком возможных прав можно ознакомиться [здесь](http://vk.com/developers.php?oid=-1&p=%D0%9F%D1%80%D0%B0%D0%B2%D0%B0_%D0%B4%D0%BE%D1%81%D1%82%D1%83%D0%BF%D0%B0_%D0%BF%D1%80%D0%B8%D0%BB%D0%BE%D0%B6%D0%B5%D0%BD%D0%B8%D0%B9). Допустим, нужно получить доступ к друзьям (`friends`) и фотографиям (`photos`) пользователя.
30
81
 
31
82
  ``` ruby
32
- @app = VkontakteApi::Client.new('my_access_token')
83
+ redirect_to VkontakteApi.authorization_url(scope: [:friends, :photos])
33
84
  ```
34
85
 
35
- Probably the easiest way to get an access token in a web-app is using [OmniAuth](https://github.com/intridea/omniauth), but you can roll your own authentication if for some reason `OmniAuth` isn't acceptable. Currently `vkontakte_api` doesn't offer authentication functionality.
36
-
37
- Now you can call the API methods. All method names are underscore_cased as opposed to the [official documentation](http://vk.com/developers.php?oid=-17680044&p=API_Method_Description) where they are camelCased, so `getGroups` becomes `get_groups`. You can still call them in a camelCased manner, but that is not a Ruby-way practice.
86
+ После подтверждения пользователь перенаправляется на указанный в настройках `redirect_uri`, причем в параметрах будет передан код, по которому можно получить токен доступа. `vkontakte_api` предоставляет метод `VkontakteApi.authorize`, который делает запрос к ВКонтакте, получает токен и создает клиент; нужно лишь передать ему код:
38
87
 
39
88
  ``` ruby
40
- @app.get_user_settings # => 327710
41
- @app.groups.get # => [1, 31022447]
89
+ @vk = VkontakteApi.authorize(code: params[:code])
90
+ # и теперь можно вызывать методы API на объекте @vk
91
+ @vk.is_app_user?
42
92
  ```
43
93
 
44
- Predicate methods (those which begin with `is`, like `is_app_user`) are expected to return the result of some condition, so the '?' is appended to the end of the method name, and they return `true` or `false`:
94
+ Также в этот момент полезно сохранить полученный токен в БД либо в сессии, чтобы использовать его повторно:
45
95
 
46
96
  ``` ruby
47
- @app.is_app_user? # => true
97
+ current_user.token = @vk.token
98
+ current_user.save
99
+ # позже
100
+ @vk = VkontakteApi::Client.new(current_user.token)
48
101
  ```
49
102
 
50
- You can still call these without a '?' and get `'1'` or `'0'` in result if you want to handle that yourself.
103
+ ##### Клиентское приложение
51
104
 
52
- Now for parameters. All method parameters are named, and you can pass them in a hash where parameter names are keys and parameter values are values:
105
+ Авторизация клиентского приложения несколько проще - не нужно получать токен отдельным запросом, он выдается сразу после редиректа пользователя.
53
106
 
54
107
  ``` ruby
55
- @app.friends.get(fields: 'uid,first_name,last_name')
56
- # => [
57
- # {
58
- # :uid => "1",
59
- # :first_name => "Павел",
60
- # :last_name => "Дуров"
61
- # },
62
- # {
63
- # :uid => "6492",
64
- # :first_name => "Andrew",
65
- # :last_name => "Rogozov"
66
- # }
67
- # ]
108
+ # пользователь направляется на следующий урл
109
+ VkontakteApi.authorization_url(type: :client, scope: [:friends, :photos])
68
110
  ```
69
111
 
70
- If the parameter value is a comma-separated list, you can pass it as an array - it will be properly handled before the request:
112
+ Необходимо принимать во внимание, что `redirect_uri` нужно выставлять на `http://api.vkontakte.ru/blank.html`, иначе не получится вызывать методы, доступные клиентским приложениям.
113
+
114
+ Когда пользователь подтвердит права приложения, он будет перенаправлен на `redirect_uri`, при этом в параметре `access_token` будет токен, который нужно передать в `VkontakteApi::Client.new`.
115
+
116
+ ##### Сервер приложения
117
+
118
+ Последний тип авторизации - самый простой, т.к. не предполагает участия пользователя.
71
119
 
72
120
  ``` ruby
73
- users_ids = [1, 6492]
74
- @app.users.get(uids: users_ids) # => same output as above
121
+ @vk = VkontakteApi.authorize(type: :app_server)
75
122
  ```
76
123
 
77
- It's also worth noting that all returned hashes have symbolized keys.
124
+ ### Обработка ошибок
78
125
 
79
- If the response is an Enumerable, you can pass a block that will yield each successive element and put the result in the returned array (like `Enumerable#map` does):
126
+ Если ВКонтакте API возвращает ошибку, выбрасывается исключение класса `VkontakteApi::Error`.
80
127
 
81
128
  ``` ruby
82
- @app.friends.get(fields: 'first_name,last_name') do |friend|
83
- "#{friend[:first_name]} #{friend[:last_name]}"
84
- end
85
- # => ["Павел Дуров", "Andrew Rogozov"]
129
+ vk = VK::Client.new
130
+ vk.friends.get(uid: 1, fields: [:first_name, :last_name, :photo])
131
+ # VkontakteApi::Error: VKontakte returned an error 7: 'Permission to perform this action is denied' after calling method 'friends.get' with parameters {"uid"=>"1", "fields"=>"first_name,last_name,photo"}.
86
132
  ```
87
133
 
88
- `vkontakte_api` doesn't keep any method names list inside (except method namespaces like `friends` or `groups`) - when you call a method, it's name is camelcased before sending a request to VKontakte. So when a new method is added to the API, you don't need to wait for the new version of `vkontakte_api` gem - you can use that new method immediately. If you mistype the method name or use a method you don't have rights to call, you will get an exception with a relevant message (more about the exceptions below).
134
+ ### Логгирование
135
+
136
+ `vkontakte_api` логгирует служебную информацию о запросах при вызове методов. По умолчанию все пишется в `STDOUT`, но в настройке можно указать любой другой совместимый логгер, например `Rails.logger`.
137
+
138
+ Есть возможность логгирования 3 типов информации, каждому соответствует ключ в глобальных настройках.
139
+
140
+ | | ключ настройки | по умолчанию | уровень логгирования |
141
+ | ---------------------- | --------------- | ------------ | -------------------- |
142
+ | URL запроса | `log_requests` | `true` | `debug` |
143
+ | JSON ответа при ошибке | `log_errors` | `true` | `warn` |
144
+ | JSON удачного ответа | `log_responses` | `false` | `debug` |
89
145
 
90
- ### Error handling
146
+ Таким образом, в rails-приложении с настройками по умолчанию в production записываются только ответы сервера при ошибках; в development также логгируются URL-ы запросов.
91
147
 
92
- If VKontakte returns an error in response, you get a `VkontakteApi::Error` exception with all meaningful information that can be retrieved:
148
+ ## Настройка
149
+
150
+ Глобальные параметры `vkontakte_api` задаются в блоке `VkontakteApi.configure` следующим образом:
93
151
 
94
152
  ``` ruby
95
- @app.audio.get_by_id
96
- # => VkontakteApi::Error: VKontakte returned an error 1: 'Unknown error occured' after calling method 'audio.getById' with parameters {}.
153
+ VkontakteApi.configure do |config|
154
+ # параметры, необходимые для авторизации средствами vkontakte_api
155
+ # (не нужны при использовании сторонней авторизации)
156
+ config.app_id = '123'
157
+ config.app_secret = 'AbCdE654'
158
+ config.redirect_uri = 'http://example.com/oauth/callback'
159
+
160
+ # faraday-адаптер для сетевых запросов
161
+ config.adapter = :net_http
162
+
163
+ # логгер
164
+ config.logger = Rails.logger
165
+ config.log_requests = true # URL-ы запросов
166
+ config.log_errors = true # ошибки
167
+ config.log_responses = false # удачные ответы
168
+ end
97
169
  ```
98
170
 
99
- ## Changelog
171
+ По умолчанию для HTTP-запросов используется `Net::HTTP`; можно выбрать [любой другой адаптер](https://github.com/technoweenie/faraday/blob/master/lib/faraday/adapter.rb), поддерживаемый `faraday`.
172
+
173
+ Чтобы сгенерировать файл с настройками по умолчанию в rails-приложении, можно воспользоваться генератором `vkontakte_api:install`:
174
+
175
+ ``` sh
176
+ $ cd /path/to/app
177
+ $ rails generate vkontakte_api:install
178
+ ```
100
179
 
101
- * 0.1 Initial stable version
102
- * 0.2 Array arguments support, cleaned up non-authorized requests, updated namespaces list, code documentation
103
- * 0.2.1 `stats` namespace
180
+ ## JSON-парсер
104
181
 
105
- ## Roadmap
182
+ `vkontakte_api` использует парсер [Oj](https://github.com/ohler55/oj) - это единственный парсер, который не показал [ошибок](https://github.com/7even/vkontakte_api/issues/1) при парсинге JSON, генерируемого ВКонтакте.
106
183
 
107
- * Logging requests
108
- * Authentication (getting the access_token from VK)
109
- * Maybe Struct-like objects in result (instead of Hashes)
184
+ Также в библиотеке `multi_json` (обертка для различных JSON-парсеров, которая выбирает самый быстрый из установленных в системе и парсит им) `Oj` поддерживается и имеет наивысший приоритет; поэтому если он установлен в системе, `multi_json` будет использовать именно его.
110
185
 
111
- ## Contributing
186
+ ## Участие в разработке
112
187
 
113
- If you want to contribute to the project, fork the repository, push your changes to a topic branch and send me a pull request.
188
+ Если вы хотите поучаствовать в разработке проекта, форкните репозиторий, положите свои изменения в отдельную ветку и отправьте мне pull request.
114
189
 
115
- `vkontakte_api` is tested under MRI `1.8.7`, `1.9.2` and `1.9.3`. If something is working incorrectly or not working at all in one of these environments, this should be considered a bug. Any bug reports are welcome at Github issues.
190
+ `vkontakte_api` тестируется под MRI `1.8.7`, `1.9.2`, `1.9.3` и `2.0.0-dev`. Если в одной из этих сред что-то работает неправильно, либо вообще не работает, то это следует считать багом, и написать об этом в [issues на Github](https://github.com/7even/vkontakte_api/issues).
@@ -0,0 +1,2 @@
1
+ Description:
2
+ Create a vkontakte_api config file in config/initializers/vkontakte_api.rb.
@@ -0,0 +1,9 @@
1
+ # A rails generator `vkontakte:install`. It creates a config file in `config/initializers/vkontakte_api.rb`.
2
+ class VkontakteApi::InstallGenerator < Rails::Generators::Base
3
+ source_root File.expand_path('../templates', __FILE__)
4
+
5
+ # Creates the config file.
6
+ def create_initializer
7
+ copy_file 'initializer.rb', 'config/initializers/vkontakte_api.rb'
8
+ end
9
+ end
@@ -0,0 +1,22 @@
1
+ VkontakteApi.configure do |config|
2
+ # Authorization parameters (not needed when using an external authorization):
3
+ # config.app_id = '123'
4
+ # config.app_secret = 'AbCdE654'
5
+ # config.redirect_uri = 'http://example.com/oauth/callback'
6
+
7
+ # Faraday adapter to make requests with:
8
+ # config.adapter = :net_http
9
+
10
+ # Logging parameters:
11
+ # log everything through the rails logger
12
+ config.logger = Rails.logger
13
+
14
+ # log requests' URLs
15
+ # config.log_requests = true
16
+
17
+ # log response JSON after errors
18
+ # config.log_errors = true
19
+
20
+ # log response JSON after successful responses
21
+ # config.log_responses = false
22
+ end
@@ -1,50 +1,38 @@
1
1
  module VkontakteApi
2
- # A low-level module which handles the requests to VKontakte and returns their results as hashes with symbolized keys.
2
+ # A low-level module which handles the requests to VKontakte API and returns their results as mashes.
3
3
  #
4
- # It uses Faraday underneath the hood.
4
+ # It uses Faraday with middleware underneath the hood.
5
5
  module API
6
- BASE_HOST = 'https://api.vkontakte.ru'
7
- BASE_URL = '/method/'
6
+ # URL prefix for calling API methods.
7
+ URL_PREFIX = 'https://api.vkontakte.ru/method'
8
8
 
9
9
  class << self
10
- # Main interface method.
10
+ # API method call.
11
11
  # @param [String] method_name A full name of the method.
12
- # @param [Hash] args Method arguments including the access token.
13
- # @return [Hash] The result of the method call.
14
- # @raise [VkontakteApi::Error] raised when VKontakte returns an error.
15
- def call(method_name, args = {}, &block)
16
- connection = Faraday.new(:url => BASE_HOST) do |builder|
17
- builder.adapter(VkontakteApi.adapter)
18
- end
19
-
20
- url = url_for(method_name, args)
21
- body = connection.get(url).body
22
- response = Yajl::Parser.parse(body, :symbolize_keys => true)
23
-
24
- if response.has_key?(:error)
25
- raise VkontakteApi::Error.new(response[:error])
26
- else
27
- response[:response]
28
- end
12
+ # @param [Hash] args Method arguments.
13
+ # @param [String] token The access token.
14
+ # @return [Hashie::Mash] Mashed server response.
15
+ def call(method_name, args = {}, token = nil)
16
+ flat_arguments = Utils.flatten_arguments(args)
17
+ connection(:url => URL_PREFIX, :token => token).get(method_name, flat_arguments).body
29
18
  end
30
19
 
31
- private
32
- def url_for(method_name, arguments)
33
- flat_arguments = flatten_arguments(arguments)
34
- "#{BASE_URL}#{method_name}?#{flat_arguments.to_param}"
35
- end
36
-
37
- def flatten_arguments(arguments)
38
- arguments.inject({}) do |flat_args, (arg_name, arg_value)|
39
- flat_args[arg_name] = if arg_value.respond_to?(:join)
40
- # if value is an array, we join it with a comma
41
- arg_value.join(',')
42
- else
43
- # otherwise leave it untouched
44
- arg_value
45
- end
46
-
47
- flat_args
20
+ # Faraday connection.
21
+ # @param [Hash] options Connection options.
22
+ # @option options [String] :url Connection URL (either full or just prefix).
23
+ # @option options [String] :token OAuth2 access token (not used if omitted).
24
+ # @return [Faraday::Connection] Created connection.
25
+ def connection(options = {})
26
+ url = options.delete(:url)
27
+ token = options.delete(:token)
28
+
29
+ Faraday.new(url) do |builder|
30
+ builder.request :oauth2, token unless token.nil?
31
+ builder.request :multipart
32
+ builder.response :vk_logger
33
+ builder.response :mashify
34
+ builder.response :oj, :preserve_raw => true
35
+ builder.adapter VkontakteApi.adapter
48
36
  end
49
37
  end
50
38
  end
@@ -0,0 +1,66 @@
1
+ module VkontakteApi
2
+ # A module containing the methods for authorization.
3
+ #
4
+ # @note `VkontakteApi::Authorization` extends `VkontakteApi` so these methods should be called from the latter.
5
+ module Authorization
6
+ # Authorization options.
7
+ OPTIONS = {
8
+ :client => {
9
+ :site => 'https://oauth.vk.com',
10
+ :authorize_url => '/authorize',
11
+ :token_url => '/access_token'
12
+ },
13
+ :client_credentials => {
14
+ 'auth_scheme' => 'request_body'
15
+ }
16
+ }
17
+
18
+ # URL for redirecting the user to VK where he gives the application all the requested access rights.
19
+ # @option options [Symbol] :type The type of authorization being used (`:site` and `:client` supported).
20
+ # @option options [String] :redirect_uri URL for redirecting the user back to the application (overrides the global configuration value).
21
+ # @option options [Array] :scope An array of requested access rights (each represented by a symbol or a string).
22
+ # @raise [ArgumentError] raises after receiving an unknown authorization type.
23
+ # @return [String] URL to redirect the user to.
24
+ def authorization_url(options = {})
25
+ type = options.delete(:type) || :site
26
+ # redirect_uri passed in options overrides the global setting
27
+ options[:redirect_uri] ||= VkontakteApi.redirect_uri
28
+ options[:scope] = VkontakteApi::Utils.flatten_argument(options[:scope]) if options[:scope]
29
+
30
+ case type
31
+ when :site
32
+ client.auth_code.authorize_url(options)
33
+ when :client
34
+ client.implicit.authorize_url(options)
35
+ else
36
+ raise ArgumentError, "Unknown authorization type #{type.inspect}"
37
+ end
38
+ end
39
+
40
+ # Authorization (getting the access token and building a `VkontakteApi::Client` with it).
41
+ # @option options [Symbol] :type The type of authorization being used (`:site` and `:app_server` supported).
42
+ # @option options [String] :code The code to exchange for an access token (for `:site` authorization type).
43
+ # @raise [ArgumentError] raises after receiving an unknown authorization type.
44
+ # @return [VkontakteApi::Client] An API client.
45
+ def authorize(options = {})
46
+ type = options.delete(:type) || :site
47
+
48
+ case type
49
+ when :site
50
+ code = options.delete(:code)
51
+ token = client.auth_code.get_token(code)
52
+ when :app_server
53
+ token = client.client_credentials.get_token({}, OPTIONS[:client_credentials])
54
+ else
55
+ raise ArgumentError, "Unknown authorization type #{type.inspect}"
56
+ end
57
+
58
+ Client.new(token)
59
+ end
60
+
61
+ private
62
+ def client
63
+ @client ||= OAuth2::Client.new(VkontakteApi.app_id, VkontakteApi.app_secret, OPTIONS[:client])
64
+ end
65
+ end
66
+ end
@@ -1,24 +1,26 @@
1
1
  module VkontakteApi
2
- # A class representing a connection to VK. It holds an access token.
2
+ # A class representing a connection to VK. It holds the access token.
3
3
  class Client
4
+ include Resolver
5
+
4
6
  # An access token needed by authorized requests.
5
- attr_reader :access_token
7
+ attr_reader :token
6
8
 
7
9
  # A new API client.
8
- # @param [String] access_token An access token.
9
- def initialize(access_token = nil)
10
- @access_token = access_token
10
+ # @param [String, OAuth2::AccessToken] token An access token.
11
+ def initialize(token = nil)
12
+ if token.respond_to?(:token)
13
+ # token is an OAuth2::AccessToken
14
+ @token = token.token
15
+ else
16
+ # token is a String or nil
17
+ @token = token
18
+ end
11
19
  end
12
20
 
13
21
  # Is a `VkontakteApi::Client` instance authorized.
14
22
  def authorized?
15
- !@access_token.nil?
16
- end
17
-
18
- # All unknown methods are delegated to a `VkontakteApi::Resolver` instance.
19
- def method_missing(method_name, *args, &block)
20
- args = args.first || {}
21
- VkontakteApi::Resolver.new(:access_token => @access_token).send(method_name, args, &block)
23
+ !@token.nil?
22
24
  end
23
25
  end
24
26
  end
@@ -1,20 +1,34 @@
1
+ require 'logger'
2
+
1
3
  module VkontakteApi
2
4
  # General configuration module.
3
5
  #
4
- # It extends `VkontakteApi` so it's methods should be called from there.
6
+ # @note `VkontakteApi::Configuration` extends `VkontakteApi` so these methods should be called from the latter.
5
7
  module Configuration
6
8
  # Available options.
7
- OPTION_NAMES = [:app_id, :app_secret, :adapter]
9
+ OPTION_NAMES = [:app_id, :app_secret, :redirect_uri, :adapter, :logger, :log_requests, :log_errors, :log_responses]
8
10
 
9
11
  attr_accessor *OPTION_NAMES
10
12
 
13
+ alias_method :log_requests?, :log_requests
14
+ alias_method :log_errors?, :log_errors
15
+ alias_method :log_responses?, :log_responses
16
+
11
17
  # Default HTTP adapter.
12
- DEFAULT_ADAPTER = :net_http
18
+ DEFAULT_ADAPTER = Faraday.default_adapter
19
+
20
+ # Logger default options.
21
+ DEFAULT_LOGGER_OPTIONS = {
22
+ :requests => true,
23
+ :errors => true,
24
+ :responses => false
25
+ }
13
26
 
14
27
  # A global configuration set via the block.
15
28
  # @example
16
29
  # VkontakteApi.configure do |config|
17
30
  # config.adapter = :net_http
31
+ # config.logger = Rails.logger
18
32
  # end
19
33
  def configure
20
34
  yield self if block_given?
@@ -23,7 +37,11 @@ module VkontakteApi
23
37
 
24
38
  # Reset all configuration options to defaults.
25
39
  def reset
26
- @adapter = DEFAULT_ADAPTER
40
+ @adapter = DEFAULT_ADAPTER
41
+ @logger = ::Logger.new(STDOUT)
42
+ @log_requests = DEFAULT_LOGGER_OPTIONS[:requests]
43
+ @log_errors = DEFAULT_LOGGER_OPTIONS[:errors]
44
+ @log_responses = DEFAULT_LOGGER_OPTIONS[:responses]
27
45
  end
28
46
 
29
47
  # When this module is extended, set all configuration options to their default values.
@@ -1,18 +1,17 @@
1
1
  module VkontakteApi
2
- # An exception raised by `VkontakteApi::API` when VKontakte returns an error.
2
+ # An exception raised by `VkontakteApi::Result` when given a response with an error.
3
3
  class Error < StandardError
4
4
  # An error code.
5
5
  # @return [Fixnum]
6
6
  attr_reader :error_code
7
7
 
8
- # An exception is initialized by the data from response hash.
8
+ # An exception is initialized by the data from response mash.
9
9
  # @param [Hash] data Error data.
10
10
  def initialize(data)
11
- @error_code = data.delete(:error_code)
12
- @error_msg = data.delete(:error_msg)
13
- @params = {}
11
+ @error_code = data.error_code
12
+ @error_msg = data.error_msg
14
13
 
15
- request_params = parse_params(data.delete :request_params)
14
+ request_params = parse_params(data.request_params)
16
15
 
17
16
  @method_name = request_params.delete('method')
18
17
  @access_token = request_params.delete('access_token')
@@ -23,7 +22,16 @@ module VkontakteApi
23
22
  # A full description of the error.
24
23
  # @return [String]
25
24
  def message
26
- "VKontakte returned an error #{@error_code}: '#{@error_msg}' after calling method '#{@method_name}' with parameters #{@params.inspect}."
25
+ message = "VKontakte returned an error #{@error_code}: '#{@error_msg}'"
26
+ message << " after calling method '#{@method_name}'"
27
+
28
+ if @params.empty?
29
+ message << " without parameters."
30
+ else
31
+ message << " with parameters #{@params.inspect}."
32
+ end
33
+
34
+ message
27
35
  end
28
36
 
29
37
  private