cloud_door 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
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