mass-client 1.0.38 → 1.0.39

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 79a458ee1f713c73e4567171dc2df8fe348612f4acb64b46987d9efbd941ee5c
4
- data.tar.gz: 5cdd47bfa69af7dafd52681b64fdd4609d3d3a2c03804dcb20ac7459af2de959
3
+ metadata.gz: 2f41c23dfa363362e8822c9c590dd0feb49fa8d7a0b46a4404289b3aaf36521d
4
+ data.tar.gz: d0378de6d177de59b594a0b40ad32a66ffc95ffaff456316843ee7ce7dd6b994
5
5
  SHA512:
6
- metadata.gz: 40bc64016ace0f97d2a8b6b3b48c85c67cfce7039f6852301be029d2a8a9ba565c6a2520bec6b5b4139a37bcc1c6ba61e24bc0d9444a2e2b36406764e2c11242
7
- data.tar.gz: 8d07063dd8c65e0a8a6831b3303ac953ddcb9e70f426259e0edb8f332b47b2e4728d755908a7fd94e241c5021a2c3a056a6745b427944384bb3f26b8fc1f0cde
6
+ metadata.gz: 40c38809a571acd66f9418892ebe4c4eaca23f01b78beed63faa9e1333b197a2a8e6575c6985f7186868d8d999efb419de5f70066b98fad9f64805dd8914e018
7
+ data.tar.gz: 78d3f81da07f724a42bbce1d53dfd2329a53a8c0c4874e8d728e7dba7a517087bedd20609a0fe77ac1916acee6ecda0248d0ce9fa7748a5b6100bf016a3d5cb2
@@ -28,25 +28,35 @@ module Mass
28
28
 
29
29
  # Function to upload a file to Amazon S3 and get its public URL
30
30
  def upload_file_to_s3(file_path, s3_key)
31
- # Upload the file
32
- Mass.s3.put_object(
33
- bucket: Mass.s3_bucket,
34
- key: s3_key,
35
- body: File.open(file_path)
36
- )
37
- # Generate the public URL
38
- public_url = "https://#{Mass.s3_bucket}.s3.amazonaws.com/#{s3_key}"
39
- # return
40
- return public_url
31
+ if @s3
32
+ # Upload the file
33
+ Mass.s3.put_object(
34
+ bucket: Mass.s3_bucket,
35
+ key: s3_key,
36
+ body: File.open(file_path)
37
+ )
38
+ # Generate the public URL
39
+ public_url = "https://#{Mass.s3_bucket}.s3.amazonaws.com/#{s3_key}"
40
+ # return
41
+ return public_url
42
+ elsif Mass.my_s3_api_key && Mass.my_s3_url
43
+ my_s3_upload_file(file_path, s3_key)
44
+ return my_s3_public_url_for(s3_key)
45
+ end
41
46
  end
42
47
 
43
48
  # Function to create a folder in S3
44
49
  def create_s3_folder(folder_name)
45
- Mass.s3.put_object(
46
- bucket: Mass.s3_bucket,
47
- key: "#{folder_name}/"
48
- )
49
- return true
50
+ if @s3
51
+ Mass.s3.put_object(
52
+ bucket: Mass.s3_bucket,
53
+ key: "#{folder_name}/"
54
+ )
55
+ return true
56
+ elsif Mass.my_s3_api_key && Mass.my_s3_url
57
+ ensure_my_s3_path_exists(folder_name)
58
+ return true
59
+ end
50
60
  end
51
61
 
52
62
  #
@@ -273,5 +283,125 @@ module Mass
273
283
  []
274
284
  end # def connectioncheck
275
285
 
286
+ class MyS3Error < StandardError; end
287
+
288
+ private
289
+
290
+ def ensure_my_s3_path_exists(path)
291
+ sanitized = path.to_s.strip.gsub(%r{^/+|/+$}, '')
292
+ return true if sanitized.empty?
293
+
294
+ current = ''
295
+ sanitized.split('/').each do |segment|
296
+ parent = current
297
+ begin
298
+ my_s3_json_post('/create_folder.json', {
299
+ path: parent,
300
+ folder_name: segment
301
+ })
302
+ rescue MyS3Error => e
303
+ raise unless e.message =~ /folder already exists/i
304
+ end
305
+ current = parent.empty? ? segment : [parent, segment].join('/').gsub(%r{/+}, '/').sub(%r{^/+}, '')
306
+ end
307
+
308
+ true
309
+ end
310
+
311
+ def my_s3_upload_file(local_path, remote_path)
312
+ raise MyS3Error, 'Local file not found' unless File.file?(local_path)
313
+
314
+ relative_path = File.dirname(remote_path.to_s)
315
+ relative_path = '' if relative_path == '.'
316
+ filename = File.basename(remote_path.to_s).to_s
317
+ raise MyS3Error, 'Remote filename is required' if filename.strip.empty?
318
+
319
+ uri = my_s3_uri_for('/upload.json')
320
+ boundary = "----MassMyS3#{SecureRandom.hex(12)}"
321
+ request = Net::HTTP::Post.new(uri)
322
+ request['X-API-Key'] = my_s3_api_key!
323
+ request['Content-Type'] = "multipart/form-data; boundary=#{boundary}"
324
+ request.body = build_my_s3_multipart(boundary, relative_path, filename, local_path)
325
+
326
+ response = my_s3_http(uri).request(request)
327
+ json = parse_my_s3_json(response.body)
328
+ return json if response.is_a?(Net::HTTPSuccess) && json['success']
329
+
330
+ message = json.dig('error', 'message') || response.body
331
+ raise MyS3Error, message
332
+ end
333
+
334
+ def my_s3_public_url_for(remote_path)
335
+ dir = File.dirname(remote_path.to_s)
336
+ dir = '' if dir == '.'
337
+ filename = File.basename(remote_path.to_s)
338
+ raise MyS3Error, 'Filename is required for public URL generation' if filename.to_s.strip.empty?
339
+
340
+ response = my_s3_json_post('/get_public_url.json', {
341
+ path: dir,
342
+ filename: filename
343
+ })
344
+
345
+ response['public_url']
346
+ end
347
+
348
+ def build_my_s3_multipart(boundary, relative_path, filename, local_path)
349
+ body = []
350
+ body << "--#{boundary}\r\n"
351
+ body << "Content-Disposition: form-data; name=\"path\"\r\n\r\n"
352
+ body << "#{relative_path}\r\n"
353
+ body << "--#{boundary}\r\n"
354
+ body << "Content-Disposition: form-data; name=\"file\"; filename=\"#{filename}\"\r\n"
355
+ body << "Content-Type: application/octet-stream\r\n\r\n"
356
+ body << File.binread(local_path)
357
+ body << "\r\n--#{boundary}--\r\n"
358
+ body.join
359
+ end
360
+
361
+ def my_s3_json_post(endpoint, payload)
362
+ uri = my_s3_uri_for(endpoint)
363
+ request = Net::HTTP::Post.new(uri)
364
+ request['Content-Type'] = 'application/json'
365
+ request['X-API-Key'] = my_s3_api_key!
366
+ request.body = JSON.generate(payload)
367
+
368
+ response = my_s3_http(uri).request(request)
369
+ json = parse_my_s3_json(response.body)
370
+ return json if response.is_a?(Net::HTTPSuccess) && json['success']
371
+
372
+ message = json.dig('error', 'message') || response.body
373
+ raise MyS3Error, message
374
+ end
375
+
376
+ def parse_my_s3_json(body)
377
+ return {} if body.nil? || body.strip.empty?
378
+ JSON.parse(body)
379
+ rescue JSON::ParserError
380
+ raise MyS3Error, "Invalid JSON response: #{body}"
381
+ end
382
+
383
+ def my_s3_uri_for(endpoint)
384
+ normalized = my_s3_base_url!
385
+ URI.join(normalized, endpoint.to_s.sub(%r{^/+}, ''))
386
+ end
387
+
388
+ def my_s3_http(uri)
389
+ http = Net::HTTP.new(uri.host, uri.port)
390
+ http.use_ssl = uri.scheme == 'https'
391
+ http
392
+ end
393
+
394
+ def my_s3_base_url!
395
+ base = Mass.my_s3_url.to_s.strip
396
+ raise MyS3Error, 'Mass.my_s3_url is not configured' if base.empty?
397
+ base.end_with?('/') ? base : "#{base}/"
398
+ end
399
+
400
+ def my_s3_api_key!
401
+ key = Mass.my_s3_api_key.to_s.strip
402
+ raise MyS3Error, 'Mass.my_s3_api_key is not configured' if key.empty?
403
+ key
404
+ end
405
+
276
406
  end # class Profile
277
407
  end # module Mass
data/lib/mass-client.rb CHANGED
@@ -17,12 +17,17 @@ module Mass
17
17
  @@drownload_path
18
18
  @@api_client
19
19
 
20
+ # DEPRECATED
20
21
  @@s3_bucket
21
22
  @@s3_region
22
23
  @@s3_access_key_id
23
24
  @@s3_secret_access_key
24
25
  @@s3
25
26
 
27
+ # https://github.com/MassProspecting/developer-documentation/issues/828
28
+ @@my_s3_api_key
29
+ @@my_s3_url
30
+
26
31
  # set the MassProspecting API client
27
32
  #
28
33
  # Parameters:
@@ -54,10 +59,15 @@ module Mass
54
59
  js_path: nil,
55
60
  download_path: [],
56
61
 
62
+ # DEPRECATED
57
63
  s3_region: nil,
58
64
  s3_access_key_id: nil,
59
65
  s3_secret_access_key: nil,
60
- s3_bucket: nil
66
+ s3_bucket: nil,
67
+
68
+ # https://github.com/MassProspecting/developer-documentation/issues/828
69
+ my_s3_api_key: nil,
70
+ my_s3_url: nil
61
71
  )
62
72
  # call the master to get the URL and port of the subaccount.
63
73
  BlackStack::API.set_client(
@@ -101,6 +111,7 @@ module Mass
101
111
  @@js_path = js_path
102
112
  @@download_path = download_path
103
113
 
114
+ @@s3 = nil
104
115
  @@s3_region = s3_region
105
116
  @@s3_access_key_id = s3_access_key_id
106
117
  @@s3_secret_access_key = s3_secret_access_key
@@ -119,6 +130,10 @@ module Mass
119
130
  secret_access_key: @@s3_secret_access_key
120
131
  )
121
132
  end
133
+
134
+ # Initialize My.S3 API key
135
+ @@my_s3_api_key = my_s3_api_key
136
+ @@my_s3_url = my_s3_url
122
137
  end
123
138
 
124
139
  def self.download_path
@@ -149,6 +164,14 @@ module Mass
149
164
  @@s3
150
165
  end
151
166
 
167
+ def self.my_s3_api_key
168
+ @@my_s3_api_key
169
+ end
170
+
171
+ def self.my_s3_url
172
+ @@my_s3_url
173
+ end
174
+
152
175
  end # module Mass
153
176
 
154
177
  # base classes
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mass-client
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.38
4
+ version: 1.0.39
5
5
  platform: ruby
6
6
  authors:
7
7
  - Leandro Daniel Sardi
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2025-12-02 00:00:00.000000000 Z
11
+ date: 2026-02-03 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: timeout