yandex_client 0.1.1 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ec95accc04a86127c16f61ad3f438ec9b42c9cb5eaa03c7589191d7a4223402f
4
- data.tar.gz: b1a50d5dd827ab178ec54cf6d7a6613d89e97065f5117d5669583e12678c4811
3
+ metadata.gz: e8b82741c31dd638b0ff6793b208d6c7ab33e9b5dc613f6c9ffd3482fb5dcde3
4
+ data.tar.gz: 510f836e9b6566ba397342544c9430232f7c88a39607261450d413c82b998367
5
5
  SHA512:
6
- metadata.gz: 5cef57682df43d60b7f666bf7df6f77d51aeb41a96579048c0c5e84b616cdadc78f4d4efae2f0c006fa1df421179b857a312c4cac37250b5c7273c7f5a56fdd1
7
- data.tar.gz: 00376bc7e7e6185bf797655630ac93509cacc567100e44f26902abfb3abd8b70e0775148ec06ff79961b8a7ea36e6be28e060b18a287acd688c7baefd1400c20
6
+ metadata.gz: 91e69d64b589fc868bb0bc18956cb81c85031e6f4bef8ffd8619a2578f1f5f4e269635b11d818f801230b0e7c0b491a6cd55a7a98bcab1cb6021e92d49f7f677
7
+ data.tar.gz: 2fff713b5cc2fe4dae297347edb3a54d4ee93c31d233d1406ad61a8d2f76ec1792c7693e5c56422b2f9a4011131c5d49454c4d9c3f44c0040d08f490298ad005
@@ -0,0 +1,30 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: ['*']
6
+ pull_request:
7
+ branches: [master]
8
+
9
+ jobs:
10
+ test:
11
+ runs-on: ubuntu-latest
12
+ strategy:
13
+ matrix:
14
+ ruby-version: ["2.5", "2.6", "2.7", "3.0"]
15
+
16
+ steps:
17
+ - uses: actions/checkout@v2
18
+
19
+ - name: Set up Ruby
20
+ # To automatically get bug fixes and new Ruby versions for ruby/setup-ruby,
21
+ # change this to (see https://github.com/ruby/setup-ruby#versioning):
22
+ # uses: ruby/setup-ruby@v1
23
+ uses: ruby/setup-ruby@v1
24
+ with:
25
+ ruby-version: ${{ matrix.ruby-version }}
26
+ bundler-cache: true
27
+ - name: rubocop
28
+ run: bundle exec ./rubocop --display-style-guide --extra-details
29
+ - name: tests
30
+ run: bundle exec rspec
data/.gitignore CHANGED
@@ -14,3 +14,5 @@
14
14
  .byebug_history
15
15
 
16
16
  Gemfile.lock
17
+ .irb-save-history
18
+ coverage
data/.pryrc ADDED
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ Pry.config.history_file = "#{File.dirname(__FILE__)}/.irb-save-history"
4
+
5
+ require 'bundler/setup'
6
+ require 'yandex_client'
data/.rubocop.yml ADDED
@@ -0,0 +1,39 @@
1
+ AllCops:
2
+ TargetRubyVersion: 3.0
3
+ NewCops: enable
4
+ SuggestExtensions: false
5
+ Exclude:
6
+ - 'bin/**/*'
7
+ - '.pryrc'
8
+ - 'vendor/**/*'
9
+
10
+ Layout/LineLength:
11
+ Max: 120
12
+
13
+ Style/AsciiComments:
14
+ Enabled: false
15
+
16
+ Layout/SpaceInsideHashLiteralBraces:
17
+ EnforcedStyle: no_space
18
+
19
+ Style/Documentation:
20
+ Enabled: false
21
+
22
+ Layout/DotPosition:
23
+ EnforcedStyle: trailing
24
+
25
+ Style/EmptyMethod:
26
+ EnforcedStyle: expanded
27
+
28
+ Layout/MultilineMethodCallIndentation:
29
+ EnforcedStyle: indented
30
+
31
+ Metrics/BlockLength:
32
+ Exclude:
33
+ - spec/**/*
34
+
35
+ Gemspec/RequiredRubyVersion:
36
+ Enabled: false
37
+
38
+ Gemspec/RequireMFA:
39
+ Enabled: false
data/Gemfile CHANGED
@@ -5,5 +5,7 @@ source 'https://rubygems.org'
5
5
  git_source(:github) { |repo_name| "https://github.com/#{repo_name}" }
6
6
 
7
7
  gem 'pry-byebug'
8
+ gem 'rubocop', require: false
9
+ gem 'rubocop-rspec', require: false
8
10
 
9
11
  gemspec
data/README.md CHANGED
@@ -1,114 +1,64 @@
1
- [![Build Status](https://travis-ci.org/yamax2/yandex_client.svg?branch=master)](https://travis-ci.org/yamax2/yandex_client)
2
-
3
1
  # YandexClient
4
2
 
5
3
  ## Installation
6
4
 
7
5
  Add this line to your application's Gemfile:
8
-
9
6
  ```ruby
10
- gem 'yandex_client'
7
+ gem 'yandex_client', '>= 1'
11
8
  ```
12
9
 
13
10
  And then execute:
14
-
15
- $ bundle
11
+ ```bash
12
+ $ bundle install
13
+ ```
16
14
 
17
15
  Or install it yourself as:
18
-
19
- $ gem install yandex_client
20
-
21
- ## Usage
22
-
23
- ### [Auth](https://yandex.ru/dev/oauth/doc/dg/concepts/about-docpage/)
24
- ```ruby
25
- cli = YandexClient::Auth::Client.new
16
+ ```bash
17
+ $ gem install yandex_client
26
18
  ```
27
19
 
28
- [create_token](https://tech.yandex.ru/oauth/doc/dg/reference/auto-code-client-docpage/#auto-code-client__get-token)
29
- ```ruby
30
- cli.create_token(code: 'your_code')
31
- ```
20
+ ## Disk webdav
32
21
 
33
- [refresh_token](https://yandex.ru/dev/oauth/doc/dg/reference/refresh-client-docpage/)
34
- ```ruby
35
- cli.refresh_token(refresh_token: 'your_token')
36
- ```
22
+ https://tech.yandex.ru/disk/doc/dg/reference/put-docpage/
37
23
 
38
- ### [Passport](https://tech.yandex.ru/passport/doc/dg/reference/)
24
+ Chainable client:
39
25
  ```ruby
40
- cli = YandexClient::Passport::Client.new(access_token: 'your_access_token')
26
+ YandexClient::Dav['your_access_token']
27
+ .put('1.txt', '/a/b/c/1.txt')
28
+ .put(File.open('1.txt', 'rb'), '/path/to/1.txt')
29
+ .put(Tempfile.new.tap { |t| t.write('say ni'); t.rewind }, '/path/to/tmp.txt')
30
+ .delete('/a/b/c/1.txt')
31
+ .mkcol('/a/b/c')
32
+ .propfind('/a/dip.yml', depth: 0)
33
+ .propfind('/a', depth: 1)
34
+ .propfind.to_a
41
35
  ```
42
36
 
43
- [info](https://yandex.ru/dev/passport/doc/dg/reference/request-docpage/)
44
- ```ruby
45
- cli.info
46
- ```
37
+ ## Disk rest api
47
38
 
48
- ### [Yandex Disk WebDav](https://yandex.ru/dev/disk/doc/dg/concepts/quickstart-docpage/)
49
- ```ruby
50
- cli = YandexClient::Dav::Client.new(access_token: 'your_token')
51
- ```
39
+ https://yandex.ru/dev/disk/api/reference/capacity-docpage/
40
+ https://yandex.ru/dev/disk/api/reference/content-docpage/
52
41
 
53
- [put](https://yandex.ru/dev/disk/doc/dg/reference/put-docpage/)
54
42
  ```ruby
55
- cli.put(file: '1.txt', name: '/a/b/c/1.txt')
43
+ YandexClient::Disk['access_token'].info
44
+ YandexClient::Disk['access_token'].download_url('path/to/file')
45
+ YandexClient::Disk['access_token'].upload_url('path/to/file')
56
46
  ```
57
47
 
58
- [delete](https://yandex.ru/dev/disk/doc/dg/reference/delete-docpage/)
59
- ```ruby
60
- cli.delete(name: '/a/b/c/1.txt')
61
- ```
48
+ ## Auth
62
49
 
63
- [mkcol](https://yandex.ru/dev/disk/doc/dg/reference/mkcol-docpage/)
64
- ```ruby
65
- cli.mkcol(name: '/a/b/c')
66
- ```
67
-
68
- [file props](https://yandex.ru/dev/disk/doc/dg/reference/property-request-docpage/)
69
- ```ruby
70
- cli.propfind(name: '/a/dip.yml', depth: 0)
71
- ```
50
+ https://tech.yandex.ru/oauth/doc/dg/reference/refresh-client-docpage/
51
+ https://tech.yandex.ru/oauth/doc/dg/reference/auto-code-client-docpage/#auto-code-client__get-token
72
52
 
73
- [list files in dir](https://yandex.ru/dev/disk/doc/dg/reference/property-request-docpage/)
74
53
  ```ruby
75
- cli.propfind(name: '/a', depth: 1)
54
+ YandexClient.auth.create_token('9388894')
55
+ YandexClient.auth.refresh_token('refresh_token')
76
56
  ```
77
57
 
78
- [account free space and quota](https://yandex.ru/dev/disk/doc/dg/reference/property-request-docpage/)
79
- ```ruby
80
- cli.propfind(name: '/', quota: true)
81
- ```
82
-
83
- ## Development
84
-
85
- After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
86
-
87
- To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
58
+ ## Passport
88
59
 
89
- ## Development with docker
60
+ https://tech.yandex.ru/passport/doc/dg/reference/request-docpage/
90
61
 
91
- * Install docker and docker-compose
92
- * Install [dip](https://github.com/bibendi/dip)
93
- ```hash
94
- gem install dip
95
- ```
96
- * Prepare the the test environment
97
- ```bash
98
- dip provision
99
- ```
100
- * Run tests
101
- ```bash
102
- dip rspec
62
+ ```ruby
63
+ YandexClient::Passport::Client['access_token'].info
103
64
  ```
104
-
105
- ## TODO
106
- * docs...
107
-
108
- ## Contributing
109
-
110
- Bug reports and pull requests are welcome on GitHub at https://github.com/yamax2/yandex_client.
111
-
112
- ## License
113
-
114
- The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
data/dip.yml CHANGED
@@ -1,14 +1,11 @@
1
- version: '1'
1
+ version: '3.3'
2
2
 
3
3
  environment:
4
- DOCKER_RUBY_VERSION: 2.6
5
- RUBY_IMAGE_TAG: 2.6.5
6
- COMPOSE_FILE_EXT: development
4
+ DOCKER_RUBY_VERSION: 3.0
7
5
 
8
6
  compose:
9
7
  files:
10
8
  - docker/docker-compose.yml
11
- - docker/docker-compose.${COMPOSE_FILE_EXT}.yml
12
9
  project_name: yandex_client
13
10
 
14
11
  interaction:
@@ -17,7 +14,7 @@ interaction:
17
14
 
18
15
  irb:
19
16
  service: app
20
- command: irb
17
+ command: bundle exec pry
21
18
 
22
19
  bundle:
23
20
  service: app
@@ -31,12 +28,16 @@ interaction:
31
28
  service: app
32
29
  command: bundle exec rspec
33
30
 
31
+ rubocop:
32
+ service: app
33
+ command: bundle exec ./rubocop --display-style-guide --extra-details
34
+
34
35
  clean:
35
36
  service: app
36
- command: rm -f Gemfile.lock
37
+ command: rm -rf Gemfile.lock
37
38
 
38
39
  provision:
40
+ - ./docker/prepare_env.sh
39
41
  - docker volume create --name bundler_data
40
42
  - dip clean
41
43
  - dip bundle install
42
- - dip appraisal install
@@ -0,0 +1,8 @@
1
+ ARG DOCKER_RUBY_VERSION
2
+ FROM ruby:${DOCKER_RUBY_VERSION}-alpine
3
+
4
+ RUN gem update --system && \
5
+ apk add --update --no-cache tzdata less git build-base mc && \
6
+ cp /usr/share/zoneinfo/Asia/Yekaterinburg /etc/localtime && echo 'Asia/Yekaterinburg' > /etc/timezone
7
+
8
+ WORKDIR /app
@@ -1,14 +1,22 @@
1
- version: '2'
1
+ version: '3.3'
2
2
 
3
3
  services:
4
4
  app:
5
5
  build:
6
6
  context: ../
7
- dockerfile: ./docker/Dockerfile.${DOCKER_RUBY_VERSION}
7
+ dockerfile: ./docker/Dockerfile.dip
8
+ args:
9
+ DOCKER_RUBY_VERSION: $DOCKER_RUBY_VERSION
10
+ labels:
11
+ com.yandex-client.ruby.version: $DOCKER_RUBY_VERSION
8
12
  environment:
9
- - BUNDLE_PATH=/bundle/$DOCKER_RUBY_VERSION
10
- - SSH_AUTH_SOCK=/ssh/auth/sock
11
- - TEST_DB_HOST=db
12
- - TEST_DB_NAME=docker
13
- - TEST_DB_USERNAME=postgres
14
- command: bash
13
+ - BUNDLE_PATH=/bundle/${DOCKER_RUBY_VERSION}
14
+ volumes:
15
+ - ..:/app
16
+ - bundler-data:/bundle
17
+ command: sh
18
+
19
+ volumes:
20
+ bundler-data:
21
+ external:
22
+ name: bundler_data
@@ -0,0 +1,11 @@
1
+ #!/bin/sh
2
+
3
+ set -e
4
+
5
+ for line in $(docker images -f "label=com.yandex-client.ruby.version" -q | uniq); do
6
+ ver=$(docker inspect --format '{{ index .Config.Labels "com.yandex-client.ruby.version"}}' $line)
7
+
8
+ if ! [ $ver = $DOCKER_RUBY_VERSION ]; then
9
+ docker image rm --force $line
10
+ fi
11
+ done
@@ -0,0 +1,62 @@
1
+ # frozen_string_literal: true
2
+
3
+ module YandexClient
4
+ # https://tech.yandex.ru/oauth/doc/dg/reference/refresh-client-docpage/
5
+ # https://tech.yandex.ru/oauth/doc/dg/reference/auto-code-client-docpage/#auto-code-client__get-token
6
+ #
7
+ # https://oauth.yandex.ru/authorize?response_type=code&client_id=ede5c51271164a9e833ab9119b4d3c26&force_confirm=false
8
+ #
9
+ # Example:
10
+ # token = Token.first
11
+ #
12
+ # YandexClient.auth.create_token('9388894')
13
+ # YandexClient.auth.refresh_token(token.refresh_token)
14
+ class Auth
15
+ include Configurable
16
+ include ErrorHandler
17
+
18
+ ACTION_URL = 'https://oauth.yandex.ru/token'
19
+
20
+ def create_token(code)
21
+ process_response with_config.post(
22
+ ACTION_URL,
23
+ headers: common_headers,
24
+ body: URI.encode_www_form(
25
+ request_body_for('authorization_code').merge!(code: code)
26
+ )
27
+ )
28
+ end
29
+
30
+ def refresh_token(refresh_token)
31
+ process_response with_config.post(
32
+ ACTION_URL,
33
+ headers: common_headers,
34
+ body: URI.encode_www_form(
35
+ request_body_for('refresh_token').merge!(refresh_token: refresh_token)
36
+ )
37
+ )
38
+ end
39
+
40
+ private
41
+
42
+ def common_headers
43
+ {'Content-type' => 'application/x-www-form-urlencoded'}
44
+ end
45
+
46
+ def request_body_for(grant_type)
47
+ {
48
+ grant_type: grant_type,
49
+ client_id: config.api_key,
50
+ client_secret: config.api_secret
51
+ }
52
+ end
53
+
54
+ def process_response(response)
55
+ if response.status.success?
56
+ JSON.parse(response.body, symbolize_names: true)
57
+ else
58
+ error_for_response(response)
59
+ end
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ module YandexClient
4
+ module Configurable
5
+ def self.included(base)
6
+ base.extend Forwardable
7
+ base.def_delegator :YandexClient, :config
8
+ end
9
+
10
+ private
11
+
12
+ def with_config
13
+ req = HTTP.timeout(
14
+ connect: config.connect_timeout,
15
+ read: config.read_timeout,
16
+ write: config.write_timeout
17
+ )
18
+
19
+ if config.logger
20
+ req.use(logging: {logger: config.logger})
21
+ else
22
+ req
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,70 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'ox'
4
+ require 'cgi'
5
+
6
+ module YandexClient
7
+ class Dav
8
+ class PropFindResponse
9
+ include Enumerable
10
+
11
+ SUCCESS_STATUS = 'HTTP/1.1 200 OK'
12
+
13
+ class Item
14
+ attr_reader :name, :created_at, :last_modified, :content_type
15
+
16
+ def initialize(name, node)
17
+ @name = name
18
+ @folder = node[:'d:resourcetype'].is_a?(Hash)
19
+
20
+ load_node_data(node)
21
+ end
22
+
23
+ def folder?
24
+ @folder
25
+ end
26
+
27
+ def file?
28
+ !@folder
29
+ end
30
+
31
+ private
32
+
33
+ def load_node_data(node)
34
+ @created_at = node.fetch(:'d:creationdate')
35
+ @last_modified = node.fetch(:'d:getlastmodified')
36
+
37
+ return if folder?
38
+
39
+ @etag = node.fetch(:'d:getetag')
40
+ @size = node.fetch(:'d:getcontentlength').to_i
41
+ @content_type = node.fetch(:'d:getcontenttype')
42
+
43
+ define_singleton_method(:etag) { @etag }
44
+ define_singleton_method(:size) { @size }
45
+ define_singleton_method(:content_type) { @content_type }
46
+ end
47
+ end
48
+
49
+ def initialize(xml)
50
+ @doc = Ox.load(
51
+ xml.dup.force_encoding('UTF-8'),
52
+ mode: :hash
53
+ )
54
+ end
55
+
56
+ def each
57
+ @doc[:'d:multistatus'].each do |node|
58
+ next if (response = node[:'d:response']).nil?
59
+
60
+ name = CGI.unescape(response.fetch(:'d:href'))
61
+ node_data = response.fetch(:'d:propstat')
62
+
63
+ raise ParseError unless node_data.fetch(:'d:status') == SUCCESS_STATUS
64
+
65
+ yield Item.new(name, node_data.fetch(:'d:prop'))
66
+ end
67
+ end
68
+ end
69
+ end
70
+ end
@@ -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,72 @@
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
+ # YandexClient::Disk[access_token].download_url('path/to/file', overwrite: false)
12
+ class Disk
13
+ include Configurable
14
+ include ErrorHandler
15
+
16
+ ACTION_URL = 'https://cloud-api.yandex.net'
17
+
18
+ attr_reader :token
19
+
20
+ class << self
21
+ def with_token(token)
22
+ new(token)
23
+ end
24
+
25
+ alias [] with_token
26
+ end
27
+
28
+ def initialize(token)
29
+ @token = token
30
+ end
31
+
32
+ def info
33
+ process_response(
34
+ with_config.get("#{ACTION_URL}/v1/disk/", headers: auth_headers)
35
+ )
36
+ end
37
+
38
+ def download_url(path)
39
+ url = URI.parse(ACTION_URL).tap do |uri|
40
+ uri.path = '/v1/disk/resources/download'
41
+ uri.query = URI.encode_www_form(path: path)
42
+ end
43
+
44
+ process_response(
45
+ with_config.get(url, headers: auth_headers)
46
+ ).fetch(:href)
47
+ end
48
+
49
+ def upload_url(path, overwrite: false)
50
+ url = URI.parse(ACTION_URL).tap do |uri|
51
+ uri.path = '/v1/disk/resources/upload'
52
+ uri.query = URI.encode_www_form(path: ::CGI.escape(path), overwrite: overwrite)
53
+ end
54
+
55
+ process_response(
56
+ with_config.get(url, headers: auth_headers)
57
+ ).fetch(:href)
58
+ end
59
+
60
+ private
61
+
62
+ def auth_headers
63
+ {Authorization: "OAuth #{@token}"}
64
+ end
65
+
66
+ def process_response(response)
67
+ return JSON.parse(response.body, symbolize_names: true) if response.status.success?
68
+
69
+ error_for_response(response)
70
+ end
71
+ end
72
+ end