Class: Mass::Profile
- Inherits:
-
BlackStack::Base
- Object
- BlackStack::Base
- Mass::Profile
- Defined in:
- lib/base-line/profile.rb
Direct Known Subclasses
Constant Summary collapse
- LOCKFILE_PATH =
DROPBOX LOCKFILE PARAMETERS
'/tmp/dropbox_upload.lock'
- LOCK_TIMEOUT =
Path to your lockfile
30
Instance Attribute Summary collapse
-
#type ⇒ Object
Returns the value of attribute type.
Class Method Summary collapse
Instance Method Summary collapse
-
#acquire_lock ⇒ Object
DROPBOX LOCKFILE FUNCTIONS.
-
#child_class_instance ⇒ Object
crate an instance of the profile type using the class defined in the ‘desc` attribute.
-
#class_name_from_profile_type ⇒ Object
convert the profile_type into the ruby class to create an instance.
-
#connectioncheck(limit: 100, logger: nil) ⇒ Object
Scrape the inbox of the profile.
-
#download_image(img, dropbox_folder = nil) ⇒ Object
download image from Selenium using JavaScript and upload to Dropbox return the URL of the screenshot.
-
#download_image_0(url, dropbox_folder = nil) ⇒ Object
download image from Selenium using JavaScript and upload to Dropbox return the URL of the screenshot.
-
#inboxcheck(limit: 100, only_unread: true, logger: nil) ⇒ Object
Scrape the inbox of the profile.
-
#initialize(h) ⇒ Profile
constructor
A new instance of Profile.
- #release_lock ⇒ Object
-
#running? ⇒ Boolean
return true of the profile is running if its profile type is rpa-access, then it will return true if the browser is running.
- #upload_to_dropbox_with_lock(tmp_path, path) ⇒ Object
Constructor Details
#initialize(h) ⇒ Profile
Returns a new instance of Profile.
163 164 165 166 |
# File 'lib/base-line/profile.rb', line 163 def initialize(h) super(h) self.type = Mass::ProfileType.new(h['profile_type_desc']).child_class_instance end |
Instance Attribute Details
#type ⇒ Object
Returns the value of attribute type.
3 4 5 |
# File 'lib/base-line/profile.rb', line 3 def type @type end |
Class Method Details
.object_name ⇒ Object
159 160 161 |
# File 'lib/base-line/profile.rb', line 159 def self.object_name 'profile' end |
Instance Method Details
#acquire_lock ⇒ Object
DROPBOX LOCKFILE FUNCTIONS
10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
# File 'lib/base-line/profile.rb', line 10 def acquire_lock begin Timeout.timeout(LOCK_TIMEOUT) do # Wait until the lockfile can be created (i.e., it's not already taken) while File.exist?(LOCKFILE_PATH) sleep 0.1 end # Create the lockfile File.open(LOCKFILE_PATH, 'w') {} end rescue Timeout::Error raise "Timeout while waiting for lockfile." end end |
#child_class_instance ⇒ Object
crate an instance of the profile type using the class defined in the ‘desc` attribute. override the base method
177 178 179 180 181 182 183 |
# File 'lib/base-line/profile.rb', line 177 def child_class_instance profile_type = self.desc['profile_type'] key = self.class_name_from_profile_type raise "Source code of profile type #{profile_type} not found. Create a class #{key} in the folder `/lib` of your mass-sdk." unless Kernel.const_defined?(key) ret = Kernel.const_get(key).new(self.desc) return ret end |
#class_name_from_profile_type ⇒ Object
convert the profile_type into the ruby class to create an instance. example: Apollo –> Mass::ApolloAPI
170 171 172 173 |
# File 'lib/base-line/profile.rb', line 170 def class_name_from_profile_type profile_type = self.desc['profile_type'] "Mass::#{profile_type}" end |
#connectioncheck(limit: 100, logger: nil) ⇒ Object
Scrape the inbox of the profile. Return a an array of hash descriptors of outreach records.
Parameters:
-
limit: the maximum number of connections to scrape. Default: 100.
-
logger: a logger object to log the process. Default: nil.
Example of a hash descritor into the returned array: “‘
# a scraped message is always a :performed message
'status' => :performed,
# what is the outreach type?
# e.g.: :LinkedIn_ConnectionRequest
# decide this in the child class.
'outreach_type' => nil,
# hash descriptor of the profile who is scraping the inbox
'profile' => self.desc,
# hash descriptor of the lead who is the conversation partner
'lead' => nil,
# if the message has been sent by the profile, it is :outgoing.
# if the message has been sent by the lead, it is :incoming.
'direction' => :accepted,
“‘
256 257 258 |
# File 'lib/base-line/profile.rb', line 256 def connectioncheck(limit: 100, logger:nil) [] end |
#download_image(img, dropbox_folder = nil) ⇒ Object
download image from Selenium using JavaScript and upload to Dropbox return the URL of the screenshot
Parameters:
-
img: Selenium image element to download from the website and upload to dropbox.
-
dropbox_folder: Dropbox folder name to store the image.
152 153 154 |
# File 'lib/base-line/profile.rb', line 152 def download_image(img, dropbox_folder=nil) download_image_0(img.attribute('src'), dropbox_folder) end |
#download_image_0(url, dropbox_folder = nil) ⇒ Object
download image from Selenium using JavaScript and upload to Dropbox return the URL of the screenshot
Parameters:
-
url: Internet address of the image to download from the website and upload to dropbox.
-
dropbox_folder: Dropbox folder name to store the image.
58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 |
# File 'lib/base-line/profile.rb', line 58 def download_image_0(url, dropbox_folder = nil) raise "Either dropbox_folder parameter or self.desc['id_account'] are required." if dropbox_folder.nil? && self.desc['id_account'].nil? dropbox_folder = self.desc['id_account'] if dropbox_folder.nil? # Parameters id = SecureRandom.uuid # JavaScript to get base64 image data js0 = " function getImageBase64(imageSrc) { return new Promise(async (resolve, reject) => { try { const response = await fetch(imageSrc); const blob = await response.blob(); const reader = new FileReader(); reader.onloadend = function() { resolve(reader.result); }; reader.onerror = function(error) { reject(error); }; reader.readAsDataURL(blob); } catch (error) { reject(error); } }); } return getImageBase64('#{url}'); " # Execute JavaScript and get base64 image data base64_image = driver.execute_script(js0) raise "Failed to retrieve image data from URL: #{url}" if base64_image.nil? # Extract MIME type and base64 data mime_type_match = base64_image.match(/^data:image\/([a-zA-Z0-9.+-]+);base64,/) if mime_type_match mime_subtype = mime_type_match[1] # e.g., 'png', 'jpeg', 'gif' # Map common MIME subtypes to file extensions extension = case mime_subtype when 'jpeg' then 'jpg' else mime_subtype end # Remove the data URL prefix image_data = base64_image.sub(/^data:image\/[a-zA-Z0-9.+-]+;base64,/, '') else raise "Unsupported or invalid image data format." end # Update filename and paths filename = "#{id}.#{extension}" tmp_paths = if Mass.download_path.is_a?(String) ["#{Mass.download_path}/#{filename}"] elsif Mass.download_path.is_a?(Array) Mass.download_path.map { |s| "#{s}/#{filename}" } else raise "Invalid Mass.download_path configuration." end # Save the image to the first available path tmp_path = tmp_paths.find { |path| File.writable?(File.dirname(path)) } raise "No writable path found in #{tmp_paths.join(', ')}." if tmp_path.nil? File.open(tmp_path, 'wb') do |file| file.write(Base64.decode64(image_data)) end # Proceed with Dropbox operations year = Time.now.year.to_s.rjust(4, '0') month = Time.now.month.to_s.rjust(2, '0') folder = "/massprospecting.rpa/#{dropbox_folder}.#{year}.#{month}" path = "#{folder}/#{filename}" BlackStack::DropBox.dropbox_create_folder(folder) # Upload the file to Dropbox upload_to_dropbox_with_lock(tmp_path, path) # Delete the local file File.delete(tmp_path) # Return the URL of the file in Dropbox # # Add a timeout to wait the file is present in the cloud. # Reference: https://github.com/MassProspecting/docs/issues/320 self.wait_for_dropbox_url(path).gsub('&dl=1', '&dl=0') end |
#inboxcheck(limit: 100, only_unread: true, logger: nil) ⇒ Object
Scrape the inbox of the profile. Return a an array of hash descriptors of outreach records.
Parameters:
-
limit: the maximum number of messages to scrape. Default: 100.
-
only_unread: if true, then only the unread messages will be scraped. Default: true.
-
logger: a logger object to log the process. Default: nil.
Example of a hash descritor into the returned array: “‘
# a scraped message is always a :performed message
'status' => :performed,
# what is the outreach type?
# e.g.: :LinkedIn_DirectMessage
# decide this in the child class.
'outreach_type' => nil,
# hash descriptor of the profile who is scraping the inbox
'profile' => self.desc,
# hash descriptor of the lead who is the conversation partner
'lead' => nil,
# if the message has been sent by the profile, it is :outgoing.
# if the message has been sent by the lead, it is :incoming.
'direction' => nil,
# the content of the message
'subject' => nil,
'body' => nil,
“‘
226 227 228 |
# File 'lib/base-line/profile.rb', line 226 def inboxcheck(limit: 100, only_unread:true, logger:nil) [] end |
#release_lock ⇒ Object
25 26 27 |
# File 'lib/base-line/profile.rb', line 25 def release_lock File.delete(LOCKFILE_PATH) if File.exist?(LOCKFILE_PATH) end |
#running? ⇒ Boolean
return true of the profile is running if its profile type is rpa-access, then it will return true if the browser is running. else, it will return always true.
188 189 190 191 192 193 194 |
# File 'lib/base-line/profile.rb', line 188 def running? if self.type.desc['access'].to_sym == :rpa c = AdsPowerClient.new(key: ADSPOWER_API_KEY) return c.check(self.desc['ads_power_id']) end return true end |
#upload_to_dropbox_with_lock(tmp_path, path) ⇒ Object
29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 |
# File 'lib/base-line/profile.rb', line 29 def upload_to_dropbox_with_lock(tmp_path, path) s = '' acquire_lock begin # Upload the file to Dropbox s = BlackStack::DropBox.dropbox_upload_file(tmp_path, path) json = JSON.parse(s) if json['is_downloadable'].nil? || !json['is_downloadable'] raise "Dropbox file upload failed. Dropbox response: #{s}" end rescue => e raise "Error during upload: #{e.} - Dropbox response: #{s}" ensure # Always release the lock, even if an error occurs release_lock end end |