cloud_door 0.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.
- checksums.yaml +7 -0
- data/.gitignore +23 -0
- data/.travis.yml +4 -0
- data/Gemfile +4 -0
- data/Guardfile +7 -0
- data/LICENSE.txt +22 -0
- data/README.md +204 -0
- data/Rakefile +11 -0
- data/bin/dropbox +133 -0
- data/bin/onedrive +133 -0
- data/cloud_door.gemspec +38 -0
- data/cloud_door_config.yml +12 -0
- data/data/.gitkeep +0 -0
- data/data/testlist +0 -0
- data/lib/cloud_door.rb +114 -0
- data/lib/cloud_door/account.rb +27 -0
- data/lib/cloud_door/cloud_storage.rb +294 -0
- data/lib/cloud_door/cloud_yaml.rb +45 -0
- data/lib/cloud_door/config.rb +61 -0
- data/lib/cloud_door/console.rb +334 -0
- data/lib/cloud_door/dropbox.rb +166 -0
- data/lib/cloud_door/exceptions.rb +153 -0
- data/lib/cloud_door/file_list.rb +164 -0
- data/lib/cloud_door/onedrive.rb +180 -0
- data/lib/cloud_door/onedrive_api.rb +169 -0
- data/lib/cloud_door/token.rb +67 -0
- data/lib/cloud_door/version.rb +3 -0
- data/log/.gitkeep +0 -0
- data/spec/cloud_door/account_spec.rb +96 -0
- data/spec/cloud_door/cloud_storage_spec.rb +10 -0
- data/spec/cloud_door/cloud_yaml_spec.rb +32 -0
- data/spec/cloud_door/config_spec.rb +95 -0
- data/spec/cloud_door/console_spec.rb +633 -0
- data/spec/cloud_door/dropbox_spec.rb +625 -0
- data/spec/cloud_door/file_list_spec.rb +451 -0
- data/spec/cloud_door/onedrive_api_spec.rb +256 -0
- data/spec/cloud_door/onedrive_spec.rb +652 -0
- data/spec/cloud_door/token_spec.rb +81 -0
- data/spec/fabricators/account_fabricator.rb +5 -0
- data/spec/fabricators/cloud_yaml_fabricator.rb +5 -0
- data/spec/fabricators/config_fabrication.rb +5 -0
- data/spec/fabricators/token_fabricator.rb +10 -0
- data/spec/spec_helper.rb +55 -0
- metadata +380 -0
@@ -0,0 +1,153 @@
|
|
1
|
+
module CloudDoor
|
2
|
+
class FileNameEmptyException < StandardError
|
3
|
+
def message
|
4
|
+
'filename is not set.'
|
5
|
+
end
|
6
|
+
|
7
|
+
def to_s
|
8
|
+
message
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
class DirectoryNameEmptyException < StandardError
|
13
|
+
def message
|
14
|
+
'directory name is not set.'
|
15
|
+
end
|
16
|
+
|
17
|
+
def to_s
|
18
|
+
message
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
class SetIDException < StandardError
|
23
|
+
def message
|
24
|
+
'not found input file name.'
|
25
|
+
end
|
26
|
+
|
27
|
+
def to_s
|
28
|
+
message
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
class NotFileException < StandardError
|
33
|
+
def message
|
34
|
+
'target is not file.'
|
35
|
+
end
|
36
|
+
|
37
|
+
def to_s
|
38
|
+
message
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
class NotDirectoryException < StandardError
|
43
|
+
def message
|
44
|
+
'target is not directory.'
|
45
|
+
end
|
46
|
+
|
47
|
+
def to_s
|
48
|
+
message
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
class NoDataException < StandardError
|
53
|
+
def message
|
54
|
+
'not found request data.'
|
55
|
+
end
|
56
|
+
|
57
|
+
def to_s
|
58
|
+
message
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
class TokenClassException < StandardError
|
63
|
+
def message
|
64
|
+
'token is not Token Class.'
|
65
|
+
end
|
66
|
+
|
67
|
+
def to_s
|
68
|
+
message
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
class FileNotExistsException < StandardError
|
73
|
+
end
|
74
|
+
|
75
|
+
class RequestMethodNotFoundException < StandardError
|
76
|
+
end
|
77
|
+
|
78
|
+
class RequestPropertyNotFoundException < StandardError
|
79
|
+
end
|
80
|
+
|
81
|
+
class AccessCodeNotIncludeException < StandardError
|
82
|
+
def message
|
83
|
+
'access code not include in redirect url.'
|
84
|
+
end
|
85
|
+
|
86
|
+
def to_s
|
87
|
+
message
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
class UnauthorizedException < StandardError
|
92
|
+
def message
|
93
|
+
'authentication failed.'
|
94
|
+
end
|
95
|
+
|
96
|
+
def to_s
|
97
|
+
message
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
class HttpConnectionException < StandardError
|
102
|
+
def message
|
103
|
+
'access to storage failed.'
|
104
|
+
end
|
105
|
+
|
106
|
+
def to_s
|
107
|
+
message
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
class UploadFailedException < StandardError
|
112
|
+
def message
|
113
|
+
'upload file to storage failed.'
|
114
|
+
end
|
115
|
+
|
116
|
+
def to_s
|
117
|
+
message
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
class DeleteFailedException < StandardError
|
122
|
+
def message
|
123
|
+
'delete file from storage failed.'
|
124
|
+
end
|
125
|
+
|
126
|
+
def to_s
|
127
|
+
message
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
class MkdirFailedException < StandardError
|
132
|
+
def message
|
133
|
+
'make directory on storage failed.'
|
134
|
+
end
|
135
|
+
|
136
|
+
def to_s
|
137
|
+
message
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
class AbstractClassException < StandardError
|
142
|
+
def message
|
143
|
+
'this class is abstract class. please make inherited subclass.'
|
144
|
+
end
|
145
|
+
|
146
|
+
def to_s
|
147
|
+
message
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
class AbstractMethodException < StandardError
|
152
|
+
end
|
153
|
+
end
|
@@ -0,0 +1,164 @@
|
|
1
|
+
module CloudDoor
|
2
|
+
class FileList
|
3
|
+
attr_accessor :list_file, :list_name
|
4
|
+
attr_reader :list
|
5
|
+
|
6
|
+
def initialize(list_name, data_path, id = nil)
|
7
|
+
@list_name = list_name
|
8
|
+
@data_path = data_path
|
9
|
+
if (id.nil?)
|
10
|
+
@list_file = @data_path + @list_name
|
11
|
+
else
|
12
|
+
list_dir = @data_path + "#{id}"
|
13
|
+
unless File.exists?(list_dir)
|
14
|
+
Dir.mkdir(list_dir)
|
15
|
+
end
|
16
|
+
@list_file = "#{list_dir}/#{@list_name}"
|
17
|
+
end
|
18
|
+
@list = nil
|
19
|
+
end
|
20
|
+
|
21
|
+
def set_locate(id)
|
22
|
+
list_dir = @data_path + "#{id}"
|
23
|
+
unless File.exists?(list_dir)
|
24
|
+
Dir.mkdir(list_dir)
|
25
|
+
end
|
26
|
+
@list_file = "#{list_dir}/#{@list_name}"
|
27
|
+
end
|
28
|
+
|
29
|
+
def load_list
|
30
|
+
list = []
|
31
|
+
if File.exist?(@list_file)
|
32
|
+
marshal = File.open(@list_file).read
|
33
|
+
list = Marshal.load(marshal)
|
34
|
+
return false unless list.is_a?(Array)
|
35
|
+
end
|
36
|
+
@list = list
|
37
|
+
true
|
38
|
+
end
|
39
|
+
|
40
|
+
def write_file_list(items, file_id = '', file_name = '')
|
41
|
+
return false if load_list == false
|
42
|
+
if @list.empty?
|
43
|
+
add_list_top(items)
|
44
|
+
elsif file_name =~ CloudStorage::PARENT_DIR_PAT
|
45
|
+
back = file_name.scan(CloudStorage::PARENT_DIR_PAT).size + 1
|
46
|
+
remove_list(back)
|
47
|
+
else
|
48
|
+
if file_name.nil? || file_name.empty?
|
49
|
+
update_list(items)
|
50
|
+
else
|
51
|
+
add_list(items, file_id, file_name)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def add_list_top(items)
|
57
|
+
return false if items.nil? || !items.is_a?(Hash)
|
58
|
+
@list = []
|
59
|
+
@list << {'id' => 'top', 'name' => 'top', 'items' => items}
|
60
|
+
write_file
|
61
|
+
end
|
62
|
+
|
63
|
+
def add_list(items, file_id, file_name)
|
64
|
+
return false if items.nil? || !items.is_a?(Hash)
|
65
|
+
return false if file_id.nil? || file_id.empty?
|
66
|
+
return false if file_name.nil? || file_name.empty?
|
67
|
+
return false if load_list == false
|
68
|
+
@list << {'id' => file_id, 'name' => file_name, 'items' => items}
|
69
|
+
write_file
|
70
|
+
end
|
71
|
+
|
72
|
+
def update_list(items)
|
73
|
+
return false if items.nil? || !items.is_a?(Hash)
|
74
|
+
return false if load_list == false
|
75
|
+
last_node = @list[-1]
|
76
|
+
@list[-1] = {'id' => last_node['id'], 'name' => last_node['name'], 'items' => items}
|
77
|
+
write_file
|
78
|
+
end
|
79
|
+
|
80
|
+
def remove_list(back)
|
81
|
+
return false if load_list == false
|
82
|
+
size = @list.size
|
83
|
+
return false if back > size
|
84
|
+
last = size - back
|
85
|
+
@list = @list[0..last]
|
86
|
+
write_file
|
87
|
+
end
|
88
|
+
|
89
|
+
def delete_file
|
90
|
+
File.delete(@list_file) if File.exist?(@list_file)
|
91
|
+
true
|
92
|
+
rescue
|
93
|
+
false
|
94
|
+
end
|
95
|
+
|
96
|
+
def pull_parent_id
|
97
|
+
convert_name_to_id('current')
|
98
|
+
end
|
99
|
+
|
100
|
+
def pull_current_dir
|
101
|
+
return false if load_list == false
|
102
|
+
return '/top' if @list.size < 2
|
103
|
+
files = []
|
104
|
+
@list.each { |part| files << part['name'] unless part['name'].nil? }
|
105
|
+
'/' + files.join('/')
|
106
|
+
end
|
107
|
+
|
108
|
+
def pull_file_properties(file_name)
|
109
|
+
if @list.nil?
|
110
|
+
return false if load_list == false
|
111
|
+
end
|
112
|
+
return false if @list.empty?
|
113
|
+
items = @list.last['items']
|
114
|
+
return false if items.empty? || !items.key?(file_name)
|
115
|
+
items[file_name]
|
116
|
+
end
|
117
|
+
|
118
|
+
def convert_name_to_id(mode, file_name = '')
|
119
|
+
return false if load_list == false
|
120
|
+
return false unless %w(current parent target).include?(mode)
|
121
|
+
send("convert_#{mode}_id", file_name)
|
122
|
+
end
|
123
|
+
|
124
|
+
def top?(file_name)
|
125
|
+
back = (file_name.scan(CloudStorage::PARENT_DIR_PAT).size) + 1
|
126
|
+
@list.count < back
|
127
|
+
end
|
128
|
+
|
129
|
+
private
|
130
|
+
|
131
|
+
def write_file
|
132
|
+
marshal = Marshal.dump(@list)
|
133
|
+
open(@list_file, 'wb') { |file| file << marshal }
|
134
|
+
true
|
135
|
+
rescue
|
136
|
+
false
|
137
|
+
end
|
138
|
+
|
139
|
+
def convert_current_id(*)
|
140
|
+
if @list.count < 2
|
141
|
+
nil
|
142
|
+
else
|
143
|
+
@list.last['id']
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
def convert_parent_id(file_name)
|
148
|
+
back = (file_name.scan(CloudStorage::PARENT_DIR_PAT).size) + 1
|
149
|
+
return false if @list.size < back
|
150
|
+
last = @list.size - back
|
151
|
+
if last == 0
|
152
|
+
nil
|
153
|
+
else
|
154
|
+
@list[list.size - back]['id']
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
def convert_target_id(file_name)
|
159
|
+
properties = pull_file_properties(file_name)
|
160
|
+
return false unless properties
|
161
|
+
properties['id']
|
162
|
+
end
|
163
|
+
end
|
164
|
+
end
|
@@ -0,0 +1,180 @@
|
|
1
|
+
require 'cloud_door/cloud_storage'
|
2
|
+
require 'cloud_door/onedrive_api'
|
3
|
+
|
4
|
+
module CloudDoor
|
5
|
+
class OneDrive < CloudStorage
|
6
|
+
attr_accessor :token, :file_list, :file_id, :file_name,
|
7
|
+
:up_file_name, :mkdir_name, :parent_id
|
8
|
+
attr_reader :config, :account
|
9
|
+
|
10
|
+
# user root file_id
|
11
|
+
ROOT_ID = 'me/skydrive'
|
12
|
+
# onedrive login site components
|
13
|
+
LOGIN_COMPONENTS = {
|
14
|
+
'account_text_name' => 'login',
|
15
|
+
'password_text_name' => 'passwd',
|
16
|
+
'signin_button_id' => 'idSIButton9',
|
17
|
+
'accept_button_id' => 'idBtn_Accept'
|
18
|
+
}
|
19
|
+
TIME_PROPERTY_PAT = /_time$/
|
20
|
+
STORAGE_NAME = 'OneDrive'
|
21
|
+
|
22
|
+
def initialize(session_id = nil)
|
23
|
+
@config = Config.new('onedrive')
|
24
|
+
@account = Account.new('onedrive', @config.data_path)
|
25
|
+
@token = Token.new('onedrive_token', @config.data_path, session_id)
|
26
|
+
@file_list = FileList.new('onedrive_list', @config.data_path, session_id)
|
27
|
+
@file_id = nil
|
28
|
+
@root_id = ROOT_ID
|
29
|
+
@storage_name = STORAGE_NAME
|
30
|
+
@session_id = session_id
|
31
|
+
end
|
32
|
+
|
33
|
+
def load_token
|
34
|
+
token_file = File.basename(@token.token_file)
|
35
|
+
@token = Token.load_token(token_file, @config.data_path, @session_id)
|
36
|
+
end
|
37
|
+
|
38
|
+
def refresh_token
|
39
|
+
raise TokenClassException unless @token.is_a?(Token)
|
40
|
+
info = request_refresh_token
|
41
|
+
raise NoDataException if info.nil?
|
42
|
+
@token.set_attributes(info)
|
43
|
+
@token.write_token
|
44
|
+
rescue => e
|
45
|
+
handle_exception(e)
|
46
|
+
end
|
47
|
+
|
48
|
+
def login(login_account, login_password)
|
49
|
+
@account.login_account = login_account
|
50
|
+
@account.login_password = login_password
|
51
|
+
url = login_browser
|
52
|
+
info = request_get_token(url)
|
53
|
+
raise NoDataException if info.nil?
|
54
|
+
@session_id = reset_token(info)
|
55
|
+
items = pull_files
|
56
|
+
@file_list.delete_file
|
57
|
+
@file_list.write_file_list(items)
|
58
|
+
if @config.session_use?
|
59
|
+
@session_id
|
60
|
+
else
|
61
|
+
true
|
62
|
+
end
|
63
|
+
rescue => e
|
64
|
+
handle_exception(e)
|
65
|
+
end
|
66
|
+
|
67
|
+
private
|
68
|
+
|
69
|
+
def request_get_token(url)
|
70
|
+
query = URI.parse(url).query
|
71
|
+
raise AccessCodeNotIncludeException if query.nil?
|
72
|
+
params = CGI.parse(query)
|
73
|
+
raise AccessCodeNotIncludeException unless params.key?('code')
|
74
|
+
code = params['code'][0]
|
75
|
+
api = OneDriveApi.new(@token.access_token)
|
76
|
+
api.request_get_token(
|
77
|
+
code,
|
78
|
+
@config.client_id,
|
79
|
+
@config.client_secret,
|
80
|
+
@config.redirect_url
|
81
|
+
)
|
82
|
+
end
|
83
|
+
|
84
|
+
def request_refresh_token
|
85
|
+
api = OneDriveApi.new(@token.access_token)
|
86
|
+
api.request_refresh_token(
|
87
|
+
@token.refresh_token,
|
88
|
+
@config.client_id,
|
89
|
+
@config.client_secret,
|
90
|
+
@config.redirect_url
|
91
|
+
)
|
92
|
+
end
|
93
|
+
|
94
|
+
def request_user
|
95
|
+
api = OneDriveApi.new(@token.access_token)
|
96
|
+
api.request_user
|
97
|
+
end
|
98
|
+
|
99
|
+
def request_dir
|
100
|
+
file_id = @parent_id || @file_id || ROOT_ID
|
101
|
+
api = OneDriveApi.new(@token.access_token)
|
102
|
+
api.request_dir(file_id)
|
103
|
+
end
|
104
|
+
|
105
|
+
def request_file
|
106
|
+
api = OneDriveApi.new(@token.access_token)
|
107
|
+
api.request_file(@file_id)
|
108
|
+
end
|
109
|
+
|
110
|
+
def request_download
|
111
|
+
api = OneDriveApi.new(@token.access_token)
|
112
|
+
contens = api.request_download(@file_id)
|
113
|
+
open("#{@file_name}", 'wb') { |file| file << contens }
|
114
|
+
end
|
115
|
+
|
116
|
+
def request_upload(file_path)
|
117
|
+
api = OneDriveApi.new(@token.access_token)
|
118
|
+
api.request_upload(file_path, @parent_id)
|
119
|
+
end
|
120
|
+
|
121
|
+
def request_delete
|
122
|
+
api = OneDriveApi.new(@token.access_token)
|
123
|
+
api.request_delete(@file_id)
|
124
|
+
end
|
125
|
+
|
126
|
+
def request_mkdir
|
127
|
+
parent_id = @parent_id || ROOT_ID
|
128
|
+
api = OneDriveApi.new(@token.access_token)
|
129
|
+
api.request_mkdir(@mkdir_name, parent_id)
|
130
|
+
end
|
131
|
+
|
132
|
+
def pull_files
|
133
|
+
dir = pick_cloud_info('request_dir', 'data')
|
134
|
+
return {} if dir.nil? || !dir.is_a?(Array) || dir.count == 0
|
135
|
+
items = {}
|
136
|
+
dir.each do |item|
|
137
|
+
type = get_type_from_id(item['id'])
|
138
|
+
items[item['name']] = {'id' => item['id'], 'type' => type}
|
139
|
+
end
|
140
|
+
items
|
141
|
+
end
|
142
|
+
|
143
|
+
def format_property(info)
|
144
|
+
items = {}
|
145
|
+
info.each do |key, val|
|
146
|
+
if key =~ TIME_PROPERTY_PAT
|
147
|
+
items[key] = DateTime.parse(info[key]).strftime('%Y-%m-%d %H:%M:%S')
|
148
|
+
else
|
149
|
+
items[key] = info[key]
|
150
|
+
end
|
151
|
+
end
|
152
|
+
items
|
153
|
+
end
|
154
|
+
|
155
|
+
def get_type_from_id(file_id)
|
156
|
+
file_id.split('.')[0]
|
157
|
+
end
|
158
|
+
|
159
|
+
def login_browser
|
160
|
+
auth_url = OneDriveApi.make_auth_url(@config.client_id, @config.redirect_url)
|
161
|
+
browser = Watir::Browser.new :phantomjs
|
162
|
+
# input account
|
163
|
+
browser.goto(auth_url)
|
164
|
+
browser.wait
|
165
|
+
browser.text_field(:name, LOGIN_COMPONENTS['account_text_name']).set @account.login_account
|
166
|
+
browser.text_field(:name, LOGIN_COMPONENTS['password_text_name']).set @account.login_password
|
167
|
+
browser.button(:id, LOGIN_COMPONENTS['signin_button_id']).click
|
168
|
+
browser.wait
|
169
|
+
# allow access
|
170
|
+
browser.button(:id, LOGIN_COMPONENTS['accept_button_id']).click
|
171
|
+
browser.wait
|
172
|
+
# get redirect url
|
173
|
+
url = browser.url
|
174
|
+
browser.close
|
175
|
+
url
|
176
|
+
rescue => e
|
177
|
+
handle_exception(e)
|
178
|
+
end
|
179
|
+
end
|
180
|
+
end
|