yandex_client 0.1.0 → 1.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/.travis.yml DELETED
@@ -1,12 +0,0 @@
1
- sudo: false
2
- language: ruby
3
- rvm:
4
- - 2.6.3
5
- before_install: gem install bundler
6
- before_script:
7
- - bundle install
8
- script: bundle exec rspec
9
- notifications:
10
- email:
11
- on_success: never
12
- on_failure: always
@@ -1,9 +0,0 @@
1
- FROM ruby:2.6.3
2
-
3
- RUN ln -fs /usr/share/zoneinfo/Asia/Yekaterinburg /etc/localtime \
4
- && dpkg-reconfigure -f noninteractive tzdata
5
-
6
- RUN echo 'gem: --no-rdoc --no-ri --no-document' > /root/.gemrc
7
- RUN gem install bundler
8
-
9
- WORKDIR /app
@@ -1,18 +0,0 @@
1
- version: '2'
2
-
3
- services:
4
- app:
5
- volumes:
6
- - ..:/app
7
- - ../:/localgems
8
- - ssh-data:/ssh:ro
9
- - bundler-data:/bundle
10
-
11
- volumes:
12
- bundler-data:
13
- external:
14
- name: bundler_data
15
-
16
- ssh-data:
17
- external:
18
- name: ssh_data
@@ -1,13 +0,0 @@
1
- module YandexClient
2
- class ApiRequestError < StandardError
3
- attr_reader :error, :error_description, :code
4
-
5
- def initialize(error:, error_description:, code:)
6
- @error = error
7
- @error_description = error_description
8
- @code = code
9
-
10
- super [error, error_description, "http code #{@code}"].compact.join(', ')
11
- end
12
- end
13
- end
@@ -1,55 +0,0 @@
1
- require 'uri'
2
-
3
- module YandexClient
4
- module Auth
5
- # https://tech.yandex.ru/oauth/doc/dg/reference/refresh-client-docpage/
6
- # https://tech.yandex.ru/oauth/doc/dg/reference/auto-code-client-docpage/#auto-code-client__get-token
7
- #
8
- # https://oauth.yandex.ru/authorize?response_type=code&client_id=99bcbd17ad7f411694710592d978a4a2&force_confirm=false
9
- #
10
- # Example:
11
- # token = Token.first
12
- #
13
- # client = YandexClient::Auth::Client.new
14
- # client.create_token(code: '9388894')
15
- # client.refresh_token(refresh_token: token.refresh_token)
16
- class Client < ::YandexClient::Client
17
- AUTH_ACTION_URL = 'https://oauth.yandex.ru/token'.freeze
18
-
19
- ACTIONS = {
20
- create_token: 'authorization_code',
21
- refresh_token: 'refresh_token'
22
- }.freeze
23
-
24
- private
25
-
26
- def http(_request_uri)
27
- @http ||= super
28
- end
29
-
30
- def http_method_for_action
31
- METHOD_POST
32
- end
33
-
34
- def request_body(params)
35
- body_hash = {
36
- grant_type: ACTIONS.fetch(@action),
37
- client_id: ::YandexClient.config.api_key,
38
- client_secret: ::YandexClient.config.api_secret
39
- }.merge!(params)
40
-
41
- URI.encode_www_form(body_hash)
42
- end
43
-
44
- def request_headers(_params)
45
- {
46
- 'Content-type' => 'application/x-www-form-urlencoded'
47
- }
48
- end
49
-
50
- def request_uri(_params)
51
- @request_uri ||= URI.parse(AUTH_ACTION_URL)
52
- end
53
- end
54
- end
55
- end
@@ -1,97 +0,0 @@
1
- require 'oj'
2
- require 'net/http'
3
-
4
- module YandexClient
5
- # Base api client
6
- class Client
7
- TIMEOUT = 10
8
- METHOD_GET = 'Get'.freeze
9
- METHOD_POST = 'Post'.freeze
10
-
11
- ERRORS_BY_CODES = {
12
- 404 => NotFoundError
13
- }.freeze
14
-
15
- def method_missing(method_name, *args, &_)
16
- return super unless self.class::ACTIONS.include?(method_name)
17
-
18
- @action = method_name
19
- result = nil
20
- response = make_request(args.last.is_a?(Hash) ? args.last : {})
21
-
22
- result = parse_response_body(response) unless response.body.nil? || response.body.empty?
23
- process_errors(response, result) unless response.is_a?(Net::HTTPSuccess)
24
-
25
- result
26
- end
27
-
28
- def respond_to_missing?(method_name, include_private = false)
29
- self.class::ACTIONS.include?(method_name) || super
30
- end
31
-
32
- private
33
-
34
- def http(request_uri)
35
- Net::HTTP.new(request_uri.host, request_uri.port).tap do |http|
36
- http.use_ssl = true
37
- http.read_timeout = TIMEOUT
38
- http.continue_timeout = TIMEOUT
39
- end
40
- end
41
-
42
- def http_method_for_action
43
- METHOD_GET
44
- end
45
-
46
- def log_api_request(request_uri, request, response)
47
- return if (logger = YandexClient.config.logger).nil?
48
-
49
- logger.info "#{request.method} #{request_uri} #{response.code} #{response.message}"
50
- logger.info "request headers: #{Oj.dump(request.to_hash)}"
51
- logger.info "response headers: #{Oj.dump(response.to_hash)}"
52
- end
53
-
54
- def make_request(params)
55
- request_uri = request_uri(params)
56
- @body = request_body(params)
57
-
58
- request = Object.const_get("Net::HTTP::#{http_method_for_action}").new(
59
- request_uri.request_uri,
60
- request_headers(params)
61
- )
62
-
63
- request.body = @body
64
- response = http(request_uri).start { |http| http.request(request) }
65
-
66
- log_api_request(request_uri, request, response)
67
-
68
- response
69
- end
70
-
71
- def parse_response_body(response)
72
- Oj.load(response.body, symbol_keys: true)
73
- end
74
-
75
- def process_errors(response, result)
76
- klass = ERRORS_BY_CODES.fetch(response.code.to_i, ApiRequestError)
77
-
78
- raise klass.new(
79
- error: result.is_a?(Hash) ? result&.fetch(:error) : result,
80
- error_description: result.is_a?(Hash) ? result&.fetch(:error_description) : nil,
81
- code: response.code.to_i
82
- )
83
- end
84
-
85
- def request_body(_params)
86
-
87
- end
88
-
89
- def request_headers(_params)
90
- {}
91
- end
92
-
93
- def request_uri(_params)
94
- raise 'not implemented'
95
- end
96
- end
97
- end
@@ -1,115 +0,0 @@
1
- require 'digest'
2
-
3
- module YandexClient
4
- module Dav
5
- # https://tech.yandex.ru/disk/doc/dg/reference/put-docpage/
6
- #
7
- # cli = YandexClient::Dav::Client.new(access_token: access_token)
8
- #
9
- # cli.put(file: '1.txt', name: '/a/b/c/1.txt')
10
- # cli.delete(name: '/a/b/c/1.txt')
11
- # cli.mkcol(name: '/a/b/c')
12
- #
13
- # cli.propfind(name: '/a/dip.yml', depth: 0)
14
- # cli.propfind(name: '/a', depth: 1)
15
- # cli.propfind(name: '/', quota: true)
16
- class Client < ::YandexClient::Client
17
- ACTION_URL = 'https://webdav.yandex.ru'.freeze
18
- PROPFIND_QUERY = '<?xml version="1.0" encoding="utf-8"?><propfind xmlns="DAV:"></propfind>'.freeze
19
- PROPFIND_QUOTA_QUERY = <<~XML.freeze
20
- <D:propfind xmlns:D="DAV:">
21
- <D:prop>
22
- <D:quota-available-bytes/>
23
- <D:quota-used-bytes/>
24
- </D:prop>
25
- </D:propfind>
26
- XML
27
-
28
- # actions with header processors
29
- ACTIONS = {
30
- mkcol: nil,
31
- delete: nil,
32
-
33
- put: lambda do |params|
34
- filename = params.fetch(:file)
35
-
36
- etag = params[:etag] || Digest::MD5.file(filename)
37
- sha256 = params[:sha256] || Digest::SHA256.file(filename)
38
- size = params[:size] || File.size(filename)
39
-
40
- {
41
- Etag: etag.to_s,
42
- Sha256: sha256.to_s,
43
- Expect: '100-continue',
44
- 'Content-Length' => size.to_s
45
- }
46
- end,
47
-
48
- propfind: lambda do |params|
49
- depth = 0
50
- depth = params.fetch(:depth, 0) unless params.key?(:quota)
51
-
52
- headers = {
53
- Depth: depth.to_s,
54
- 'Content-Type' => 'application/x-www-form-urlencoded'
55
- }
56
-
57
- headers['Content-Length'] = @body.length unless @body.nil? || @body.empty?
58
- headers
59
- end
60
- }.freeze
61
-
62
- BODY_PROCESSORS = {
63
- put: ->(params) { File.read(params.fetch(:file)) },
64
- propfind: lambda do |params|
65
- if params.fetch(:quota, false)
66
- PROPFIND_QUOTA_QUERY
67
- elsif params.fetch(:depth, 0).zero?
68
- PROPFIND_QUERY
69
- end
70
- end
71
- }.freeze
72
-
73
- RESPONSE_PARSERS = {
74
- propfind: PropfindParser
75
- }.freeze
76
-
77
- def initialize(access_token:)
78
- @access_token = access_token
79
- end
80
-
81
- private
82
-
83
- def http_method_for_action
84
- @action.to_s.capitalize
85
- end
86
-
87
- def parse_response_body(response)
88
- if response.is_a?(Net::HTTPSuccess) && !(parser = RESPONSE_PARSERS[@action]).nil?
89
- parser.call(response.body)
90
- else
91
- response.body
92
- end
93
- end
94
-
95
- def request_body(params)
96
- return if (proc = BODY_PROCESSORS[@action]).nil?
97
-
98
- proc.call(params)
99
- end
100
-
101
- def request_headers(params)
102
- proc = ACTIONS.fetch(@action)
103
-
104
- headers = {Authorization: "OAuth #{@access_token}"}
105
- headers.merge!(proc.call(params)) unless proc.nil?
106
-
107
- headers
108
- end
109
-
110
- def request_uri(params)
111
- URI.parse("#{ACTION_URL}#{params.fetch(:name)}")
112
- end
113
- end
114
- end
115
- end
@@ -1,48 +0,0 @@
1
- require 'ox'
2
- require 'cgi'
3
-
4
- module YandexClient
5
- module Dav
6
- class PropfindParser
7
- SUCCESS_STATUS = 'HTTP/1.1 200 OK'.freeze
8
-
9
- PROCESSORS = {
10
- getcontentlength: ->(value) { value.to_i },
11
- resourcetype: ->(value) { value.is_a?(Hash) ? :folder : :file }
12
- }.freeze
13
-
14
- class ParseError < StandardError
15
- end
16
-
17
- def initialize(xml)
18
- @document = Ox.load(xml.force_encoding('UTF-8'), mode: :hash)
19
- end
20
-
21
- def call
22
- @document[:'d:multistatus'].each_with_object({}) do |node, memo|
23
- next if (response = node[:'d:response']).nil?
24
-
25
- name = CGI.unescape(response.fetch(:'d:href'))
26
- memo[name] = parse_node_props(response.fetch(:'d:propstat'))
27
- end
28
- end
29
-
30
- def self.call(xml)
31
- new(xml).call
32
- end
33
-
34
- private
35
-
36
- def parse_node_props(node)
37
- raise ParseError unless node.fetch(:'d:status') == SUCCESS_STATUS
38
-
39
- node.fetch(:'d:prop').each_with_object({}) do |(key, value), memo|
40
- prop_key = key.to_s.gsub(/^d:/, '').to_sym
41
- processor = PROCESSORS[prop_key]
42
-
43
- memo[prop_key] = processor.nil? ? value : processor.call(value)
44
- end
45
- end
46
- end
47
- end
48
- end
@@ -1,4 +0,0 @@
1
- module YandexClient
2
- class NotFoundError < ApiRequestError
3
- end
4
- end
@@ -1,34 +0,0 @@
1
- module YandexClient
2
- module Passport
3
- # https://tech.yandex.ru/passport/doc/dg/reference/request-docpage/
4
- #
5
- # Example:
6
- # client = YandexClient::Passport::Client.new(access_token: Token.first.access_token)
7
- # client.info
8
- class Client < ::YandexClient::Client
9
- ACTION_URL = 'https://login.yandex.ru/info'.freeze
10
- ACTIONS = %i[info].freeze
11
-
12
- # action - info
13
- def initialize(access_token:)
14
- @access_token = access_token
15
- end
16
-
17
- private
18
-
19
- def http(_request_uri)
20
- @http ||= super
21
- end
22
-
23
- def request_uri(_params)
24
- @request_uri ||= URI.parse(ACTION_URL)
25
- end
26
-
27
- def request_headers(_params)
28
- {
29
- Authorization: "Bearer #{@access_token}"
30
- }
31
- end
32
- end
33
- end
34
- end