rb1drv 0.1.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +8 -0
- data/.travis.yml +6 -0
- data/Gemfile +3 -0
- data/Gemfile.lock +36 -0
- data/LICENSE.txt +21 -0
- data/README.md +78 -0
- data/lib/rb1drv/auth.rb +29 -0
- data/lib/rb1drv/onedrive.rb +18 -0
- data/lib/rb1drv/onedrive_dir.rb +136 -0
- data/lib/rb1drv/onedrive_file.rb +61 -0
- data/lib/rb1drv/onedrive_item.rb +33 -0
- data/lib/rb1drv/sliced_io.rb +29 -0
- data/lib/rb1drv/version.rb +3 -0
- data/lib/rb1drv.rb +57 -0
- data/rb1drv.gemspec +28 -0
- metadata +115 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: feafbb64ce01c80b2c8f55c4d62dbed44aa6bca0d908965d94700a01def35f8a
|
4
|
+
data.tar.gz: 1b31de1595f55f7ecc4f40da51979a87fc72cb0ee6602768af2a6f7a08319661
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 9a09646c4cbb6c1afc6e65f7bf2332865a5eae3afe32028b053908c21bacbeec8338e6b31f47176632c6939502971e9962627602528fd6f9eb68765ab9ebeaa2
|
7
|
+
data.tar.gz: 37cf356d74830003591bf77c5d3328d354cdfdd46f112b31fddf7baaf029f9ca23318cf782a1a228fd2c4e9842971fcef7f38d39bea5151fb4afb38f64321b31
|
data/.gitignore
ADDED
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
rb1drv (0.1.1)
|
5
|
+
excon (~> 0.62)
|
6
|
+
oauth2 (~> 1.4)
|
7
|
+
|
8
|
+
GEM
|
9
|
+
remote: https://rubygems.org/
|
10
|
+
specs:
|
11
|
+
excon (0.62.0)
|
12
|
+
faraday (0.12.2)
|
13
|
+
multipart-post (>= 1.2, < 3)
|
14
|
+
jwt (1.5.6)
|
15
|
+
multi_json (1.13.1)
|
16
|
+
multi_xml (0.6.0)
|
17
|
+
multipart-post (2.0.0)
|
18
|
+
oauth2 (1.4.0)
|
19
|
+
faraday (>= 0.8, < 0.13)
|
20
|
+
jwt (~> 1.0)
|
21
|
+
multi_json (~> 1.3)
|
22
|
+
multi_xml (~> 0.5)
|
23
|
+
rack (>= 1.2, < 3)
|
24
|
+
rack (2.0.5)
|
25
|
+
rake (10.5.0)
|
26
|
+
|
27
|
+
PLATFORMS
|
28
|
+
ruby
|
29
|
+
|
30
|
+
DEPENDENCIES
|
31
|
+
bundler (~> 1.16)
|
32
|
+
rake (~> 10.0)
|
33
|
+
rb1drv!
|
34
|
+
|
35
|
+
BUNDLED WITH
|
36
|
+
1.16.1
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2018 Xinyue Lu
|
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
|
13
|
+
all 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
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,78 @@
|
|
1
|
+
# Rb1drv
|
2
|
+
|
3
|
+
[![Build Status](https://travis-ci.org/msg7086/rb1drv.svg?branch=master)](https://travis-ci.org/msg7086/rb1drv)
|
4
|
+
|
5
|
+
Rb1drv is a Ruby SDK for Microsoft OneDrive service, providing a simple interface to access files inside OneDrive.
|
6
|
+
|
7
|
+
Rb1drv allows you to list directories, upload or download files, etc.
|
8
|
+
|
9
|
+
To use the command line application, install [`rb1drv-tools`](https://github.com/msg7086/rb1drv-tools) gem instead.
|
10
|
+
|
11
|
+
Further functionalities can be added to the library upon requests.
|
12
|
+
|
13
|
+
Rb1drv uses the latest Microsoft OAuth2 + Graph API at the time it is written, while there are not many other libraries available for reference (e.g. official OneDrive SDK still uses old OAuth2 API instead of new OAuth2 v2.0 API). Feel free to take this as an unoffical reference implementation and write your own SDK.
|
14
|
+
|
15
|
+
## Installation
|
16
|
+
|
17
|
+
Add this line to your application's Gemfile:
|
18
|
+
|
19
|
+
```ruby
|
20
|
+
gem 'rb1drv'
|
21
|
+
```
|
22
|
+
|
23
|
+
And then execute:
|
24
|
+
|
25
|
+
$ bundle
|
26
|
+
|
27
|
+
Or install it yourself as:
|
28
|
+
|
29
|
+
$ gem install rb1drv
|
30
|
+
|
31
|
+
## Usage
|
32
|
+
|
33
|
+
You will have to register a new application on Microsoft Application Registration Portal before using the API.
|
34
|
+
Read more at [OneDrive API Docs](https://github.com/OneDrive/onedrive-api-docs/blob/live/docs/rest-api/getting-started/graph-oauth.md).
|
35
|
+
|
36
|
+
od = OneDrive.new('a2b3c4d5-your-app-id', 'C8V3{your-app-secret(', 'https://your-callback/url')
|
37
|
+
|
38
|
+
To start using `OneDrive` library, instanciate the class with your application information.
|
39
|
+
|
40
|
+
---
|
41
|
+
|
42
|
+
od.root
|
43
|
+
od.get('/Folder1')
|
44
|
+
od.get('/File1.avi')
|
45
|
+
|
46
|
+
Use `OneDrive#root` or `OneDrive#get` to get a drive item.
|
47
|
+
|
48
|
+
---
|
49
|
+
|
50
|
+
od.root.children
|
51
|
+
od.root.children.grep(OneDriveDir)
|
52
|
+
|
53
|
+
Use `OneDriveDir#children` to get contents of a directory.
|
54
|
+
|
55
|
+
---
|
56
|
+
|
57
|
+
od.get('/File1.avi').save_as('/tmp/test.avi', overwrite: true) do |event, stat|
|
58
|
+
puts "Downloaded #{stat[:progress]} of #{stat[:total]}" if event == :progress
|
59
|
+
end
|
60
|
+
|
61
|
+
Use `OneDriveFile#save_as` to download a file.
|
62
|
+
|
63
|
+
---
|
64
|
+
|
65
|
+
od.get('/Folder1').upload('/tmp/test.avi', overwrite: true, target_name: 'party.avi') do |event, stat|
|
66
|
+
puts "Uploading #{stat[:progress]} of #{stat[:total]} for segment #{stat[:from]}-#{stat[:to]}" if event == :progress
|
67
|
+
puts "Uploaded segment #{stat[:from]}-#{stat[:to]}" if event == :finish_segment
|
68
|
+
end
|
69
|
+
|
70
|
+
Use `OneDriveDir#upload` to upload a file to target directory.
|
71
|
+
|
72
|
+
## Contributing
|
73
|
+
|
74
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/msg7086/rb1drv.
|
75
|
+
|
76
|
+
## License
|
77
|
+
|
78
|
+
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
data/lib/rb1drv/auth.rb
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
module Rb1drv
|
2
|
+
class OneDrive
|
3
|
+
# Gets authorize URL to start authentication process
|
4
|
+
#
|
5
|
+
# @return [String] the authorize URL
|
6
|
+
def auth_url
|
7
|
+
@oauth2_client.auth_code.authorize_url(
|
8
|
+
redirect_uri: @callback_url,
|
9
|
+
scope: 'openid offline_access https://graph.microsoft.com/Files.ReadWrite.All'
|
10
|
+
)
|
11
|
+
end
|
12
|
+
|
13
|
+
# Gets access token from authorize code
|
14
|
+
#
|
15
|
+
# @return [OAuth2::AccessToken] the access token
|
16
|
+
def auth_access(auth_code)
|
17
|
+
@access_token = @oauth2_client.auth_code.get_token(auth_code, redirect_uri: @callback_url)
|
18
|
+
end
|
19
|
+
|
20
|
+
# Loads previously retrieved access token from Hash
|
21
|
+
#
|
22
|
+
# @return [OAuth2::AccessToken] the access token
|
23
|
+
def auth_load(access_token)
|
24
|
+
@access_token = OAuth2::AccessToken.from_hash(@oauth2_client, access_token)
|
25
|
+
@access_token = @access_token.refresh! if @access_token.expired?
|
26
|
+
@access_token
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module Rb1drv
|
2
|
+
class OneDrive
|
3
|
+
# Get root directory object.
|
4
|
+
#
|
5
|
+
# @return [OneDriveDir] your root
|
6
|
+
def root
|
7
|
+
@_root_dir ||= OneDriveDir.new(self, request('drive/root'))
|
8
|
+
end
|
9
|
+
|
10
|
+
# Get an object by an arbitary path.
|
11
|
+
#
|
12
|
+
# @return [OneDriveDir,OneDriveFile] the drive item you asked
|
13
|
+
def get(path)
|
14
|
+
path = "/#{path}" unless path[0] == '/'
|
15
|
+
OneDriveItem.smart_new(self, request("drive/root:#{path}"))
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,136 @@
|
|
1
|
+
require 'rb1drv/sliced_io'
|
2
|
+
|
3
|
+
module Rb1drv
|
4
|
+
class OneDriveDir < OneDriveItem
|
5
|
+
attr_reader :child_count
|
6
|
+
def initialize(od, api_hash)
|
7
|
+
super
|
8
|
+
@child_count = api_hash.dig('folder', 'childCount')
|
9
|
+
end
|
10
|
+
|
11
|
+
# Lists contents of current directory.
|
12
|
+
#
|
13
|
+
# @return [Array<OneDriveDir,OneDriveFile>] directories and files whose parent is current directory
|
14
|
+
def children
|
15
|
+
return [] if child_count <= 0
|
16
|
+
@od.request("drive/items/#{@id}/children")['value'].map do |child|
|
17
|
+
OneDriveItem.smart_new(@od, child)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
# Get an object by an arbitary path related to current directory.
|
22
|
+
#
|
23
|
+
# To get an absolute path, make use of OneDrive#get and not this.
|
24
|
+
#
|
25
|
+
# @param path [String] path relative to current directory
|
26
|
+
#
|
27
|
+
# @return [OneDriveDir,OneDriveFile] the drive item you asked
|
28
|
+
def get(path)
|
29
|
+
path = "/#{path}" unless path[0] == '/'
|
30
|
+
OneDriveItem.smart_new(self, @od.request("drive/items/#{@id}:#{path}"))
|
31
|
+
end
|
32
|
+
|
33
|
+
# Yes
|
34
|
+
def dir?
|
35
|
+
true
|
36
|
+
end
|
37
|
+
|
38
|
+
# No
|
39
|
+
def file?
|
40
|
+
false
|
41
|
+
end
|
42
|
+
|
43
|
+
# @return [String] absolute path of current item
|
44
|
+
def absolute_path
|
45
|
+
if @parent_path
|
46
|
+
File.join(@parent_path, @name)
|
47
|
+
else
|
48
|
+
'/'
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
# Recursively creates empty directories.
|
53
|
+
#
|
54
|
+
# @param name [String] directories you'd like to create
|
55
|
+
# @return [OneDriveDir] the directory you created
|
56
|
+
def mkdir(name)
|
57
|
+
newdir, *remainder = name.split('/')
|
58
|
+
subdir = @od.request("drive/items/#{@id}:/#{newdir}") rescue nil
|
59
|
+
unless subdir
|
60
|
+
subdir = @od.request("drive/items/#{@id}/children",
|
61
|
+
name: newdir,
|
62
|
+
folder: {},
|
63
|
+
'@microsoft.graph.conflictBehavior': 'rename'
|
64
|
+
)
|
65
|
+
end
|
66
|
+
subdir = OneDriveDir.new(@od, subdir)
|
67
|
+
remainder.any? ? subdir.mkdir(remainder.join('/')) : subdir
|
68
|
+
end
|
69
|
+
|
70
|
+
# Uploads a local file into current remote directory using large file uploading mode.
|
71
|
+
#
|
72
|
+
# Unfinished download is stored as +target_name.incomplete+ and renamed upon completion.
|
73
|
+
#
|
74
|
+
# @param filename [String] local filename you'd like to upload
|
75
|
+
# @param overwrite [Boolean] whether to overwrite remote file, or rename this
|
76
|
+
# @param fragment_size [Integer] fragment size for each upload session, recommended to be multiple of 320KiB
|
77
|
+
# @param chunk_size [Integer] IO size for each disk read request and progress notification
|
78
|
+
# @param target_name [String] desired remote filename, a relative path to current directory
|
79
|
+
#
|
80
|
+
# @yield [event, status] for receive progress notification
|
81
|
+
# @yieldparam event [Symbol] event of this notification
|
82
|
+
# @yieldparam status [{Symbol => String,Integer}] details
|
83
|
+
def upload(filename, overwrite: false, fragment_size: 41_943_040, chunk_size: 1_048_576, target_name: nil, &block)
|
84
|
+
raise ArgumentError.new('File not found') unless File.exist?(filename)
|
85
|
+
file_size = File.size(filename)
|
86
|
+
resume_file = "#{filename}.1drv_upload"
|
87
|
+
resume_session = JSON.parse(File.read(resume_file)) rescue nil if File.exist?(resume_file)
|
88
|
+
|
89
|
+
if resume_session && resume_session['session_url']
|
90
|
+
conn = Excon.new(resume_session['session_url'])
|
91
|
+
result = JSON.parse(conn.get.body)
|
92
|
+
resume_position = result.dig('nextExpectedRanges', 0)&.split('-')&.first&.to_i or resume_session = nil
|
93
|
+
end
|
94
|
+
|
95
|
+
resume_position ||= 0
|
96
|
+
|
97
|
+
if resume_session
|
98
|
+
file_size == resume_session['source_size'] or resume_session = nil
|
99
|
+
end
|
100
|
+
|
101
|
+
unless resume_session
|
102
|
+
target_name ||= File.basename(filename)
|
103
|
+
result = @od.request("drive/items/#{@id}:/#{target_name}:/createUploadSession", item: {'@microsoft.graph.conflictBehavior': overwrite ? 'replace' : 'rename'})
|
104
|
+
resume_session = {
|
105
|
+
'session_url' => result['uploadUrl'],
|
106
|
+
'source_size' => File.size(filename),
|
107
|
+
'fragment_size' => fragment_size
|
108
|
+
}
|
109
|
+
File.write(resume_file, JSON.pretty_generate(resume_session))
|
110
|
+
end
|
111
|
+
|
112
|
+
new_file = nil
|
113
|
+
File.open(filename, mode: 'rb', external_encoding: Encoding::BINARY) do |f|
|
114
|
+
resume_position.step(file_size, resume_session['fragment_size']) do |from|
|
115
|
+
to = [from + resume_session['fragment_size'], file_size].min - 1
|
116
|
+
len = to - from + 1
|
117
|
+
headers = {
|
118
|
+
'Content-Length': len.to_s,
|
119
|
+
'Content-Range': "bytes #{from}-#{to}/#{file_size}"
|
120
|
+
}
|
121
|
+
@od.logger.info "Uploading #{from}-#{to}/#{file_size}"
|
122
|
+
yield :new_segment, file: filename, from: from, to: to if block_given?
|
123
|
+
sliced_io = SlicedIO.new(f, from, to) do |progress, total|
|
124
|
+
yield :progress, file: filename, from: from, to: to, progress: progress, total: total if block_given?
|
125
|
+
end
|
126
|
+
result = conn.put headers: headers, chunk_size: chunk_size, body: sliced_io
|
127
|
+
yield :finish_segment, file: filename, from: from, to: to if block_given?
|
128
|
+
result = JSON.parse(result.body)
|
129
|
+
new_file = OneDriveFile.new(@od, result) if result.dig('file')
|
130
|
+
end
|
131
|
+
File.unlink(resume_file)
|
132
|
+
end
|
133
|
+
new_file
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
module Rb1drv
|
2
|
+
class OneDriveFile < OneDriveItem
|
3
|
+
attr_reader :download_url
|
4
|
+
def initialize(od, api_hash)
|
5
|
+
super
|
6
|
+
@download_url = api_hash.dig('@microsoft.graph.downloadUrl')
|
7
|
+
end
|
8
|
+
|
9
|
+
# No
|
10
|
+
def dir?
|
11
|
+
false
|
12
|
+
end
|
13
|
+
|
14
|
+
# Yes
|
15
|
+
def file?
|
16
|
+
true
|
17
|
+
end
|
18
|
+
|
19
|
+
# Saves current remote file as local file.
|
20
|
+
#
|
21
|
+
# Unfinished download is stored as +target_name.incomplete+ and renamed upon completion.
|
22
|
+
#
|
23
|
+
# @param target_name [String] desired local filename, a relative path to current directory or an absolute path
|
24
|
+
# @param overwrite [Boolean] whether to overwrite local file, or skip this
|
25
|
+
# @param resume [Boolean] whether to resume an unfinished download, or start over anyway
|
26
|
+
#
|
27
|
+
# @yield [event, status] for receive progress notification
|
28
|
+
# @yieldparam event [Symbol] event of this notification
|
29
|
+
# @yieldparam status [{Symbol => String,Integer}] details
|
30
|
+
def save_as(target_name=nil, overwrite: false, resume: true, &block)
|
31
|
+
target_name ||= @name
|
32
|
+
tmpfile = "#{target_name}.incomplete"
|
33
|
+
|
34
|
+
return if !overwrite && File.exist?(target_name)
|
35
|
+
|
36
|
+
if resume && File.size(tmpfile) > 0
|
37
|
+
from = File.size(tmpfile)
|
38
|
+
len = @size - from
|
39
|
+
fmode = 'ab'
|
40
|
+
headers = {
|
41
|
+
'Range': "bytes=#{from}-"
|
42
|
+
}
|
43
|
+
else
|
44
|
+
from = 0
|
45
|
+
len = @size
|
46
|
+
fmode = 'wb'
|
47
|
+
headers = {}
|
48
|
+
end
|
49
|
+
|
50
|
+
yield :new_segment, file: target_name, from: from if block_given?
|
51
|
+
File.open(tmpfile, mode: fmode, external_encoding: Encoding::BINARY) do |f|
|
52
|
+
Excon.get download_url, headers: headers, response_block: ->(chunk, remaining_bytes, total_bytes) do
|
53
|
+
f.write(chunk)
|
54
|
+
yield :progress, file: target_name, from: from, progress: total_bytes - remaining_bytes, total: total_bytes if block_given?
|
55
|
+
end
|
56
|
+
end
|
57
|
+
yield :finish_segment, file: target_name if block_given?
|
58
|
+
FileUtils.mv(tmpfile, filename)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module Rb1drv
|
2
|
+
class OneDriveItem
|
3
|
+
attr_reader :id, :name, :eTag, :size, :mtime, :ctime, :muser, :cuser, :parent_path
|
4
|
+
protected
|
5
|
+
def initialize(od, api_hash)
|
6
|
+
@od = od
|
7
|
+
%w(id name eTag size).each do |key|
|
8
|
+
instance_variable_set("@#{key}", api_hash[key])
|
9
|
+
end
|
10
|
+
@mtime = Time.iso8601(api_hash.dig('lastModifiedDateTime'))
|
11
|
+
@ctime = Time.iso8601(api_hash.dig('createdDateTime'))
|
12
|
+
@muser = api_hash.dig('lastModifiedBy', 'user', 'displayName') || 'N/A'
|
13
|
+
@cuser = api_hash.dig('createdBy', 'user', 'displayName') || 'N/A'
|
14
|
+
@parent_path = api_hash.dig('parentReference', 'path')
|
15
|
+
end
|
16
|
+
|
17
|
+
# Create subclass instance by checking the item type
|
18
|
+
#
|
19
|
+
# @return [OneDriveFile, OneDriveDir] instanciated drive item
|
20
|
+
def self.smart_new(od, item_hash)
|
21
|
+
item_hash['file'] ? OneDriveFile.new(od, item_hash) : OneDriveDir.new(od, item_hash)
|
22
|
+
end
|
23
|
+
|
24
|
+
# @return [String] absolute path of current item
|
25
|
+
def absolute_path
|
26
|
+
if @parent_path
|
27
|
+
File.join(@parent_path, @name)
|
28
|
+
else
|
29
|
+
@name
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# SlicedIO slices a large File into a small portion.
|
2
|
+
class SlicedIO
|
3
|
+
def initialize(io, from, to, &block)
|
4
|
+
@io = io
|
5
|
+
@from = from
|
6
|
+
@to = to
|
7
|
+
@block = block
|
8
|
+
@current = 0
|
9
|
+
end
|
10
|
+
|
11
|
+
def rewind
|
12
|
+
io.seek(from)
|
13
|
+
@current = 0
|
14
|
+
end
|
15
|
+
|
16
|
+
def size
|
17
|
+
@size ||= @to - @from + 1
|
18
|
+
end
|
19
|
+
|
20
|
+
def read(len)
|
21
|
+
return nil if @current >= size
|
22
|
+
len = [len, @to - @current + 1].min
|
23
|
+
# Notify before we read
|
24
|
+
@block.call(@current, size)
|
25
|
+
@io.read(len)
|
26
|
+
ensure
|
27
|
+
@current += len
|
28
|
+
end
|
29
|
+
end
|
data/lib/rb1drv.rb
ADDED
@@ -0,0 +1,57 @@
|
|
1
|
+
require 'excon'
|
2
|
+
require 'oauth2'
|
3
|
+
require "rb1drv/version"
|
4
|
+
|
5
|
+
module Rb1drv
|
6
|
+
# Base class to support oauth2 authentication and sending simple API requests.
|
7
|
+
#
|
8
|
+
# Call +#root+ or +#get+ to get an +OneDriveDir+ or +OneDriveFile+ to wotk with.
|
9
|
+
class OneDrive
|
10
|
+
attr_reader :oauth2_client, :logger, :access_token
|
11
|
+
# Instanciates with app id and secret.
|
12
|
+
def initialize(client_id, client_secret, callback_url, logger=Logger.new(STDERR))
|
13
|
+
@client_id = client_id
|
14
|
+
@client_secret = client_secret
|
15
|
+
@callback_url = callback_url
|
16
|
+
@logger = logger
|
17
|
+
@oauth2_client = OAuth2::Client.new client_id, client_secret,
|
18
|
+
authorize_url: 'https://login.microsoftonline.com/common/oauth2/v2.0/authorize',
|
19
|
+
token_url: 'https://login.microsoftonline.com/common/oauth2/v2.0/token'
|
20
|
+
@conn = Excon.new('https://graph.microsoft.com/', persistent: true)
|
21
|
+
@conn.logger = @logger
|
22
|
+
end
|
23
|
+
|
24
|
+
# Issues requests to API endpoint.
|
25
|
+
#
|
26
|
+
# @param uri [String] relative path of the API
|
27
|
+
# @param data [Hash] JSON data to be post
|
28
|
+
# @param verb [Symbol] HTTP request verb if data is given
|
29
|
+
#
|
30
|
+
# @return [Hash] response from API.
|
31
|
+
def request(uri, data=nil, verb=:post)
|
32
|
+
@logger.info(uri)
|
33
|
+
query = {
|
34
|
+
path: File.join('v1.0/me/', uri),
|
35
|
+
headers: {
|
36
|
+
'Authorization': "Bearer #{@access_token.token}"
|
37
|
+
}
|
38
|
+
}
|
39
|
+
if data
|
40
|
+
query[:body] = JSON.generate(data)
|
41
|
+
query[:headers]['Content-Type'] = 'application/json'
|
42
|
+
@logger.info(query[:body])
|
43
|
+
verb = :post unless [:post, :put, :delete].include?(verb)
|
44
|
+
response = @conn.send(verb, query)
|
45
|
+
else
|
46
|
+
response = @conn.get(query)
|
47
|
+
end
|
48
|
+
JSON.parse(response.body)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
require 'rb1drv/auth'
|
54
|
+
require 'rb1drv/onedrive'
|
55
|
+
require 'rb1drv/onedrive_item'
|
56
|
+
require 'rb1drv/onedrive_dir'
|
57
|
+
require 'rb1drv/onedrive_file'
|
data/rb1drv.gemspec
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
|
2
|
+
lib = File.expand_path("../lib", __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require "rb1drv/version"
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "rb1drv"
|
8
|
+
spec.version = Rb1drv::VERSION
|
9
|
+
spec.authors = ["Xinyue Lu"]
|
10
|
+
spec.email = ["i@7086.in"]
|
11
|
+
|
12
|
+
spec.summary = "Ruby OneDrive Library"
|
13
|
+
spec.homepage = "https://github.com/msg7086/rb1drv"
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
spec.files = `git ls-files -z`.split("\x0").reject do |f|
|
17
|
+
f.match(%r{^(test|spec|features)/})
|
18
|
+
end
|
19
|
+
spec.bindir = "exe"
|
20
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
21
|
+
spec.require_paths = ["lib"]
|
22
|
+
spec.required_ruby_version = '>= 2.3'
|
23
|
+
|
24
|
+
spec.add_dependency "oauth2", "~> 1.4"
|
25
|
+
spec.add_dependency "excon", "~> 0.62"
|
26
|
+
spec.add_development_dependency "bundler", "~> 1.16"
|
27
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
28
|
+
end
|
metadata
ADDED
@@ -0,0 +1,115 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: rb1drv
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.2
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Xinyue Lu
|
8
|
+
autorequire:
|
9
|
+
bindir: exe
|
10
|
+
cert_chain: []
|
11
|
+
date: 2018-05-18 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: oauth2
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.4'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.4'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: excon
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0.62'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0.62'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: bundler
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '1.16'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '1.16'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: rake
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '10.0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '10.0'
|
69
|
+
description:
|
70
|
+
email:
|
71
|
+
- i@7086.in
|
72
|
+
executables: []
|
73
|
+
extensions: []
|
74
|
+
extra_rdoc_files: []
|
75
|
+
files:
|
76
|
+
- ".gitignore"
|
77
|
+
- ".travis.yml"
|
78
|
+
- Gemfile
|
79
|
+
- Gemfile.lock
|
80
|
+
- LICENSE.txt
|
81
|
+
- README.md
|
82
|
+
- lib/rb1drv.rb
|
83
|
+
- lib/rb1drv/auth.rb
|
84
|
+
- lib/rb1drv/onedrive.rb
|
85
|
+
- lib/rb1drv/onedrive_dir.rb
|
86
|
+
- lib/rb1drv/onedrive_file.rb
|
87
|
+
- lib/rb1drv/onedrive_item.rb
|
88
|
+
- lib/rb1drv/sliced_io.rb
|
89
|
+
- lib/rb1drv/version.rb
|
90
|
+
- rb1drv.gemspec
|
91
|
+
homepage: https://github.com/msg7086/rb1drv
|
92
|
+
licenses:
|
93
|
+
- MIT
|
94
|
+
metadata: {}
|
95
|
+
post_install_message:
|
96
|
+
rdoc_options: []
|
97
|
+
require_paths:
|
98
|
+
- lib
|
99
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - ">="
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '2.3'
|
104
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
105
|
+
requirements:
|
106
|
+
- - ">="
|
107
|
+
- !ruby/object:Gem::Version
|
108
|
+
version: '0'
|
109
|
+
requirements: []
|
110
|
+
rubyforge_project:
|
111
|
+
rubygems_version: 2.7.6
|
112
|
+
signing_key:
|
113
|
+
specification_version: 4
|
114
|
+
summary: Ruby OneDrive Library
|
115
|
+
test_files: []
|