mass-client 1.0.17 → 1.0.19

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 15fc20e0e46b85a66c45cbabbf3862fd1db6bff5fc254ec8b94414a0c5f086da
4
- data.tar.gz: 6cd0e9274b472a4e64a07d3f9f0d846b5499b2bbb3384e3e45a322d3a1210202
3
+ metadata.gz: 8606bfe0664c8ac8cf9f5af547b4925ff5982957da2842e1650caba3d974c02e
4
+ data.tar.gz: 0f72b71d5f681333ad318f23c1d27cc89267dc7a765ab72dc49d74e04356b6bd
5
5
  SHA512:
6
- metadata.gz: 663c292587112ca68d8a29643d7348d4510cf7028d1564d7f24c9259c518e1e25de0dfffc8bfef889f90f2f8e7a9d4625e80e4d95e8344ce81db83387c84cb66
7
- data.tar.gz: 176098ed2b937fc66af21da5e0d2d585a1960c209ab0eaa2be6579aa2a05fe866f532b36011c2bcb01043e51af202e1026235e870116f519191ecc04cd954e9b
6
+ metadata.gz: d9506f4eb6db0fb7dd2785efc503ee239b33764e6cf1d0643099ab3ce9f913bdf00e280b1301288fe069f97db6d9ed50a1c358c5e57bd7254f753355be0b773f
7
+ data.tar.gz: 7fce26002d9e2acf148330f23bb5c2ca4ced10fdcbf760b1e3d1286d35aa14bafff2f3057dc8fbe56f48b0f34894aff69263afdaff2670ebf1322d4aa5048011
@@ -91,7 +91,6 @@ module Mass
91
91
  # l.logf "Instantly warming email".red
92
92
  else
93
93
  lead_email = envelope.from[0].mailbox.to_s + '@' + envelope.from[0].host.to_s
94
-
95
94
  lead_name = envelope.from[0].name
96
95
  subject = envelope.subject
97
96
  body = imap.fetch(id, "BODY[]")[0].attr["BODY[]"]
@@ -101,33 +100,38 @@ module Mass
101
100
  #is_bounce = !rep.nil?
102
101
  #bounce_reason = rep[0].reason if rep
103
102
  #bounce_diagnosticcode = rep[0].diagnosticcode if rep
104
-
105
- h = {
106
- # a scraped message is always a :performed message
107
- 'status' => :performed,
108
- # what is the outreach type?
109
- # e.g.: :LinkedIn_DirectMessage
110
- # decide this in the child class.
111
- 'outreach_type' => :GMail_DirectMessage,
112
- # hash descriptor of the profile who is scraping the inbox
113
- 'profile' => p.desc,
114
- # hash descriptor of the lead who is the conversation partner
115
- 'lead_or_company' => {
116
- 'name' => lead_name,
117
- 'email' => lead_email,
118
- },
119
- # if the message has been sent by the profile, it is :outgoing.
120
- # if the message has been sent by the lead, it is :incoming.
121
- 'direction' => :incoming,
122
- # the content of the message
123
- 'subject' => subject,
124
- 'body' => body,
125
- 'message_id' => message_id,
126
- 'reply_to_message_id' => reply_to_message_id,
127
- }
128
- ret << h
129
103
 
130
- l.logf "done".green
104
+ if lead_name.nil?
105
+ l.skip(details: "lead_name is nil")
106
+ elsif lead_email.nil?
107
+ l.skip(details: "lead_email is nil")
108
+ else
109
+ h = {
110
+ # a scraped message is always a :performed message
111
+ 'status' => :performed,
112
+ # what is the outreach type?
113
+ # e.g.: :LinkedIn_DirectMessage
114
+ # decide this in the child class.
115
+ 'outreach_type' => :GMail_DirectMessage,
116
+ # hash descriptor of the profile who is scraping the inbox
117
+ 'profile' => p.desc,
118
+ # hash descriptor of the lead who is the conversation partner
119
+ 'lead_or_company' => {
120
+ 'name' => lead_name,
121
+ 'email' => lead_email,
122
+ },
123
+ # if the message has been sent by the profile, it is :outgoing.
124
+ # if the message has been sent by the lead, it is :incoming.
125
+ 'direction' => :incoming,
126
+ # the content of the message
127
+ 'subject' => subject,
128
+ 'body' => body,
129
+ 'message_id' => message_id,
130
+ 'reply_to_message_id' => reply_to_message_id,
131
+ }
132
+ ret << h
133
+ l.logf "done".green
134
+ end
131
135
  end
132
136
  }
133
137
 
@@ -175,96 +175,109 @@ module Mass
175
175
  automaticDownloads.find_element(:id => status.to_s).click()
176
176
  end # def automatic_downloads
177
177
 
178
+
179
+ def wait_for_file(file_paths, timeout = 30)
180
+ Timeout.timeout(timeout) do
181
+ loop do
182
+ file_paths.each do |path|
183
+ return path if File.exist?(path)
184
+ end
185
+ sleep(1)
186
+ end
187
+ end
188
+ rescue Timeout::Error
189
+ raise "Downloaded file not found in paths #{file_paths.join(',')} after #{timeout} seconds."
190
+ end
191
+
178
192
  # download image from Selenium using JavaScript and upload to Dropbox
179
193
  # return the URL of the screenshot
180
194
  #
181
195
  # Parameters:
182
196
  # - url: Internet address of the image to download from the website and upload to dropbox.
183
197
  # - dropbox_folder: Dropbox folder name to store the image.
184
- #
185
- def download_image_0(url, dropbox_folder=nil)
198
+ #
199
+ def download_image_0(url, dropbox_folder = nil)
186
200
  raise "Either dropbox_folder parameter or self.desc['id_account'] are required." if dropbox_folder.nil? && self.desc['id_account'].nil?
187
201
  dropbox_folder = self.desc['id_account'] if dropbox_folder.nil?
188
- # parameters
202
+
203
+ # Parameters
189
204
  id = SecureRandom.uuid
190
- filename = "#{id}.png"
191
- tmp_path = ["#{Mass.download_path}/#{filename}"] if Mass.download_path.is_a?(String)
192
- tmp_paths = Mass.download_path.map { |s| "#{s}/#{filename}" } if Mass.download_path.is_a?(Array)
193
-
194
- # excute JavaScript function downloadImage with the parameter src
195
- #binding.pry
196
- # this function is to download images from the same browser, using the proxy of the browser.
197
- # never download images from the server, because sites can track the IP.
198
- =begin
199
- js0 = "
200
- async function downloadImage(imageSrc, filename) {
201
- const image = await fetch(imageSrc)
202
- const imageBlog = await image.blob()
203
- const imageURL = URL.createObjectURL(imageBlog)
204
-
205
- const link = document.createElement('a')
206
- link.href = imageURL
207
- link.download = filename
208
- document.body.appendChild(link)
209
- link.click()
210
- document.body.removeChild(link)
211
- }
212
- downloadImage('#{url}', '#{filename}')
213
- "
214
- =end
215
- # Promise Handling: By returning a Promise in the JavaScript code, Selenium will wait for the asynchronous operation to complete.
216
- # Reference: https://github.com/MassProspecting/docs/issues/253
205
+
206
+ # JavaScript to get base64 image data
217
207
  js0 = "
218
- function downloadImage(imageSrc, filename) {
208
+ function getImageBase64(imageSrc) {
219
209
  return new Promise(async (resolve, reject) => {
220
210
  try {
221
- const image = await fetch(imageSrc);
222
- const imageBlob = await image.blob();
223
- const imageURL = URL.createObjectURL(imageBlob);
224
-
225
- const link = document.createElement('a');
226
- link.href = imageURL;
227
- link.download = filename;
228
- document.body.appendChild(link);
229
- link.click();
230
- document.body.removeChild(link);
231
-
232
- resolve('Download initiated');
233
- } catch (error) {
211
+ const response = await fetch(imageSrc);
212
+ const blob = await response.blob();
213
+ const reader = new FileReader();
214
+ reader.onloadend = function() {
215
+ resolve(reader.result);
216
+ };
217
+ reader.onerror = function(error) {
234
218
  reject(error);
219
+ };
220
+ reader.readAsDataURL(blob);
221
+ } catch (error) {
222
+ reject(error);
235
223
  }
236
224
  });
237
- }
238
- return downloadImage('#{url}', '#{filename}');
225
+ }
226
+ return getImageBase64('#{url}');
239
227
  "
240
- #binding.pry
241
- driver.execute_script(js0)
242
- sleep(10)
243
- # code
244
- year = Time.now.year.to_s.rjust(4,'0')
245
- month = Time.now.month.to_s.rjust(2,'0')
228
+
229
+ # Execute JavaScript and get base64 image data
230
+ base64_image = driver.execute_script(js0)
231
+ raise "Failed to retrieve image data from URL: #{url}" if base64_image.nil?
232
+
233
+ # Extract MIME type and base64 data
234
+ mime_type_match = base64_image.match(/^data:image\/([a-zA-Z0-9.+-]+);base64,/)
235
+ if mime_type_match
236
+ mime_subtype = mime_type_match[1] # e.g., 'png', 'jpeg', 'gif'
237
+ # Map common MIME subtypes to file extensions
238
+ extension = case mime_subtype
239
+ when 'jpeg' then 'jpg'
240
+ else mime_subtype
241
+ end
242
+ # Remove the data URL prefix
243
+ image_data = base64_image.sub(/^data:image\/[a-zA-Z0-9.+-]+;base64,/, '')
244
+ else
245
+ raise "Unsupported or invalid image data format."
246
+ end
247
+
248
+ # Update filename and paths
249
+ filename = "#{id}.#{extension}"
250
+ tmp_paths = if Mass.download_path.is_a?(String)
251
+ ["#{Mass.download_path}/#{filename}"]
252
+ elsif Mass.download_path.is_a?(Array)
253
+ Mass.download_path.map { |s| "#{s}/#{filename}" }
254
+ else
255
+ raise "Invalid Mass.download_path configuration."
256
+ end
257
+
258
+ # Save the image to the first available path
259
+ tmp_path = tmp_paths.find { |path| File.writable?(File.dirname(path)) }
260
+ raise "No writable path found in #{tmp_paths.join(', ')}." if tmp_path.nil?
261
+
262
+ File.open(tmp_path, 'wb') do |file|
263
+ file.write(Base64.decode64(image_data))
264
+ end
265
+
266
+ # Proceed with Dropbox operations
267
+ year = Time.now.year.to_s.rjust(4, '0')
268
+ month = Time.now.month.to_s.rjust(2, '0')
246
269
  folder = "/massprospecting.rpa/#{dropbox_folder}.#{year}.#{month}"
247
270
  path = "#{folder}/#{filename}"
248
271
  BlackStack::DropBox.dropbox_create_folder(folder)
249
-
250
- # find the tmp_path that exists
251
- tmp_path = nil
252
- tmp_paths.each { |s|
253
- if File.exist?(s)
254
- tmp_path = s
255
- break
256
- end
257
- }
258
- raise "Downloaded file #{filename} not found in paths #{tmp_paths.join(',')}." if tmp_path.nil?
259
-
260
- # upload the file to dropbox
272
+
273
+ # Upload the file to Dropbox
261
274
  BlackStack::DropBox.dropbox_upload_file(tmp_path, path)
262
- # delete the file
275
+ # Delete the local file
263
276
  File.delete(tmp_path)
264
- # return the URL of the file in dropbox
277
+ # Return the URL of the file in Dropbox
265
278
  BlackStack::DropBox.get_file_url(path).gsub('&dl=1', '&dl=0')
266
- end # def download_image_0
267
-
279
+ end
280
+
268
281
  # download image from Selenium using JavaScript and upload to Dropbox
269
282
  # return the URL of the screenshot
270
283
  #
data/lib/mass-client.rb CHANGED
@@ -5,6 +5,8 @@ require 'blackstack-core'
5
5
  require 'simple_cloud_logging'
6
6
  require 'simple_command_line_parser'
7
7
  require 'colorize'
8
+ require 'timeout'
9
+ require 'base64'
8
10
 
9
11
  # mass client configuration
10
12
  module Mass
metadata CHANGED
@@ -1,33 +1,55 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mass-client
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.17
4
+ version: 1.0.19
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: 2024-09-09 00:00:00.000000000 Z
11
+ date: 2024-09-17 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
- name: uri
14
+ name: timeout
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: 0.11.2
20
- - - ">="
19
+ version: 0.4.1
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
21
25
  - !ruby/object:Gem::Version
22
- version: 0.11.2
26
+ version: 0.4.1
27
+ - !ruby/object:Gem::Dependency
28
+ name: base64
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: 0.1.1
23
34
  type: :runtime
24
35
  prerelease: false
25
36
  version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: 0.1.1
41
+ - !ruby/object:Gem::Dependency
42
+ name: uri
43
+ requirement: !ruby/object:Gem::Requirement
26
44
  requirements:
27
45
  - - "~>"
28
46
  - !ruby/object:Gem::Version
29
47
  version: 0.11.2
30
- - - ">="
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
31
53
  - !ruby/object:Gem::Version
32
54
  version: 0.11.2
33
55
  - !ruby/object:Gem::Dependency
@@ -37,9 +59,6 @@ dependencies:
37
59
  - - "~>"
38
60
  - !ruby/object:Gem::Version
39
61
  version: 0.2.0
40
- - - ">="
41
- - !ruby/object:Gem::Version
42
- version: 0.2.0
43
62
  type: :runtime
44
63
  prerelease: false
45
64
  version_requirements: !ruby/object:Gem::Requirement
@@ -47,9 +66,6 @@ dependencies:
47
66
  - - "~>"
48
67
  - !ruby/object:Gem::Version
49
68
  version: 0.2.0
50
- - - ">="
51
- - !ruby/object:Gem::Version
52
- version: 0.2.0
53
69
  - !ruby/object:Gem::Dependency
54
70
  name: json
55
71
  requirement: !ruby/object:Gem::Requirement
@@ -57,9 +73,6 @@ dependencies:
57
73
  - - "~>"
58
74
  - !ruby/object:Gem::Version
59
75
  version: 2.6.3
60
- - - ">="
61
- - !ruby/object:Gem::Version
62
- version: 2.6.3
63
76
  type: :runtime
64
77
  prerelease: false
65
78
  version_requirements: !ruby/object:Gem::Requirement
@@ -67,9 +80,6 @@ dependencies:
67
80
  - - "~>"
68
81
  - !ruby/object:Gem::Version
69
82
  version: 2.6.3
70
- - - ">="
71
- - !ruby/object:Gem::Version
72
- version: 2.6.3
73
83
  - !ruby/object:Gem::Dependency
74
84
  name: blackstack-core
75
85
  requirement: !ruby/object:Gem::Requirement
@@ -77,9 +87,6 @@ dependencies:
77
87
  - - "~>"
78
88
  - !ruby/object:Gem::Version
79
89
  version: 1.2.20
80
- - - ">="
81
- - !ruby/object:Gem::Version
82
- version: 1.2.20
83
90
  type: :runtime
84
91
  prerelease: false
85
92
  version_requirements: !ruby/object:Gem::Requirement
@@ -87,9 +94,6 @@ dependencies:
87
94
  - - "~>"
88
95
  - !ruby/object:Gem::Version
89
96
  version: 1.2.20
90
- - - ">="
91
- - !ruby/object:Gem::Version
92
- version: 1.2.20
93
97
  - !ruby/object:Gem::Dependency
94
98
  name: colorize
95
99
  requirement: !ruby/object:Gem::Requirement
@@ -97,9 +101,6 @@ dependencies:
97
101
  - - "~>"
98
102
  - !ruby/object:Gem::Version
99
103
  version: 0.8.1
100
- - - ">="
101
- - !ruby/object:Gem::Version
102
- version: 0.8.1
103
104
  type: :runtime
104
105
  prerelease: false
105
106
  version_requirements: !ruby/object:Gem::Requirement
@@ -107,9 +108,6 @@ dependencies:
107
108
  - - "~>"
108
109
  - !ruby/object:Gem::Version
109
110
  version: 0.8.1
110
- - - ">="
111
- - !ruby/object:Gem::Version
112
- version: 0.8.1
113
111
  - !ruby/object:Gem::Dependency
114
112
  name: simple_cloud_logging
115
113
  requirement: !ruby/object:Gem::Requirement
@@ -117,9 +115,6 @@ dependencies:
117
115
  - - "~>"
118
116
  - !ruby/object:Gem::Version
119
117
  version: 1.2.6
120
- - - ">="
121
- - !ruby/object:Gem::Version
122
- version: 1.2.6
123
118
  type: :runtime
124
119
  prerelease: false
125
120
  version_requirements: !ruby/object:Gem::Requirement
@@ -127,9 +122,6 @@ dependencies:
127
122
  - - "~>"
128
123
  - !ruby/object:Gem::Version
129
124
  version: 1.2.6
130
- - - ">="
131
- - !ruby/object:Gem::Version
132
- version: 1.2.6
133
125
  - !ruby/object:Gem::Dependency
134
126
  name: simple_command_line_parser
135
127
  requirement: !ruby/object:Gem::Requirement
@@ -137,9 +129,6 @@ dependencies:
137
129
  - - "~>"
138
130
  - !ruby/object:Gem::Version
139
131
  version: 1.1.2
140
- - - ">="
141
- - !ruby/object:Gem::Version
142
- version: 1.1.2
143
132
  type: :runtime
144
133
  prerelease: false
145
134
  version_requirements: !ruby/object:Gem::Requirement
@@ -147,9 +136,6 @@ dependencies:
147
136
  - - "~>"
148
137
  - !ruby/object:Gem::Version
149
138
  version: 1.1.2
150
- - - ">="
151
- - !ruby/object:Gem::Version
152
- version: 1.1.2
153
139
  description: Ruby library for MassProspecting API.
154
140
  email: leandro@massprospecting.com
155
141
  executables: []