yandex_client 0.2.0 → 1.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,104 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'digest'
4
+ require 'http'
5
+ require 'yandex_client/dav/prop_find_response'
6
+
7
+ module YandexClient
8
+ # https://tech.yandex.ru/disk/doc/dg/reference/put-docpage/
9
+ #
10
+ # Chainable client:
11
+ #
12
+ # YandexClient::Dav[access_token]
13
+ # .put('1.txt', '/a/b/c/1.txt')
14
+ # .put(File.open('1.txt', 'rb'), '/path/to/1.txt')
15
+ # .put(Tempfile.new.tap { |t| t.write('say ni'); t.rewind }, '/path/to/tmp.txt')
16
+ # .delete('/a/b/c/1.txt')
17
+ # .mkcol('/a/b/c')
18
+ # .propfind('/a/dip.yml', depth: 0)
19
+ # .propfind('/a', depth: 1)
20
+ # .propfind.to_a
21
+ class Dav
22
+ include Configurable
23
+ include ErrorHandler
24
+
25
+ ACTION_URL = 'https://webdav.yandex.ru'
26
+ PROPFIND_QUERY = '<?xml version="1.0" encoding="utf-8"?><propfind xmlns="DAV:"></propfind>'
27
+
28
+ attr_reader :token
29
+
30
+ class << self
31
+ def with_token(token)
32
+ new(token)
33
+ end
34
+
35
+ alias [] with_token
36
+ end
37
+
38
+ def initialize(token)
39
+ @token = token
40
+ end
41
+
42
+ def put(file, dest, etag: nil, sha256: nil, size: nil)
43
+ io = file.is_a?(String) ? File.open(file, 'rb') : file
44
+
45
+ headers = auth_headers.merge!(
46
+ 'Etag' => etag || Digest::MD5.file(io.path),
47
+ 'Sha256' => sha256 || Digest::SHA256.file(io.path),
48
+ 'Expect' => '100-continue',
49
+ 'Content-Length' => (size || File.size(io.path)).to_s
50
+ )
51
+
52
+ process_response with_config.put(url_for(dest), body: io, headers: headers)
53
+ end
54
+
55
+ def delete(dest)
56
+ process_response with_config.delete(
57
+ url_for(dest),
58
+ headers: auth_headers
59
+ )
60
+ end
61
+
62
+ def mkcol(dest)
63
+ process_response with_config.request(
64
+ :mkcol,
65
+ url_for(dest),
66
+ headers: auth_headers
67
+ )
68
+ end
69
+
70
+ def propfind(dest = '', depth = 1)
71
+ headers = auth_headers.merge!(
72
+ Depth: depth.to_s,
73
+ 'Content-Type' => 'application/x-www-form-urlencoded',
74
+ 'Content-Length' => PROPFIND_QUERY.length
75
+ )
76
+
77
+ response = with_config.request(:propfind, url_for(dest), headers: headers, body: PROPFIND_QUERY)
78
+ process_response(response)
79
+
80
+ PropFindResponse.new(response.body.to_s)
81
+ end
82
+
83
+ private
84
+
85
+ def auth_headers
86
+ {Authorization: "OAuth #{token}"}
87
+ end
88
+
89
+ def url_for(dest)
90
+ URI.parse(ACTION_URL).tap do |uri|
91
+ path = dest
92
+ path = "/#{path}" unless path.match?(%r{^/})
93
+
94
+ uri.path = path
95
+ end
96
+ end
97
+
98
+ def process_response(response)
99
+ return self if response.status.success?
100
+
101
+ error_for_response(response)
102
+ end
103
+ end
104
+ end
@@ -0,0 +1,60 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'json'
4
+
5
+ module YandexClient
6
+ # https://yandex.ru/dev/disk/api/reference/capacity-docpage/
7
+ # https://yandex.ru/dev/disk/api/reference/content-docpage/
8
+ #
9
+ # YandexClient::Disk[access_token].info
10
+ # YandexClient::Disk[access_token].download_url('path/to/file')
11
+ class Disk
12
+ include Configurable
13
+ include ErrorHandler
14
+
15
+ ACTION_URL = 'https://cloud-api.yandex.net'
16
+
17
+ attr_reader :token
18
+
19
+ class << self
20
+ def with_token(token)
21
+ new(token)
22
+ end
23
+
24
+ alias [] with_token
25
+ end
26
+
27
+ def initialize(token)
28
+ @token = token
29
+ end
30
+
31
+ def info
32
+ process_response(
33
+ with_config.get("#{ACTION_URL}/v1/disk/", headers: auth_headers)
34
+ )
35
+ end
36
+
37
+ def download_url(path)
38
+ url = URI.parse(ACTION_URL).tap do |uri|
39
+ uri.path = '/v1/disk/resources/download'
40
+ uri.query = URI.encode_www_form(path: path)
41
+ end
42
+
43
+ process_response(
44
+ with_config.get(url, headers: auth_headers)
45
+ ).fetch(:href)
46
+ end
47
+
48
+ private
49
+
50
+ def auth_headers
51
+ {Authorization: "OAuth #{@token}"}
52
+ end
53
+
54
+ def process_response(response)
55
+ return JSON.parse(response.body, symbolize_names: true) if response.status.success?
56
+
57
+ error_for_response(response)
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ module YandexClient
4
+ module ErrorHandler
5
+ private
6
+
7
+ def error_for_response(response)
8
+ msg = response.body.empty? ? response.status.to_s : response.body.to_s.force_encoding('UTF-8')
9
+ err =
10
+ case response.code
11
+ when 404
12
+ NotFoundError.new(msg, http_code: 404)
13
+ else
14
+ ApiRequestError.new(msg, http_code: response.code)
15
+ end
16
+
17
+ raise err
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ module YandexClient
4
+ # https://tech.yandex.ru/passport/doc/dg/reference/request-docpage/
5
+ #
6
+ # Example:
7
+ # YandexClient::Passport::Client[Token.first.access_token].info
8
+ class Passport
9
+ include Configurable
10
+ include ErrorHandler
11
+
12
+ ACTION_URL = 'https://login.yandex.ru/info'
13
+
14
+ attr_reader :token
15
+
16
+ class << self
17
+ def with_token(token)
18
+ new(token)
19
+ end
20
+
21
+ alias [] with_token
22
+ end
23
+
24
+ def initialize(token)
25
+ @token = token
26
+ end
27
+
28
+ def info
29
+ process_response \
30
+ with_config.get(ACTION_URL, headers: auth_headers)
31
+ end
32
+
33
+ private
34
+
35
+ def auth_headers
36
+ {Authorization: "Bearer #{@token}"}
37
+ end
38
+
39
+ def process_response(response)
40
+ return JSON.parse(response.body, symbolize_names: true) if response.status.success?
41
+
42
+ error_for_response(response)
43
+ end
44
+ end
45
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module YandexClient
4
- VERSION = '0.2.0'
4
+ VERSION = '1.0.1'
5
5
  end
data/lib/yandex_client.rb CHANGED
@@ -2,35 +2,50 @@
2
2
 
3
3
  require 'yandex_client/version'
4
4
 
5
- module YandexClient
6
- Config = Struct.new(:api_key, :api_secret, :logger, :read_timeout)
5
+ require 'yandex_client/error_handler'
6
+ require 'yandex_client/configurable'
7
7
 
8
- def self.config
9
- @config ||= Config.new(nil, nil, nil, 10)
10
- end
8
+ require 'yandex_client/dav'
9
+ require 'yandex_client/disk'
10
+ require 'yandex_client/auth'
11
+ require 'yandex_client/passport'
11
12
 
12
- def self.configure
13
- yield config
13
+ module YandexClient
14
+ Config = Struct.new \
15
+ :api_key,
16
+ :api_secret,
17
+ :logger,
18
+ :read_timeout,
19
+ :write_timeout,
20
+ :connect_timeout
21
+
22
+ class ApiRequestError < StandardError
23
+ attr_reader :http_code
24
+
25
+ def initialize(msg = nil, http_code: nil)
26
+ if http_code
27
+ super "#{msg}, (http code #{http_code})"
28
+ else
29
+ super msg
30
+ end
31
+
32
+ @http_code = http_code
33
+ end
14
34
  end
15
35
 
16
- autoload :Client, 'yandex_client/client'
17
- autoload :ApiRequestError, 'yandex_client/api_request_error'
18
- autoload :NotFoundError, 'yandex_client/not_found_error'
36
+ NotFoundError = Class.new(ApiRequestError)
19
37
 
20
- module Auth
21
- autoload :Client, 'yandex_client/auth/client'
22
- end
38
+ class << self
39
+ def config
40
+ @config ||= Config.new(nil, nil, nil, 120, 600, 5)
41
+ end
23
42
 
24
- module Disk
25
- autoload :Client, 'yandex_client/disk/client'
26
- end
27
-
28
- module Passport
29
- autoload :Client, 'yandex_client/passport/client'
30
- end
43
+ def configure
44
+ yield config
45
+ end
31
46
 
32
- module Dav
33
- autoload :Client, 'yandex_client/dav/client'
34
- autoload :PropfindParser, 'yandex_client/dav/propfind_parser'
47
+ def auth
48
+ @auth ||= Auth.new
49
+ end
35
50
  end
36
51
  end
@@ -23,12 +23,13 @@ Gem::Specification.new do |spec|
23
23
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
24
24
  spec.require_paths = ['lib']
25
25
 
26
- spec.add_runtime_dependency 'oj'
26
+ spec.add_runtime_dependency 'http'
27
27
  spec.add_runtime_dependency 'ox'
28
28
 
29
29
  spec.add_development_dependency 'bundler'
30
30
  spec.add_development_dependency 'rake', '>= 10'
31
31
  spec.add_development_dependency 'rspec', '>= 3.0'
32
+ spec.add_development_dependency 'simplecov', '>= 0.9'
32
33
  spec.add_development_dependency 'vcr'
33
34
  spec.add_development_dependency 'webmock'
34
35
 
metadata CHANGED
@@ -1,17 +1,17 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: yandex_client
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 1.0.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Maxim Tretyakov
8
- autorequire:
8
+ autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2020-01-24 00:00:00.000000000 Z
11
+ date: 2021-08-27 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
- name: oj
14
+ name: http
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
17
  - - ">="
@@ -80,6 +80,20 @@ dependencies:
80
80
  - - ">="
81
81
  - !ruby/object:Gem::Version
82
82
  version: '3.0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: simplecov
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0.9'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0.9'
83
97
  - !ruby/object:Gem::Dependency
84
98
  name: vcr
85
99
  requirement: !ruby/object:Gem::Requirement
@@ -115,10 +129,11 @@ executables: []
115
129
  extensions: []
116
130
  extra_rdoc_files: []
117
131
  files:
132
+ - ".github/workflows/main.yml"
118
133
  - ".gitignore"
134
+ - ".pryrc"
119
135
  - ".rspec"
120
136
  - ".rubocop.yml"
121
- - ".travis.yml"
122
137
  - Gemfile
123
138
  - LICENSE.txt
124
139
  - README.md
@@ -126,25 +141,24 @@ files:
126
141
  - bin/console
127
142
  - bin/setup
128
143
  - dip.yml
129
- - docker/Dockerfile.2.6
130
- - docker/docker-compose.development.yml
144
+ - docker/Dockerfile.dip
131
145
  - docker/docker-compose.yml
146
+ - docker/prepare_env.sh
132
147
  - lib/yandex_client.rb
133
- - lib/yandex_client/api_request_error.rb
134
- - lib/yandex_client/auth/client.rb
135
- - lib/yandex_client/client.rb
136
- - lib/yandex_client/dav/client.rb
137
- - lib/yandex_client/dav/propfind_parser.rb
138
- - lib/yandex_client/disk/client.rb
139
- - lib/yandex_client/not_found_error.rb
140
- - lib/yandex_client/passport/client.rb
148
+ - lib/yandex_client/auth.rb
149
+ - lib/yandex_client/configurable.rb
150
+ - lib/yandex_client/dav.rb
151
+ - lib/yandex_client/dav/prop_find_response.rb
152
+ - lib/yandex_client/disk.rb
153
+ - lib/yandex_client/error_handler.rb
154
+ - lib/yandex_client/passport.rb
141
155
  - lib/yandex_client/version.rb
142
156
  - yandex_client.gemspec
143
157
  homepage: https://github.com/yamax2/yandex_client
144
158
  licenses:
145
159
  - MIT
146
160
  metadata: {}
147
- post_install_message:
161
+ post_install_message:
148
162
  rdoc_options: []
149
163
  require_paths:
150
164
  - lib
@@ -159,8 +173,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
159
173
  - !ruby/object:Gem::Version
160
174
  version: '0'
161
175
  requirements: []
162
- rubygems_version: 3.0.6
163
- signing_key:
176
+ rubygems_version: 3.2.26
177
+ signing_key:
164
178
  specification_version: 4
165
179
  summary: Yandex Client
166
180
  test_files: []
data/.travis.yml DELETED
@@ -1,12 +0,0 @@
1
- sudo: false
2
- language: ruby
3
- rvm:
4
- - 2.6.5
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