yandex_client 0.1.2 → 1.2.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: 6ff2e1ef6c319dbb6dfe2443e6d30eaeb3c8d4151898464909e91b30d1b00590
4
- data.tar.gz: b3d1e8182e4bd59b491304b3a8d43ff135f4af1cf6245d2af8c2e926d787f738
3
+ metadata.gz: 53b4e247150833a4820941be868068a42e30262fd68361a598f9ef82d548e95a
4
+ data.tar.gz: 0af348f76bbed344d03c0f43a4f7070ef259eec6ba531dbf5566a19865cb2ca2
5
5
  SHA512:
6
- metadata.gz: 2095d85ea6b36bc5151ead67fac45420bcf18763d1e342294475dee157e3ce9e2fb71c8bf33ffbe50a7df9dc80dc2e7dde564a6dc658d37d2787455f91f69c51
7
- data.tar.gz: 915b9297b9bb13d2d32c80f6a33faec3354b5d296dba643693c90fc021598fa09def3dbb0f844d58d29afd02e3dec7b544c388a2dab5cdadac2a73b2ef75829b
6
+ metadata.gz: 4131c44a5ca7238d405069d8f298db91322768f729b3b5df87438bd4c376983faf7b6531de203a43b76ca851f9e9f3c9d192594cdc9aafcce0a554acb0342438
7
+ data.tar.gz: ed5d3b7b09decb39e554b8bebee7ce956167263cd5a0302996d4f113b44b71025d89660b8a5d9f44a3f4c17ff92967d57700d547313521cde3f30abb0a871199
@@ -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 CHANGED
@@ -1,8 +1,11 @@
1
1
  AllCops:
2
- TargetRubyVersion: 2.4
2
+ TargetRubyVersion: 3.0
3
+ NewCops: enable
4
+ SuggestExtensions: false
3
5
  Exclude:
4
6
  - 'bin/**/*'
5
7
  - '.pryrc'
8
+ - 'vendor/**/*'
6
9
 
7
10
  Layout/LineLength:
8
11
  Max: 120
@@ -28,3 +31,9 @@ Layout/MultilineMethodCallIndentation:
28
31
  Metrics/BlockLength:
29
32
  Exclude:
30
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,65 @@
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', overwrite: false)
46
+ YandexClient::Disk['access_token'].move('path/to/file', 'new_path/to/new_file', overwrite: false)
56
47
  ```
57
48
 
58
- [delete](https://yandex.ru/dev/disk/doc/dg/reference/delete-docpage/)
59
- ```ruby
60
- cli.delete(name: '/a/b/c/1.txt')
61
- ```
49
+ ## Auth
62
50
 
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
- ```
51
+ https://tech.yandex.ru/oauth/doc/dg/reference/refresh-client-docpage/
52
+ https://tech.yandex.ru/oauth/doc/dg/reference/auto-code-client-docpage/#auto-code-client__get-token
72
53
 
73
- [list files in dir](https://yandex.ru/dev/disk/doc/dg/reference/property-request-docpage/)
74
54
  ```ruby
75
- cli.propfind(name: '/a', depth: 1)
55
+ YandexClient.auth.create_token('9388894')
56
+ YandexClient.auth.refresh_token('refresh_token')
76
57
  ```
77
58
 
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).
59
+ ## Passport
88
60
 
89
- ## Development with docker
61
+ https://tech.yandex.ru/passport/doc/dg/reference/request-docpage/
90
62
 
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
63
+ ```ruby
64
+ YandexClient::Passport::Client['access_token'].info
103
65
  ```
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,16 +28,16 @@ interaction:
31
28
  service: app
32
29
  command: bundle exec rspec
33
30
 
34
- clean:
31
+ rubocop:
35
32
  service: app
36
- command: rm -f Gemfile.lock
33
+ command: bundle exec ./rubocop --display-style-guide --extra-details
37
34
 
38
- rubocop:
35
+ clean:
39
36
  service: app
40
- command: rubocop
37
+ command: rm -rf Gemfile.lock
41
38
 
42
39
  provision:
40
+ - ./docker/prepare_env.sh
43
41
  - docker volume create --name bundler_data
44
42
  - dip clean
45
43
  - dip bundle install
46
- - 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,84 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'json'
4
+
5
+ module YandexClient
6
+ # https://yandex.ru/dev/disk/api/reference/capacity.html
7
+ # https://yandex.ru/dev/disk/api/reference/content.html
8
+ # https://yandex.ru/dev/disk/api/reference/move.html
9
+ #
10
+ # YandexClient::Disk[access_token].info
11
+ # YandexClient::Disk[access_token].download_url('path/to/file')
12
+ # YandexClient::Disk[access_token].download_url('path/to/file', overwrite: false)
13
+ class Disk
14
+ include Configurable
15
+ include ErrorHandler
16
+
17
+ ACTION_URL = 'https://cloud-api.yandex.net'
18
+
19
+ attr_reader :token
20
+
21
+ class << self
22
+ def with_token(token)
23
+ new(token)
24
+ end
25
+
26
+ alias [] with_token
27
+ end
28
+
29
+ def initialize(token)
30
+ @token = token
31
+ end
32
+
33
+ def info
34
+ process_response(
35
+ with_config.get("#{ACTION_URL}/v1/disk/", headers: auth_headers)
36
+ )
37
+ end
38
+
39
+ def download_url(path)
40
+ url = URI.parse(ACTION_URL).tap do |uri|
41
+ uri.path = '/v1/disk/resources/download'
42
+ uri.query = URI.encode_www_form(path: path)
43
+ end
44
+
45
+ process_response(
46
+ with_config.get(url, headers: auth_headers)
47
+ ).fetch(:href)
48
+ end
49
+
50
+ def upload_url(path, overwrite: false)
51
+ url = URI.parse(ACTION_URL).tap do |uri|
52
+ uri.path = '/v1/disk/resources/upload'
53
+ uri.query = URI.encode_www_form(path: path, overwrite: overwrite)
54
+ end
55
+
56
+ process_response(
57
+ with_config.get(url, headers: auth_headers)
58
+ ).fetch(:href)
59
+ end
60
+
61
+ def move(from, to, overwrite: false)
62
+ url = URI.parse(ACTION_URL).tap do |uri|
63
+ uri.path = '/v1/disk/resources/move'
64
+ uri.query = URI.encode_www_form(from: from, path: to, overwrite: overwrite)
65
+ end
66
+
67
+ process_response(
68
+ with_config.post(url, headers: auth_headers)
69
+ ).fetch(:href)
70
+ end
71
+
72
+ private
73
+
74
+ def auth_headers
75
+ {Authorization: "OAuth #{@token}"}
76
+ end
77
+
78
+ def process_response(response)
79
+ return JSON.parse(response.body, symbolize_names: true) if response.status.success?
80
+
81
+ error_for_response(response)
82
+ end
83
+ end
84
+ end