odnoklassniki 0.0.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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: fa32a6ad3f01eeb19c56f001b06a75ba7564610d
4
+ data.tar.gz: 888fdd5cacb10c743b680d5858df65a98d6830ff
5
+ SHA512:
6
+ metadata.gz: d3f1963e9c51d82be4760e9c7ac58795e40a5c39262b62755df9221216b2299d7d3aa07e88065f31640e6da82a987da2a475968744186dc4da0913debda505c7
7
+ data.tar.gz: 18876b13cbc7e90b6038f78ad528ae100733555a870fb904d18c772b5d1e5c8d1a841d7f48c72efd517ba2cf7e640a5880b04ceaddf6170fa033a014450e817a
@@ -0,0 +1,3 @@
1
+ /.bundle
2
+ /Gemfile.lock
3
+ /coverage
@@ -0,0 +1,12 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.0.0
4
+ - 2.1.0
5
+ - 2.1.5
6
+ - 2.2.0
7
+ - jruby-19mode # JRuby in 1.9 mode
8
+ - rbx
9
+ matrix:
10
+ allow_failures:
11
+ - rvm: jruby-19mode
12
+ - rvm: rbx
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in odnoklassniki.gemspec
4
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2015 Alexey Gaziev
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
22
+
@@ -0,0 +1,106 @@
1
+ # Odnoklassniki
2
+ [![Build Status](https://travis-ci.org/gazay/odnoklassniki.svg)](http://travis-ci.org/gazay/odnoklassniki) [![CodeClimate](https://d3s6mut3hikguw.cloudfront.net/github/gazay/odnoklassniki/badges/gpa.svg)](https://codeclimate.com/github/gazay/odnoklassniki)
3
+
4
+ Ruby wrapper for Odnoklassniki API
5
+
6
+ Right now it is a simple wrapper on get and post requests to Odnoklassniki api.
7
+
8
+ This gem widely used in [Amplifr](https://amplifr.com) and currently being developed
9
+
10
+ <a href="https://evilmartians.com/?utm_source=odnoklassniki-gem">
11
+ <img src="https://evilmartians.com/badges/sponsored-by-evil-martians.svg" alt="Sponsored by Evil Martians" width="236" height="54">
12
+ </a>
13
+
14
+ ## Installation
15
+
16
+ ```
17
+ gem install odnoklassniki
18
+ ```
19
+
20
+ ## Usage
21
+
22
+ To use odnoklassniki api methods you should have [VALUABLE ACCESS](http://dev.odnoklassniki.ru/wiki/pages/viewpage.action?pageId=12878032) to odnoklassniki.
23
+
24
+ ### Configuration
25
+
26
+ You can create global configuration for your application. Create initializer `config/initializers/ok_api.rb`:
27
+
28
+ ```ruby
29
+ Odnoklassniki.configure do |c|
30
+ c.application_key = 'You application key'
31
+ c.client_id = 'Your client id'
32
+ c.client_secret = 'Your client secret'
33
+ end
34
+ ```
35
+
36
+ Or you can create config object and feed it to `Odnoklassniki` module:
37
+
38
+ ```ruby
39
+ config = Odnoklassniki::Config.configure do |c|
40
+ ...
41
+ end
42
+
43
+ Odnoklassniki.config = config
44
+ ```
45
+
46
+ Also, when you create new `Odnoklassniki::Client` you can pass all needed (or missed on configuration step) options right there:
47
+
48
+ ```ruby
49
+ Odnoklassniki::Client.new(access_token: 'your token', client_id: 'your client id')
50
+ ```
51
+
52
+ ### Example
53
+
54
+ ```ruby
55
+ client = Odnoklassniki::Client.new(access_token: token)
56
+
57
+ new_token = client.refresh_token! # This method will be called automaticaly just once
58
+ # for each client before performing request
59
+
60
+ client.get('friends.get')
61
+ client.get('friends/get')
62
+ client.get('api/friends/get')
63
+ client.get('/api/friends/get')
64
+ # All get requests above identical
65
+
66
+ client.post('mediatopic.post', type: 'USER_STATUS', attachment: attachment)
67
+ ```
68
+
69
+ ### Error handling
70
+
71
+ Most of errors from Odnoklassniki API retruned in success response (with status code 200).
72
+ So there is a wrapper for it in this gem:
73
+
74
+ ```ruby
75
+ begin
76
+ client.get('some.wrong.request')
77
+ rescue Odnoklassniki::Error::ClientError => e
78
+ e.inspect
79
+ end
80
+ ```
81
+
82
+ Also there are bunch of client/server error classes which structure was gratefully copied and adopted from
83
+ @sferik's twitter gem. They can be useful when Odnoklassniki API wasn't reached or when some other issue occured.
84
+
85
+ ## TODO
86
+
87
+ 1. Wrap some usual methods like `users.getCurrentUser`, `mediatopic.post` etc.
88
+ 2. Write tests with real credentials
89
+
90
+ ## Contributing
91
+
92
+ 1. Fork it
93
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
94
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
95
+ 4. Push to the branch (`git push origin my-new-feature`)
96
+ 5. Create new Pull Request
97
+
98
+ ## Contributors
99
+
100
+ * @gazay
101
+
102
+ Special thanks to @Strech, @igas.
103
+
104
+ ## License
105
+
106
+ The MIT License
@@ -0,0 +1,9 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+ require 'rake/testtask'
4
+
5
+ Rake::TestTask.new do |t|
6
+ t.test_files = Dir.glob('test/**/*_test.rb')
7
+ end
8
+
9
+ task(default: :test)
@@ -0,0 +1,27 @@
1
+ require_relative 'odnoklassniki/error'
2
+ require_relative 'odnoklassniki/version'
3
+ require_relative 'odnoklassniki/client'
4
+ require_relative 'odnoklassniki/config'
5
+
6
+ module Odnoklassniki
7
+
8
+ class << self
9
+ attr_accessor :config
10
+
11
+ def new(options = {})
12
+ Odnoklassniki::Client.new(options)
13
+ end
14
+
15
+ def configure
16
+ @config = Odnoklassniki::Config.new
17
+ yield @config
18
+ @config
19
+ end
20
+
21
+ def options
22
+ (@config && @config.options) || {}
23
+ end
24
+
25
+ end
26
+
27
+ end
@@ -0,0 +1,75 @@
1
+ require_relative 'request'
2
+
3
+ module Odnoklassniki
4
+ class Client
5
+
6
+ def initialize(attrs= {})
7
+ attrs = Odnoklassniki.options.merge(attrs)
8
+ Config::VALID_OPTIONS_KEYS.each do |key|
9
+ instance_variable_set("@#{key}".to_sym, attrs[key])
10
+ end
11
+ @refreshed = false
12
+ end
13
+
14
+ def get(method, params={})
15
+ request_method(:get, method, params)
16
+ end
17
+
18
+ def post(method, params={})
19
+ request_method(:post, method, params)
20
+ end
21
+
22
+ def refresh_token!
23
+ @refreshed = true
24
+ data = request.post('/oauth/token.do', refresh_credentials)
25
+ @request = nil
26
+ @access_token = data['access_token']
27
+ end
28
+
29
+ private
30
+
31
+ def fallback(params)
32
+ [params.delete(:method), params]
33
+ end
34
+
35
+ def method_path(method)
36
+ if method.start_with?('api')
37
+ "/#{method}"
38
+ elsif method.start_with?('/api')
39
+ method
40
+ elsif method.start_with?('/')
41
+ "/api#{method}"
42
+ else
43
+ "/api/#{method}"
44
+ end.gsub('.', '/')
45
+ end
46
+
47
+ def refresh_credentials
48
+ {
49
+ refresh_token: @access_token,
50
+ grant_type: 'refresh_token',
51
+ client_id: @client_id,
52
+ client_secret: @client_secret
53
+ }
54
+ end
55
+
56
+ def request_method(http_method, method, params)
57
+ method, params = fallback(method) if method.is_a?(Hash)
58
+ request.send(http_method, method_path(method), params)
59
+ end
60
+
61
+ def request
62
+ refresh_token! unless @refreshed
63
+ @request ||= Request.new(credentials)
64
+ end
65
+
66
+ def credentials
67
+ {
68
+ access_token: @access_token,
69
+ client_secret: @client_secret,
70
+ application_key: @application_key
71
+ }
72
+ end
73
+
74
+ end
75
+ end
@@ -0,0 +1,31 @@
1
+ module Odnoklassniki
2
+ class Config
3
+
4
+ VALID_OPTIONS_KEYS = [:access_token,
5
+ :client_id,
6
+ :client_secret,
7
+ :application_key].freeze
8
+
9
+ attr_accessor *VALID_OPTIONS_KEYS
10
+
11
+ def self.configure
12
+ config = self.new
13
+ yield config
14
+ config
15
+ end
16
+
17
+ def initialize(options={})
18
+ @access_token = options[:access_token] || options['access_token']
19
+ @client_id = options[:client_id] || options['client_id']
20
+ @client_secret = options[:client_secret] || options['client_secret']
21
+ @application_key = options[:application_key] || options['application_key']
22
+ end
23
+
24
+ def options
25
+ options = {}
26
+ VALID_OPTIONS_KEYS.each{ |pname| options[pname] = send(pname) }
27
+ options
28
+ end
29
+
30
+ end
31
+ end
@@ -0,0 +1,29 @@
1
+ require 'faraday'
2
+ require 'faraday_middleware'
3
+
4
+ module Odnoklassniki
5
+ module Connection
6
+ API_HOST = 'http://api.odnoklassniki.ru'
7
+
8
+ def connection(options={})
9
+ options = options.clone
10
+
11
+ default_options = {
12
+ :headers => {
13
+ :accept => 'application/json',
14
+ :user_agent => "odnoklassniki ruby gem/#{Odnoklassniki::VERSION}"
15
+ },
16
+ :url => "#{API_HOST}/"
17
+ }
18
+
19
+ client = Faraday.default_adapter
20
+
21
+ Faraday.new(default_options.merge(options)) do |conn|
22
+ conn.request :multipart
23
+ conn.request :url_encoded
24
+ conn.adapter client
25
+ end
26
+ end
27
+
28
+ end
29
+ end
@@ -0,0 +1,182 @@
1
+ # Taken and adopted from https://github.com/sferik/twitter gem
2
+ module Odnoklassniki
3
+ # Custom error class for rescuing from all Odnoklassniki errors
4
+ class Error < StandardError
5
+ # @return [Integer]
6
+ attr_reader :code
7
+
8
+ # Raised when Odnoklassniki returns a 2xx HTTP status code
9
+ ClientError = Class.new(self)
10
+
11
+ # Raised when Odnoklassniki returns the HTTP status code 400
12
+ BadRequest = Class.new(ClientError)
13
+
14
+ # Raised when Odnoklassniki returns the HTTP status code 401
15
+ Unauthorized = Class.new(ClientError)
16
+
17
+ # Raised when Odnoklassniki returns the HTTP status code 403
18
+ Forbidden = Class.new(ClientError)
19
+
20
+ # Raised when Odnoklassniki returns the HTTP status code 404
21
+ NotFound = Class.new(ClientError)
22
+
23
+ # Raised when Odnoklassniki returns the HTTP status code 406
24
+ NotAcceptable = Class.new(ClientError)
25
+
26
+ # Raised when Odnoklassniki returns the HTTP status code 422
27
+ UnprocessableEntity = Class.new(ClientError)
28
+
29
+ # Raised when Odnoklassniki returns the HTTP status code 429
30
+ TooManyRequests = Class.new(ClientError)
31
+
32
+ # Raised when Odnoklassniki returns a 5xx HTTP status code
33
+ ServerError = Class.new(self)
34
+
35
+ # Raised when Odnoklassniki returns the HTTP status code 500
36
+ InternalServerError = Class.new(ServerError)
37
+
38
+ # Raised when Odnoklassniki returns the HTTP status code 502
39
+ BadGateway = Class.new(ServerError)
40
+
41
+ # Raised when Odnoklassniki returns the HTTP status code 503
42
+ ServiceUnavailable = Class.new(ServerError)
43
+
44
+ # Raised when Odnoklassniki returns the HTTP status code 504
45
+ GatewayTimeout = Class.new(ServerError)
46
+
47
+ ERRORS = {
48
+ 200 => Odnoklassniki::Error::ClientError,
49
+ 400 => Odnoklassniki::Error::BadRequest,
50
+ 401 => Odnoklassniki::Error::Unauthorized,
51
+ 403 => Odnoklassniki::Error::Forbidden,
52
+ 404 => Odnoklassniki::Error::NotFound,
53
+ 406 => Odnoklassniki::Error::NotAcceptable,
54
+ 422 => Odnoklassniki::Error::UnprocessableEntity,
55
+ 429 => Odnoklassniki::Error::TooManyRequests,
56
+ 500 => Odnoklassniki::Error::InternalServerError,
57
+ 502 => Odnoklassniki::Error::BadGateway,
58
+ 503 => Odnoklassniki::Error::ServiceUnavailable,
59
+ 504 => Odnoklassniki::Error::GatewayTimeout,
60
+ }
61
+
62
+ module Code
63
+ UNKNOWN = 1 # Unknown error
64
+ SERVICE = 2 # Service temporary unavailable
65
+ METHOD = 3 # Method does not exist.
66
+ REQUEST = 4 # Failed to process request due to invalid request
67
+ ACTION_BLOCKED = 7 # The requested action is temporarily blocked for current user
68
+ FLOOD_BLOCKED = 8 # The execution of method is blocked due to flood
69
+ IP_BLOCKED = 9 # The execution of method is blocked by IP address due to suspicious activity of current user or due to other restrictions applied to given method
70
+ PERMISSION_DENIED = 10 # Permission denied. Possible reason - user not authorized application to perform operation
71
+ LIMIT_REACHED = 11 # Method invocation limit reached
72
+ CANCELLED = 12 # Operation was cancelled by user
73
+ NOT_MULTIPART = 21 # Not a multi-part request when uploading photo
74
+ NOT_ACTIVATED = 22 # User must activate his profile to complete the action
75
+ NOT_YET_INVOLVED = 23 # User not involved to the application - see notes (in russian)
76
+ NOT_OWNER = 24 # User does not own specified object
77
+ NOT_ACTIVE = 25 # Notification sending error. User not active in application.
78
+ TOTAL_LIMIT_REACHED = 26 # Notification sending error. Notification limit reached. notes (in russian)
79
+ PARAM = 100 # Missing or invalid parameter
80
+ PARAM_API_KEY = 101 # Parameter application_key not specified or invalid
81
+ PARAM_SESSION_EXPIRED = 102 # Session key is expired
82
+ PARAM_SESSION_KEY = 103 # Invalid session key
83
+ PARAM_SIGNATURE = 104 # Invalid signature
84
+ PARAM_RESIGNATURE = 105 # Invalid re-signature
85
+ PARAM_ENTITY_ID = 106 # Invalid entity ID (discussions)
86
+ PARAM_USER_ID = 110 # Invalid user ID
87
+ PARAM_ALBUM_ID = 120 # Invalid album ID
88
+ PARAM_PHOTO_ID = 121 # Invalid photo ID
89
+ PARAM_WIDGET = 130 # Invalid Widget ID
90
+ PARAM_MESSAGE_ID = 140 # Invalid message ID
91
+ PARAM_COMMENT_ID = 141 # Invalid comment ID
92
+ PARAM_HAPPENING_ID = 150 # Invalid happening ID
93
+ PARAM_HAPPENING_PHOTO_ID = 151 # Invalid happening photo ID
94
+ PARAM_GROUP_ID = 160 # Invalid group ID
95
+ PARAM_PERMISSION = 200 # Application can not perform operation. In most cases, caused by access to operation without user authorization
96
+ PARAM_APPLICATION_DISABLED = 210 # Application is disabled
97
+ PARAM_DECISION = 211 # Invalid decision ID
98
+ PARAM_BADGE_ID = 212 # Invalid badge ID
99
+ PARAM_PRESENT_ID = 213 # Invalid present ID
100
+ PARAM_RELATION_TYPE = 214 # Invalid relation type
101
+ NOT_FOUND = 300 # Requested information is not found
102
+ EDIT_PHOTO_FILE = 324 # Error processing multi-part request
103
+ AUTH_LOGIN = 401 # Authentication failure. Invalid login/password or authentication token or user is deleted/blocked.
104
+ AUTH_LOGIN_CAPTCHA = 402 # Authentication failure. Captcha entry is required for login.
105
+ AUTH_LOGIN_WEB_HUMAN_CHECK = 403 # Authentication failure.
106
+ NOT_SESSION_METHOD = 451 # Session is prohibited for the method, but session key was specified
107
+ SESSION_REQUIRED = 453 # Session key was not specified for the method, which requires session
108
+ CENSOR_MATCH = 454 # Text rejected by censor
109
+ FRIEND_RESTRICTION = 455 # Cannot perform operation because friend set restriction on it (put to "black list" or made his/her account private)
110
+ GROUP_RESTRICTION = 456 # Cannot perform operation because group set restriction on it
111
+ UNAUTHORIZED_RESTRICTION = 457 # Unauthorized access
112
+ PRIVACY_RESTRICTION = 458 # Same as FRIEND_RESTRICTION
113
+ PHOTO_SIZE_LIMIT_EXCEEDED = 500 # The size in bytes of image binary content exceeds the limits
114
+ PHOTO_SIZE_TOO_SMALL = 501 # The image size in pixels are too small
115
+ PHOTO_SIZE_TOO_BIG = 502 # The image size in pixels are too big
116
+ PHOTO_INVALID_FORMAT = 503 # The image format cannot be recognized
117
+ PHOTO_IMAGE_CORRUPTED = 504 # The image format is recognized, but the content is corrupted
118
+ PHOTO_NO_IMAGE = 505 # No image is found in request
119
+ PHOTO_PIN_TOO_MUCH = 508 # Too much photopin's on photo.
120
+ IDS_BLOCKED = 511 # Photopin error from antispam system
121
+ PHOTO_ALBUM_NOT_BELONGS_TO_USER = 512 # Album not belongs to the user
122
+ PHOTO_ALBUM_NOT_BELONGS_TO_GROUP = 513 # Album not belongs to the specified group
123
+ MEDIA_TOPIC_BLOCK_LIMIT = 600 # Too many media parameters
124
+ MEDIA_TOPIC_TEXT_LIMIT = 601 # Text limit reached
125
+ MEDIA_TOPIC_POLL_QUESTION_TEXT_LIMIT = 602 # Question text limit reached
126
+ MEDIA_TOPIC_POLL_ANSWERS_LIMIT = 603 # Too many answer parameters
127
+ MEDIA_TOPIC_POLL_ANSWER_TEXT_LIMIT = 604 # Answer text limit reached
128
+ MEDIA_TOPIC_WITH_FRIENDS_LIMIT = 605 # Pinned friends count limit reached
129
+ MEDIA_TOPIC_WITH_FRIENDS_USER_LIMIT = 606 # Pinned friends count limit reached (user-specific)
130
+ GROUP_DUPLICATE_JOIN_REQUEST = 610 # Group join request already registered.
131
+ COMMENT_NOT_FOUND = 700 # Comment not found
132
+ INVALID_AUTHOR = 701 # Invalid author
133
+ COMMENT_NOT_ACTIVE = 702 # Comment was removed
134
+ TIMEOUT_EXCEEDED = 704 # Edit timeout exceeded
135
+ CHAT_NOT_FOUND = 705 # Chat not found
136
+ MESSAGE_NOT_ACTIVE = 706 # Message was removed
137
+ NO_SUCH_APP = 900 # Returned, when try to get public application information for not existing application
138
+ CALLBACK_INVALID_PAYMENT = 1001 # Error returned by the application server to notify about invalid transaction details
139
+ PAYMENT_IS_REQUIRED_PAYMENT = 1002 # Payment is required to use service
140
+ INVALID_PAYMENT = 1003 # Invalid payment transaction
141
+ DUPLICATE_PAYMENT = 1004 # Instant payment is too frequent
142
+ NOT_ENOUGH_MONEY = 1005 # User has no requested amount of money on his account
143
+ VCHAT_SERVICE_DISABLED = 1101 # Video chat is disabled.
144
+ TARGET_USER_UNAVAILABLE = 1102 # Target user is not available for video chat or video message/
145
+ FRIENDSHIP_REQUIRED = 1103 # Target user must be a friend.
146
+ BATCH = 1200 # Batching error.
147
+ APP_NO_PLATFORM_ALLOWED = 1300 # No platforms allowed for this application
148
+ APP_DEVICE_NOT_ALLOWED = 1301 # Specified device not allowed
149
+ APP_DEVICE_NOT_SPECIFIED = 1302 # Device not specified
150
+ APP_EMPTY_SEARCH_PARAMS = 1400 # Location search error.
151
+ APP_SEARCH_SCENARIO_DOES_NOT_EXIST = 1401 # Location search error.
152
+ SYSTEM = 9999 # Critical system error. Please report these problems support
153
+ end
154
+
155
+ class << self
156
+ # Create a new error from an HTTP response
157
+ #
158
+ # @param response [HTTP::Response]
159
+ # @return [Odnoklassniki::Error]
160
+ def from_response(body)
161
+ new(*parse_error(body))
162
+ end
163
+
164
+ private
165
+
166
+ def parse_error(body)
167
+ [body['error_msg'].to_s, body['error_code']]
168
+ end
169
+
170
+ end
171
+
172
+ # Initializes a new Error object
173
+ #
174
+ # @param message [Exception, String]
175
+ # @param code [Integer]
176
+ # @return [Odnoklassniki::Error]
177
+ def initialize(message = '', code = nil)
178
+ super(message)
179
+ @code = code
180
+ end
181
+ end
182
+ end