vkontakte_api 0.2.1 → 1.0.rc

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.
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