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.
Files changed (44) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +23 -0
  3. data/.travis.yml +4 -0
  4. data/Gemfile +4 -0
  5. data/Guardfile +7 -0
  6. data/LICENSE.txt +22 -0
  7. data/README.md +204 -0
  8. data/Rakefile +11 -0
  9. data/bin/dropbox +133 -0
  10. data/bin/onedrive +133 -0
  11. data/cloud_door.gemspec +38 -0
  12. data/cloud_door_config.yml +12 -0
  13. data/data/.gitkeep +0 -0
  14. data/data/testlist +0 -0
  15. data/lib/cloud_door.rb +114 -0
  16. data/lib/cloud_door/account.rb +27 -0
  17. data/lib/cloud_door/cloud_storage.rb +294 -0
  18. data/lib/cloud_door/cloud_yaml.rb +45 -0
  19. data/lib/cloud_door/config.rb +61 -0
  20. data/lib/cloud_door/console.rb +334 -0
  21. data/lib/cloud_door/dropbox.rb +166 -0
  22. data/lib/cloud_door/exceptions.rb +153 -0
  23. data/lib/cloud_door/file_list.rb +164 -0
  24. data/lib/cloud_door/onedrive.rb +180 -0
  25. data/lib/cloud_door/onedrive_api.rb +169 -0
  26. data/lib/cloud_door/token.rb +67 -0
  27. data/lib/cloud_door/version.rb +3 -0
  28. data/log/.gitkeep +0 -0
  29. data/spec/cloud_door/account_spec.rb +96 -0
  30. data/spec/cloud_door/cloud_storage_spec.rb +10 -0
  31. data/spec/cloud_door/cloud_yaml_spec.rb +32 -0
  32. data/spec/cloud_door/config_spec.rb +95 -0
  33. data/spec/cloud_door/console_spec.rb +633 -0
  34. data/spec/cloud_door/dropbox_spec.rb +625 -0
  35. data/spec/cloud_door/file_list_spec.rb +451 -0
  36. data/spec/cloud_door/onedrive_api_spec.rb +256 -0
  37. data/spec/cloud_door/onedrive_spec.rb +652 -0
  38. data/spec/cloud_door/token_spec.rb +81 -0
  39. data/spec/fabricators/account_fabricator.rb +5 -0
  40. data/spec/fabricators/cloud_yaml_fabricator.rb +5 -0
  41. data/spec/fabricators/config_fabrication.rb +5 -0
  42. data/spec/fabricators/token_fabricator.rb +10 -0
  43. data/spec/spec_helper.rb +55 -0
  44. metadata +380 -0
@@ -0,0 +1,45 @@
1
+ require 'yaml'
2
+
3
+ module CloudDoor
4
+ class CloudYaml
5
+ attr_accessor :file, :items, :storage
6
+
7
+ def load_yaml
8
+ return false unless File.exist?(@file)
9
+ all_config = YAML.load_file(@file)
10
+ return false unless all_config.is_a?(Hash)
11
+ return false unless all_config.key?(@storage)
12
+ config = all_config[@storage]
13
+ @items.each do |item|
14
+ instance_variable_set("@#{item}", config[item]) if config.key?(item)
15
+ end
16
+ true
17
+ end
18
+
19
+ def update_yaml(update_params)
20
+ if File.exist?(@file)
21
+ all_config = YAML.load_file(@file)
22
+ if all_config.key?(@storage)
23
+ config = all_config[@storage]
24
+ else
25
+ config = {}
26
+ end
27
+ else
28
+ all_config = {}
29
+ config = {}
30
+ end
31
+ @items.each do |item|
32
+ next unless update_params.key?(item)
33
+ config[item] = update_params[item]
34
+ end
35
+ begin
36
+ all_config[@storage] = config
37
+ open(@file, 'wb') { |f| YAML.dump(all_config, f) }
38
+ load_yaml
39
+ true
40
+ rescue
41
+ false
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,61 @@
1
+ require 'cloud_door/cloud_yaml'
2
+
3
+ module CloudDoor
4
+ class Config < CloudYaml
5
+ attr_accessor :client_id, :client_secret, :redirect_url
6
+ attr_reader :data_path
7
+
8
+ CONFIG_FILE = './cloud_door_config.yml'
9
+
10
+ GLOBAL_CONFIG_ITEMS = [
11
+ 'data_path',
12
+ 'sessoin_flg',
13
+ ]
14
+
15
+ CONFIG_ITEMS = [
16
+ 'client_id',
17
+ 'client_secret',
18
+ 'redirect_url'
19
+ ]
20
+
21
+ SESSION_FLG_ON = '1'
22
+ SESSION_FLG_OFF = '0'
23
+
24
+ def initialize(storage)
25
+ @storage = storage
26
+ @data_path = './data/'
27
+ @session_flg = SESSION_FLG_OFF
28
+ @file = CONFIG_FILE
29
+ @items = CONFIG_ITEMS
30
+ @client_id = ''
31
+ @client_secret = ''
32
+ @redirect_url = ''
33
+ load_global_config
34
+ load_yaml
35
+ end
36
+
37
+ def load_global_config
38
+ return false unless File.exist?(@file)
39
+ all_config = YAML.load_file(@file)
40
+ return false unless all_config.is_a?(Hash)
41
+ return false unless all_config.key?('global')
42
+ config = all_config['global']
43
+ GLOBAL_CONFIG_ITEMS.each do |item|
44
+ instance_variable_set("@#{item}", config[item]) if config.key?(item)
45
+ end
46
+ true
47
+ end
48
+
49
+ def init?
50
+ CONFIG_ITEMS.each do |item|
51
+ val = instance_variable_get("@#{item}")
52
+ return false if val.nil? || val.empty?
53
+ end
54
+ true
55
+ end
56
+
57
+ def session_use?
58
+ (@session_flg.to_s == SESSION_FLG_ON.to_s)
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,334 @@
1
+ require 'highline/import'
2
+ require 'cloud_door'
3
+
4
+ module CloudDoor
5
+ class Console
6
+ attr_accessor :drive
7
+ attr_reader :storage_name
8
+
9
+ def initialize(drive, session_id = nil)
10
+ @drive = CloudDoor.new(drive, session_id)
11
+ @storage_name = @drive.show_storage_name
12
+ end
13
+
14
+ def config(show = false)
15
+ if show
16
+ show_configuration(@drive.show_configuration)
17
+ exit
18
+ end
19
+ configs = ask_configuration
20
+ result = @drive.update_configuration(configs)
21
+ show_result_message(result, 'update configuration')
22
+ end
23
+
24
+ def account(show = false)
25
+ if show
26
+ show_account(@drive.show_account)
27
+ exit
28
+ end
29
+ accounts = ask_account
30
+ result = @drive.update_account(accounts)
31
+ show_result_message(result, 'update account')
32
+ end
33
+
34
+ def login(default = false)
35
+ unless @drive.configuration_init?
36
+ say(make_message(:not_configuration, @storage_name.downcase))
37
+ exit
38
+ end
39
+ exit unless agree(make_message(:agree_access, @storage_name))
40
+ account = login_set_account(default)
41
+ say(make_message(:start_connection, @storage_name))
42
+ if @drive.login(account['login_account'], account['login_password'])
43
+ user = @drive.show_user
44
+ user_name = user['name'] || user['display_name']
45
+ say(make_message(:result_success, 'login'))
46
+ say(make_message(:login_as, user_name))
47
+ say("\n")
48
+ pwd = @drive.show_current_directory
49
+ list = @drive.show_files
50
+ show_file_list(pwd, list)
51
+ else
52
+ say(make_message(:result_fail, 'login'))
53
+ end
54
+ rescue => e
55
+ show_exception(e)
56
+ end
57
+
58
+ def ls(file_name)
59
+ @drive.load_token
60
+ fullname = make_fullname(file_name)
61
+ if !file_name.nil? && !file_name.empty?
62
+ unless @drive.file_exist?(file_name)
63
+ say(make_message(:file_not_exists, fullname, @storage_name))
64
+ exit
65
+ end
66
+ end
67
+ list = @drive.show_files(file_name)
68
+ show_file_list(fullname, list)
69
+ rescue => e
70
+ show_exception(e)
71
+ end
72
+
73
+ def cd(file_name)
74
+ if (file_name.nil? || file_name.empty?)
75
+ say(make_message(:wrong_parameter, 'file name'))
76
+ exit
77
+ end
78
+ @drive.load_token
79
+ fullname = make_fullname(file_name)
80
+ unless @drive.file_exist?(file_name)
81
+ say(make_message(:file_not_exists, fullname, @storage_name))
82
+ exit
83
+ end
84
+ say(make_message(:move_to, fullname))
85
+ list = @drive.change_directory(file_name)
86
+ show_file_list(fullname, list)
87
+ rescue => e
88
+ show_exception(e)
89
+ end
90
+
91
+ def info(file_name)
92
+ if (file_name.nil? || file_name.empty?)
93
+ say(make_message(:wrong_parameter, 'file name'))
94
+ exit
95
+ end
96
+ @drive.load_token
97
+ fullname = make_fullname(file_name)
98
+ unless @drive.file_exist?(file_name)
99
+ say(make_message(:file_not_exists, fullname, @storage_name))
100
+ exit
101
+ end
102
+ info = @drive.show_property(file_name)
103
+ unless (info.empty?)
104
+ say(make_message(:show_information, fullname))
105
+ max = info.max { |a, b| a[0].length <=> b[0].length }
106
+ max_len = max[0].length
107
+ info.each do |key, value|
108
+ say(" #{key.ljust(max_len)} : #{value}")
109
+ end
110
+ end
111
+ rescue => e
112
+ show_exception(e)
113
+ end
114
+
115
+ def pwd
116
+ @drive.load_token
117
+ say(@drive.show_current_directory)
118
+ end
119
+
120
+ def download(file_name)
121
+ if (file_name.nil? || file_name.empty?)
122
+ say(make_message(:wrong_parameter, 'file name'))
123
+ exit
124
+ end
125
+ @drive.load_token
126
+ fullname = make_fullname(file_name)
127
+ unless @drive.file_exist?(file_name)
128
+ say(make_message(:file_not_exists, fullname, @storage_name))
129
+ exit
130
+ end
131
+ if File.exist?(file_name)
132
+ say(make_message(:same_file_exist, file_name, 'local'))
133
+ exit unless agree(make_message(:agree_overwrite, file_name))
134
+ end
135
+ result = @drive.download_file(file_name)
136
+ show_result_message(result, "'#{file_name}' download")
137
+ rescue => e
138
+ show_exception(e)
139
+ end
140
+
141
+ def upload(file_name)
142
+ if (file_name.nil? || file_name.empty?)
143
+ say(make_message(:wrong_parameter, 'file name'))
144
+ exit
145
+ end
146
+ @drive.load_token
147
+ unless File.exists?(file_name)
148
+ say(make_message(:file_not_exists, file_name, 'local'))
149
+ exit
150
+ end
151
+ if File.directory?(file_name)
152
+ say(make_message(:is_directory, file_name))
153
+ say(make_message(:compress_to, file_name))
154
+ say("\n")
155
+ end
156
+ up_file = @drive.assign_upload_file_name(file_name)
157
+ fullname = make_fullname(up_file)
158
+ if @drive.file_exist?(up_file)
159
+ say(make_message(:same_file_exist, fullname, @storage_name))
160
+ exit unless agree(make_message(:agree_overwrite, fullname))
161
+ end
162
+ result = @drive.upload_file(file_name)
163
+ show_result_message(result, "'#{fullname}' upload")
164
+ rescue => e
165
+ show_exception(e)
166
+ end
167
+
168
+ def rm(file_name)
169
+ if (file_name.nil? || file_name.empty?)
170
+ say(make_message(:wrong_parameter, 'file name'))
171
+ exit
172
+ end
173
+ @drive.load_token
174
+ fullname = make_fullname(file_name)
175
+ exit unless agree(make_message(:agree_delete, fullname))
176
+ unless @drive.file_exist?(file_name)
177
+ say(make_message(:file_not_exists, fullname, @storage_name))
178
+ exit
179
+ end
180
+ if @drive.has_file?(file_name)
181
+ say(make_message(:has_files, fullname))
182
+ # exit unless agree("Do you want to delete these files (Y/N)?")
183
+ exit
184
+ end
185
+ result = @drive.delete_file(file_name)
186
+ show_result_message(result, "'#{fullname}' delete")
187
+ rescue => e
188
+ show_exception(e)
189
+ end
190
+
191
+ def mkdir(mkdir_name)
192
+ if (mkdir_name.nil? || mkdir_name.empty?)
193
+ say(make_message(:wrong_parameter, 'file name'))
194
+ exit
195
+ end
196
+ @drive.load_token
197
+ fullname = make_fullname(mkdir_name)
198
+ if @drive.file_exist?(mkdir_name)
199
+ say(make_message(:same_file_exist, fullname, @storage_name))
200
+ exit
201
+ end
202
+ result = @drive.make_directory(mkdir_name)
203
+ show_result_message(result, "make '#{fullname}' directory")
204
+ rescue => e
205
+ show_exception(e)
206
+ end
207
+
208
+ private
209
+
210
+ def make_message(type, *args)
211
+ messages = {
212
+ show_configuration: "#{args[0]} configuration are",
213
+ show_account: "#{args[0]} account are",
214
+ ask_configuration: "please enter the #{args[0]} configuration.",
215
+ ask_account: "please enter the #{args[0]} account.",
216
+ not_configuration: "config is not found. please execute './#{args[0]} config' before.",
217
+ account_found: "found defaulut account '#{args[0]}'. use this account.",
218
+ account_not_found: "default account is not found. please execute './#{args[0]} account' before.",
219
+ start_connection: "start a connection to the #{args[0]}. please wait a few seconds.",
220
+ login_as: "login as #{args[0]}.",
221
+ show_files: "you have these files on '#{args[0]}'.",
222
+ show_no_file: "you have no file on '#{args[0]}'.",
223
+ show_information: "information of '#{args[0]}'.",
224
+ move_to: "move to '#{args[0]}'.",
225
+ is_directory: "'#{args[0]}' is a directory.",
226
+ compress_to: "upload as '#{args[0]}.zip'.",
227
+ has_files: "'#{args[0]}' has files.",
228
+ wrong_parameter: "this command needs #{args[0]}.",
229
+ file_not_exists: "'#{args[0]}' not exists in #{args[1]}.",
230
+ same_file_exist: "'#{args[0]}' already exists in #{args[1]}.",
231
+ agree_access: "do you want to allow access to the #{args[0]} from this system(Y/N)?",
232
+ agree_overwrite: "do you want to overwrite '#{args[0]}' (Y/N)?",
233
+ agree_delete: "do you want to delete '#{args[0]}' (Y/N)?",
234
+ result_success: "#{args[0]} success.",
235
+ result_fail: "#{args[0]} fail.",
236
+ result_exception: "command fail.",
237
+ login_fail: "login fail.",
238
+ unauthorized: "please execute #{args[0]} auth' command."
239
+ }
240
+ if messages.key?(type)
241
+ messages[type]
242
+ end
243
+ end
244
+
245
+ def make_fullname(file_name)
246
+ pwd = @drive.show_current_directory
247
+ if file_name.nil? || file_name.empty?
248
+ pwd
249
+ else
250
+ "#{pwd}/#{file_name}"
251
+ end
252
+ end
253
+
254
+ def show_configuration(config)
255
+ say(make_message(:show_configuration, @storage_name))
256
+ say(" client_id : #{config.client_id}\n")
257
+ say(" client_secret: #{config.client_secret}\n")
258
+ say(" redirect_url : #{config.redirect_url}\n")
259
+ end
260
+
261
+ def ask_configuration
262
+ say(make_message(:ask_configuration, @storage_name))
263
+ configs = {}
264
+ configs['client_id'] = ask('client_id : ')
265
+ configs['client_secret'] = ask('client_secret : ')
266
+ configs['redirect_url'] = ask('redirect_url : ')
267
+ configs.each { |key, val| configs[key] = val.to_s }
268
+ end
269
+
270
+ def show_account(account)
271
+ say(make_message(:show_account, @storage_name))
272
+ say(" login_account : #{account.login_account}\n")
273
+ say(" login_password: #{account.login_password}\n")
274
+ end
275
+
276
+ def ask_account
277
+ say(make_message(:ask_account, @storage_name))
278
+ accounts = {}
279
+ accounts['login_account'] = ask('login_account : ')
280
+ accounts['login_password'] = ask('login_password: ') { |q| q.echo = '*' }
281
+ accounts.each { |key, val| accounts[key] = val.to_s }
282
+ end
283
+
284
+ def login_set_account(default)
285
+ account = Hash.new
286
+ if default
287
+ if @drive.isset_account?
288
+ default_account = @drive.show_account
289
+ account['login_account'] = default_account.login_account
290
+ account['login_password'] = default_account.login_password
291
+ say(make_message(:account_found, account['login_account']))
292
+ else
293
+ say(make_message(:account_not_found, @storage_name.downcase))
294
+ exit
295
+ end
296
+ else
297
+ say(make_message(:ask_account, @storage_name))
298
+ login_account = ask('login_account : ')
299
+ login_password = ask('login_password: ') { |q| q.echo = '*' }
300
+ account['login_account'] = login_account
301
+ account['login_password'] = login_password
302
+ end
303
+ account
304
+ end
305
+
306
+ def show_file_list(pwd, list)
307
+ if list.count > 0
308
+ say(make_message(:show_files, pwd))
309
+ list.each do |name, properties|
310
+ type = properties['type'].ljust(6)
311
+ say("[#{type}] #{name}")
312
+ end
313
+ else
314
+ say(make_message(:show_no_file, pwd))
315
+ end
316
+ end
317
+
318
+ def show_result_message(result, target)
319
+ if result
320
+ say(make_message(:result_success, target))
321
+ else
322
+ say(make_message(:result_fail, target))
323
+ end
324
+ end
325
+
326
+ def show_exception(e)
327
+ say(make_message(:result_exception))
328
+ say(e.message)
329
+ if e.is_a?(UnauthorizedException)
330
+ say(make_message(:unauthorized, @storage_name.downcase))
331
+ end
332
+ end
333
+ end
334
+ end
@@ -0,0 +1,166 @@
1
+ require 'dropbox_sdk'
2
+ require 'cloud_door/cloud_storage'
3
+
4
+ module CloudDoor
5
+ class Dropbox < 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
+ # dropbox login site components
11
+ LOGIN_COMPONENTS = {
12
+ 'account_text_name' => 'login_email',
13
+ 'password_text_name' => 'login_password',
14
+ 'signin_button_class' => 'login-button',
15
+ 'accept_button_name' => 'allow_access',
16
+ 'auth_code_id' => 'auth-code'
17
+ }
18
+
19
+ TIME_PROPERTIES = %w(client_mtime modified)
20
+ CONTENTS_KEY = 'contents'
21
+ ROOT_ID = '/'
22
+ STORAGE_NAME = 'Dropbox'
23
+
24
+ def initialize(session_id = nil)
25
+ @config = Config.new('dropbox')
26
+ @account = Account.new('dropbox', @config.data_path)
27
+ @token = Token.new('dropbox_token', @config.data_path, session_id)
28
+ @file_list = FileList.new('dropbox_list', @config.data_path, session_id)
29
+ @file_id = nil
30
+ @root_id = ROOT_ID
31
+ @storage_name = STORAGE_NAME
32
+ @session_id = session_id
33
+ end
34
+
35
+ def load_token
36
+ token_file = File.basename(@token.token_file)
37
+ @token = Token.load_token(token_file, @config.data_path, @session_id)
38
+ end
39
+
40
+ def login(login_account, login_password)
41
+ @account.login_account = login_account
42
+ @account.login_password = login_password
43
+ flow = DropboxOAuth2FlowNoRedirect.new(@config.client_id, @config.client_secret)
44
+ code = login_browser(flow.start())
45
+ access_token, user_id = flow.finish(code)
46
+ raise NoDataException if access_token.nil?
47
+ @session_id = reset_token({'access_token' => access_token})
48
+ items = pull_files
49
+ @file_list.delete_file
50
+ @file_list.write_file_list(items)
51
+ if @config.session_use?
52
+ @session_id
53
+ else
54
+ true
55
+ end
56
+ rescue => e
57
+ handle_exception(e)
58
+ end
59
+
60
+ private
61
+
62
+ def request_user
63
+ client = DropboxClient.new(@token.access_token)
64
+ info = client.account_info()
65
+ raise NoDataException if info.nil? || info.empty?
66
+ info
67
+ end
68
+
69
+ def request_dir
70
+ file_id = @parent_id || @file_id || ROOT_ID
71
+ client = DropboxClient.new(@token.access_token)
72
+ client.metadata(file_id)
73
+ end
74
+
75
+ def request_file
76
+ client = DropboxClient.new(@token.access_token)
77
+ client.metadata(@file_id)
78
+ end
79
+
80
+ def request_download
81
+ client = DropboxClient.new(@token.access_token)
82
+ contents, metadata = client.get_file_and_metadata(@file_id)
83
+ open(@file_name, 'w') {|f| f.puts contents }
84
+ metadata
85
+ end
86
+
87
+ def request_upload(file_path)
88
+ client = DropboxClient.new(@token.access_token)
89
+ if @parent_id == ROOT_ID
90
+ to_path = @parent_id + file_path
91
+ else
92
+ to_path = "#{@parent_id}/#{file_path}"
93
+ end
94
+ response = client.put_file(to_path, open(file_path))
95
+ raise UploadFailedException if response.nil? || response.empty?
96
+ response
97
+ end
98
+
99
+ def request_delete
100
+ client = DropboxClient.new(@token.access_token)
101
+ response = client.file_delete(@file_id)
102
+ raise DeleteFailedException if response.nil? || response.empty?
103
+ response
104
+ end
105
+
106
+ def request_mkdir
107
+ client = DropboxClient.new(@token.access_token)
108
+ if @parent_id == ROOT_ID
109
+ path = @parent_id + @mkdir_name
110
+ else
111
+ path = "#{@parent_id}/#{@mkdir_name}"
112
+ end
113
+ response = client.file_create_folder(path)
114
+ raise MkdirFailedException if response.nil? || response.empty?
115
+ response
116
+ end
117
+
118
+ def pull_files
119
+ dir = pick_cloud_info('request_dir', 'contents')
120
+ return {} if dir.nil? || !dir.is_a?(Array) || dir.count == 0
121
+ items = {}
122
+ dir.each do |item|
123
+ path, name = File.split(item['path'])
124
+ type = item['is_dir'] ? 'folder' : 'file'
125
+ items[name] = {'id' => item['path'], 'type' => type}
126
+ end
127
+ items
128
+ end
129
+
130
+ def format_property(info)
131
+ path, name = File.split(info['path'])
132
+ items = {}
133
+ items['name'] = name
134
+ info.each do |key, val|
135
+ if TIME_PROPERTIES.include?(key)
136
+ items[key] = DateTime.parse(val).strftime('%Y-%m-%d %H:%M:%S')
137
+ elsif key == CONTENTS_KEY
138
+ items['count'] = val.count
139
+ else
140
+ items[key] = val
141
+ end
142
+ end
143
+ items
144
+ end
145
+
146
+ def login_browser(auth_url)
147
+ browser = Watir::Browser.new :phantomjs
148
+ # input account
149
+ browser.goto(auth_url)
150
+ browser.wait
151
+ browser.text_field(:name, LOGIN_COMPONENTS['account_text_name']).set @account.login_account
152
+ browser.text_field(:name, LOGIN_COMPONENTS['password_text_name']).set @account.login_password
153
+ browser.button(:class, LOGIN_COMPONENTS['signin_button_class']).click
154
+ browser.button(:name => LOGIN_COMPONENTS['accept_button_name']).wait_until_present
155
+ # allow access
156
+ browser.button(:name, LOGIN_COMPONENTS['accept_button_name']).click
157
+ browser.wait
158
+ # get code
159
+ code = browser.div(:id, LOGIN_COMPONENTS['auth_code_id']).text
160
+ browser.close
161
+ code
162
+ rescue => e
163
+ handle_exception(e)
164
+ end
165
+ end
166
+ end