roseflow-proxycurl 0.5.0
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 +7 -0
 - data/.rspec +3 -0
 - data/.standard.yml +3 -0
 - data/CHANGELOG.md +10 -0
 - data/CODE_OF_CONDUCT.md +84 -0
 - data/Gemfile +12 -0
 - data/LICENSE.txt +21 -0
 - data/README.md +49 -0
 - data/Rakefile +10 -0
 - data/lib/roseflow/linkedin/company/lookup_query.rb +58 -0
 - data/lib/roseflow/linkedin/company/object.rb +82 -0
 - data/lib/roseflow/linkedin/company/profile_query.rb +50 -0
 - data/lib/roseflow/linkedin/company.rb +38 -0
 - data/lib/roseflow/linkedin/job/object.rb +77 -0
 - data/lib/roseflow/linkedin/job/profile_query.rb +32 -0
 - data/lib/roseflow/linkedin/job/search_query.rb +48 -0
 - data/lib/roseflow/linkedin/job.rb +38 -0
 - data/lib/roseflow/linkedin/job_list_entry.rb +20 -0
 - data/lib/roseflow/linkedin/person/experience.rb +73 -0
 - data/lib/roseflow/linkedin/person/lookup_query.rb +57 -0
 - data/lib/roseflow/linkedin/person/object.rb +69 -0
 - data/lib/roseflow/linkedin/person/profile_query.rb +53 -0
 - data/lib/roseflow/linkedin/person/role_query.rb +48 -0
 - data/lib/roseflow/linkedin/person.rb +50 -0
 - data/lib/roseflow/proxycurl/client.rb +27 -0
 - data/lib/roseflow/proxycurl/config.rb +17 -0
 - data/lib/roseflow/proxycurl/object.rb +11 -0
 - data/lib/roseflow/proxycurl/version.rb +18 -0
 - data/lib/roseflow/proxycurl.rb +10 -0
 - data/roseflow-proxycurl.gemspec +49 -0
 - data/sig/roseflow/proxycurl.rbs +6 -0
 - metadata +244 -0
 
| 
         @@ -0,0 +1,73 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # frozen_string_literal: true
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            module Types
         
     | 
| 
      
 4 
     | 
    
         
            +
              DateOrNil = Date | Nil
         
     | 
| 
      
 5 
     | 
    
         
            +
              StringOrNil = String | Nil
         
     | 
| 
      
 6 
     | 
    
         
            +
            end
         
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
      
 8 
     | 
    
         
            +
            module Functions
         
     | 
| 
      
 9 
     | 
    
         
            +
              extend Dry::Transformer::Registry
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
              register :to_date, ->(v) { Date.parse("#{v.dig(:year)}-#{v.dig(:month)}-#{v.dig(:day)}") unless v.nil? }
         
     | 
| 
      
 12 
     | 
    
         
            +
            end
         
     | 
| 
      
 13 
     | 
    
         
            +
             
     | 
| 
      
 14 
     | 
    
         
            +
            module Roseflow
         
     | 
| 
      
 15 
     | 
    
         
            +
              module LinkedIn
         
     | 
| 
      
 16 
     | 
    
         
            +
                class Person
         
     | 
| 
      
 17 
     | 
    
         
            +
                  class ExperienceMapper < Dry::Transformer::Pipe
         
     | 
| 
      
 18 
     | 
    
         
            +
                    import Dry::Transformer::HashTransformations
         
     | 
| 
      
 19 
     | 
    
         
            +
             
     | 
| 
      
 20 
     | 
    
         
            +
                    def custom_t(*args)
         
     | 
| 
      
 21 
     | 
    
         
            +
                      Functions[*args]
         
     | 
| 
      
 22 
     | 
    
         
            +
                    end
         
     | 
| 
      
 23 
     | 
    
         
            +
             
     | 
| 
      
 24 
     | 
    
         
            +
                    define! do
         
     | 
| 
      
 25 
     | 
    
         
            +
                      deep_symbolize_keys
         
     | 
| 
      
 26 
     | 
    
         
            +
                      rename_keys company_linkedin_profile_url: :company_profile_url, starts_at: :started_on, ends_at: :ended_on
         
     | 
| 
      
 27 
     | 
    
         
            +
             
     | 
| 
      
 28 
     | 
    
         
            +
                      map_value :started_on, ->(v) { Date.parse("#{v.dig(:year)}-#{v.dig(:month)}-#{v.dig(:day)}") unless v.nil? }
         
     | 
| 
      
 29 
     | 
    
         
            +
                      map_value :ended_on, ->(v) { Date.parse("#{v.dig(:year)}-#{v.dig(:month)}-#{v.dig(:day)}") unless v.nil? }
         
     | 
| 
      
 30 
     | 
    
         
            +
                    end
         
     | 
| 
      
 31 
     | 
    
         
            +
                  end
         
     | 
| 
      
 32 
     | 
    
         
            +
             
     | 
| 
      
 33 
     | 
    
         
            +
                  class Experience < Dry::Struct
         
     | 
| 
      
 34 
     | 
    
         
            +
                    defines :contract_object
         
     | 
| 
      
 35 
     | 
    
         
            +
             
     | 
| 
      
 36 
     | 
    
         
            +
                    class ExperienceContract < Dry::Validation::Contract
         
     | 
| 
      
 37 
     | 
    
         
            +
                      params do
         
     | 
| 
      
 38 
     | 
    
         
            +
                        required(:title).filled(:string)
         
     | 
| 
      
 39 
     | 
    
         
            +
                        required(:company).filled(:string)
         
     | 
| 
      
 40 
     | 
    
         
            +
                        optional(:company_profile_url).filled(:string)
         
     | 
| 
      
 41 
     | 
    
         
            +
                        optional(:location)
         
     | 
| 
      
 42 
     | 
    
         
            +
                        optional(:description)
         
     | 
| 
      
 43 
     | 
    
         
            +
                        optional(:started_on).filled(:date)
         
     | 
| 
      
 44 
     | 
    
         
            +
                        optional(:ended_on)
         
     | 
| 
      
 45 
     | 
    
         
            +
                      end
         
     | 
| 
      
 46 
     | 
    
         
            +
             
     | 
| 
      
 47 
     | 
    
         
            +
                      def call(input)
         
     | 
| 
      
 48 
     | 
    
         
            +
                        transformed = ExperienceMapper.new.call(input)
         
     | 
| 
      
 49 
     | 
    
         
            +
                        super(transformed)
         
     | 
| 
      
 50 
     | 
    
         
            +
                      end
         
     | 
| 
      
 51 
     | 
    
         
            +
                    end
         
     | 
| 
      
 52 
     | 
    
         
            +
             
     | 
| 
      
 53 
     | 
    
         
            +
                    attribute :title, Types::String
         
     | 
| 
      
 54 
     | 
    
         
            +
                    attribute :company, Types::String
         
     | 
| 
      
 55 
     | 
    
         
            +
                    attribute? :company_profile_url, Types::StringOrNil
         
     | 
| 
      
 56 
     | 
    
         
            +
                    attribute? :location, Types::StringOrNil
         
     | 
| 
      
 57 
     | 
    
         
            +
                    attribute? :description, Types::StringOrNil
         
     | 
| 
      
 58 
     | 
    
         
            +
                    attribute :started_on, Types::Date
         
     | 
| 
      
 59 
     | 
    
         
            +
                    attribute? :ended_on, Types::DateOrNil
         
     | 
| 
      
 60 
     | 
    
         
            +
             
     | 
| 
      
 61 
     | 
    
         
            +
                    contract_object ExperienceContract
         
     | 
| 
      
 62 
     | 
    
         
            +
             
     | 
| 
      
 63 
     | 
    
         
            +
                    schema schema.strict
         
     | 
| 
      
 64 
     | 
    
         
            +
             
     | 
| 
      
 65 
     | 
    
         
            +
                    def self.new(input)
         
     | 
| 
      
 66 
     | 
    
         
            +
                      validation = self.contract_object.new.call(input)
         
     | 
| 
      
 67 
     | 
    
         
            +
                      raise ArgumentError, validation.errors.to_h unless validation.success?
         
     | 
| 
      
 68 
     | 
    
         
            +
                      super(validation.to_h)
         
     | 
| 
      
 69 
     | 
    
         
            +
                    end
         
     | 
| 
      
 70 
     | 
    
         
            +
                  end
         
     | 
| 
      
 71 
     | 
    
         
            +
                end
         
     | 
| 
      
 72 
     | 
    
         
            +
              end
         
     | 
| 
      
 73 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,57 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # frozen_string_literal: true
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            require "dry-validation"
         
     | 
| 
      
 4 
     | 
    
         
            +
            require "roseflow/proxycurl/object"
         
     | 
| 
      
 5 
     | 
    
         
            +
            require "roseflow/linkedin/person"
         
     | 
| 
      
 6 
     | 
    
         
            +
            require "roseflow/types"
         
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
      
 8 
     | 
    
         
            +
            module Roseflow
         
     | 
| 
      
 9 
     | 
    
         
            +
              module LinkedIn
         
     | 
| 
      
 10 
     | 
    
         
            +
                class Person
         
     | 
| 
      
 11 
     | 
    
         
            +
                  class LookupQuery < Proxycurl::ProxycurlObject
         
     | 
| 
      
 12 
     | 
    
         
            +
                    class LookupQueryContract < Dry::Validation::Contract
         
     | 
| 
      
 13 
     | 
    
         
            +
                      params do
         
     | 
| 
      
 14 
     | 
    
         
            +
                        required(:domain).filled(:string)
         
     | 
| 
      
 15 
     | 
    
         
            +
                        required(:first_name).filled(:string)
         
     | 
| 
      
 16 
     | 
    
         
            +
                        optional(:last_name).filled(:string)
         
     | 
| 
      
 17 
     | 
    
         
            +
                        optional(:title).filled(:string)
         
     | 
| 
      
 18 
     | 
    
         
            +
                        optional(:location).filled(:string)
         
     | 
| 
      
 19 
     | 
    
         
            +
                        optional(:enrich).filled(:bool)
         
     | 
| 
      
 20 
     | 
    
         
            +
                      end
         
     | 
| 
      
 21 
     | 
    
         
            +
                    end
         
     | 
| 
      
 22 
     | 
    
         
            +
             
     | 
| 
      
 23 
     | 
    
         
            +
                    contract_object LookupQueryContract
         
     | 
| 
      
 24 
     | 
    
         
            +
             
     | 
| 
      
 25 
     | 
    
         
            +
                    schema schema.strict
         
     | 
| 
      
 26 
     | 
    
         
            +
             
     | 
| 
      
 27 
     | 
    
         
            +
                    attribute :domain, Types::String
         
     | 
| 
      
 28 
     | 
    
         
            +
                    attribute :first_name, Types::String
         
     | 
| 
      
 29 
     | 
    
         
            +
                    attribute? :last_name, Types::String
         
     | 
| 
      
 30 
     | 
    
         
            +
                    attribute? :title, Types::String
         
     | 
| 
      
 31 
     | 
    
         
            +
                    attribute? :location, Types::String
         
     | 
| 
      
 32 
     | 
    
         
            +
                    attribute? :enrich, Types::Bool.default(false)
         
     | 
| 
      
 33 
     | 
    
         
            +
             
     | 
| 
      
 34 
     | 
    
         
            +
                    def self.new(input)
         
     | 
| 
      
 35 
     | 
    
         
            +
                      validation = self.contract_object.new.call(input)
         
     | 
| 
      
 36 
     | 
    
         
            +
                      raise ArgumentError, validation.errors.to_h.inspect unless validation.success?
         
     | 
| 
      
 37 
     | 
    
         
            +
                      super(input)
         
     | 
| 
      
 38 
     | 
    
         
            +
                    end
         
     | 
| 
      
 39 
     | 
    
         
            +
             
     | 
| 
      
 40 
     | 
    
         
            +
                    def to_request_params
         
     | 
| 
      
 41 
     | 
    
         
            +
                      params = {
         
     | 
| 
      
 42 
     | 
    
         
            +
                        company_domain: domain,
         
     | 
| 
      
 43 
     | 
    
         
            +
                        first_name: first_name,
         
     | 
| 
      
 44 
     | 
    
         
            +
                        last_name: last_name,
         
     | 
| 
      
 45 
     | 
    
         
            +
                        title: title,
         
     | 
| 
      
 46 
     | 
    
         
            +
                        location: location,
         
     | 
| 
      
 47 
     | 
    
         
            +
                        enrich_profile: enrich == true ? "enrich" : "skip",
         
     | 
| 
      
 48 
     | 
    
         
            +
                      }
         
     | 
| 
      
 49 
     | 
    
         
            +
             
     | 
| 
      
 50 
     | 
    
         
            +
                      params.each_pair do |key, value|
         
     | 
| 
      
 51 
     | 
    
         
            +
                        params.delete(key) unless value
         
     | 
| 
      
 52 
     | 
    
         
            +
                      end
         
     | 
| 
      
 53 
     | 
    
         
            +
                    end
         
     | 
| 
      
 54 
     | 
    
         
            +
                  end
         
     | 
| 
      
 55 
     | 
    
         
            +
                end
         
     | 
| 
      
 56 
     | 
    
         
            +
              end
         
     | 
| 
      
 57 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,69 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # frozen_string_literal: true
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            require "dry-transformer"
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
            require "roseflow/linkedin/person/experience"
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
            module Roseflow
         
     | 
| 
      
 8 
     | 
    
         
            +
              module LinkedIn
         
     | 
| 
      
 9 
     | 
    
         
            +
                class Person
         
     | 
| 
      
 10 
     | 
    
         
            +
                  class Object < Dry::Struct
         
     | 
| 
      
 11 
     | 
    
         
            +
                    defines :contract_object
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
                    class PersonMapper < Dry::Transformer::Pipe
         
     | 
| 
      
 14 
     | 
    
         
            +
                      import Dry::Transformer::HashTransformations
         
     | 
| 
      
 15 
     | 
    
         
            +
             
     | 
| 
      
 16 
     | 
    
         
            +
                      define! do
         
     | 
| 
      
 17 
     | 
    
         
            +
                        deep_symbolize_keys
         
     | 
| 
      
 18 
     | 
    
         
            +
                        rename_keys public_identifier: :id, profile_pic_url: :profile_picture_url, follower_count: :followers
         
     | 
| 
      
 19 
     | 
    
         
            +
                      end
         
     | 
| 
      
 20 
     | 
    
         
            +
                    end
         
     | 
| 
      
 21 
     | 
    
         
            +
             
     | 
| 
      
 22 
     | 
    
         
            +
                    class PersonContract < Dry::Validation::Contract
         
     | 
| 
      
 23 
     | 
    
         
            +
                      params do
         
     | 
| 
      
 24 
     | 
    
         
            +
                        required(:id).filled(:string)
         
     | 
| 
      
 25 
     | 
    
         
            +
                        required(:first_name).filled(:string)
         
     | 
| 
      
 26 
     | 
    
         
            +
                        required(:last_name).filled(:string)
         
     | 
| 
      
 27 
     | 
    
         
            +
                        required(:full_name).filled(:string)
         
     | 
| 
      
 28 
     | 
    
         
            +
                        required(:profile_url).filled(:string)
         
     | 
| 
      
 29 
     | 
    
         
            +
                        required(:profile_picture_url).filled(:string)
         
     | 
| 
      
 30 
     | 
    
         
            +
                        required(:headline).filled(:string)
         
     | 
| 
      
 31 
     | 
    
         
            +
                        optional(:followers)
         
     | 
| 
      
 32 
     | 
    
         
            +
                        optional(:connections)
         
     | 
| 
      
 33 
     | 
    
         
            +
                        optional(:occupation)
         
     | 
| 
      
 34 
     | 
    
         
            +
                        optional(:experiences).filled(:array)
         
     | 
| 
      
 35 
     | 
    
         
            +
                      end
         
     | 
| 
      
 36 
     | 
    
         
            +
             
     | 
| 
      
 37 
     | 
    
         
            +
                      def call(input)
         
     | 
| 
      
 38 
     | 
    
         
            +
                        transformed = PersonMapper.new.call(input)
         
     | 
| 
      
 39 
     | 
    
         
            +
                        super(transformed)
         
     | 
| 
      
 40 
     | 
    
         
            +
                      end
         
     | 
| 
      
 41 
     | 
    
         
            +
                    end
         
     | 
| 
      
 42 
     | 
    
         
            +
             
     | 
| 
      
 43 
     | 
    
         
            +
                    attribute :id, Types::String
         
     | 
| 
      
 44 
     | 
    
         
            +
                    attribute :first_name, Types::String
         
     | 
| 
      
 45 
     | 
    
         
            +
                    attribute :last_name, Types::String
         
     | 
| 
      
 46 
     | 
    
         
            +
                    attribute :full_name, Types::String
         
     | 
| 
      
 47 
     | 
    
         
            +
                    attribute :profile_url, Types::String
         
     | 
| 
      
 48 
     | 
    
         
            +
                    attribute :profile_picture_url, Types::String
         
     | 
| 
      
 49 
     | 
    
         
            +
                    attribute :headline, Types::String
         
     | 
| 
      
 50 
     | 
    
         
            +
                    attribute :followers, Types::Integer.optional
         
     | 
| 
      
 51 
     | 
    
         
            +
                    attribute :connections, Types::Integer.optional
         
     | 
| 
      
 52 
     | 
    
         
            +
                    attribute :occupation, Types::String
         
     | 
| 
      
 53 
     | 
    
         
            +
                    attribute :experiences, Types::Array.of(Experience).optional
         
     | 
| 
      
 54 
     | 
    
         
            +
             
     | 
| 
      
 55 
     | 
    
         
            +
                    contract_object PersonContract
         
     | 
| 
      
 56 
     | 
    
         
            +
             
     | 
| 
      
 57 
     | 
    
         
            +
                    schema schema.strict
         
     | 
| 
      
 58 
     | 
    
         
            +
             
     | 
| 
      
 59 
     | 
    
         
            +
                    def self.new(input)
         
     | 
| 
      
 60 
     | 
    
         
            +
                      experiences = input.delete("experiences")
         
     | 
| 
      
 61 
     | 
    
         
            +
                      input[:experiences] = experiences.map { |experience| Experience.new(experience) } if experiences
         
     | 
| 
      
 62 
     | 
    
         
            +
                      validation = self.contract_object.new.call(input)
         
     | 
| 
      
 63 
     | 
    
         
            +
                      raise ArgumentError, validation.errors.to_h.inspect unless validation.success?
         
     | 
| 
      
 64 
     | 
    
         
            +
                      super(validation.to_h)
         
     | 
| 
      
 65 
     | 
    
         
            +
                    end
         
     | 
| 
      
 66 
     | 
    
         
            +
                  end
         
     | 
| 
      
 67 
     | 
    
         
            +
                end
         
     | 
| 
      
 68 
     | 
    
         
            +
              end
         
     | 
| 
      
 69 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,53 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # frozen_string_literal: true
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            require "dry-validation"
         
     | 
| 
      
 4 
     | 
    
         
            +
            require "roseflow/proxycurl/object"
         
     | 
| 
      
 5 
     | 
    
         
            +
            require "roseflow/linkedin/person"
         
     | 
| 
      
 6 
     | 
    
         
            +
            require "roseflow/types"
         
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
      
 8 
     | 
    
         
            +
            module Roseflow
         
     | 
| 
      
 9 
     | 
    
         
            +
              module LinkedIn
         
     | 
| 
      
 10 
     | 
    
         
            +
                class Person
         
     | 
| 
      
 11 
     | 
    
         
            +
                end
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
                class Person::ProfileQuery < Proxycurl::ProxycurlObject
         
     | 
| 
      
 14 
     | 
    
         
            +
                  class ProfileQueryContract < Dry::Validation::Contract
         
     | 
| 
      
 15 
     | 
    
         
            +
                    params do
         
     | 
| 
      
 16 
     | 
    
         
            +
                      required(:url).filled(:string)
         
     | 
| 
      
 17 
     | 
    
         
            +
                    end
         
     | 
| 
      
 18 
     | 
    
         
            +
             
     | 
| 
      
 19 
     | 
    
         
            +
                    rule (:url) do
         
     | 
| 
      
 20 
     | 
    
         
            +
                      unless URI.parse(value).is_a?(URI::HTTP)
         
     | 
| 
      
 21 
     | 
    
         
            +
                        key.failure("must be a valid URL")
         
     | 
| 
      
 22 
     | 
    
         
            +
                      end
         
     | 
| 
      
 23 
     | 
    
         
            +
             
     | 
| 
      
 24 
     | 
    
         
            +
                      unless value.match?(/linkedin\.com\/in\/\w+/)
         
     | 
| 
      
 25 
     | 
    
         
            +
                        key.failure("must be a valid LinkedIn profile URL")
         
     | 
| 
      
 26 
     | 
    
         
            +
                      end
         
     | 
| 
      
 27 
     | 
    
         
            +
                    end
         
     | 
| 
      
 28 
     | 
    
         
            +
                  end
         
     | 
| 
      
 29 
     | 
    
         
            +
             
     | 
| 
      
 30 
     | 
    
         
            +
                  contract_object ProfileQueryContract
         
     | 
| 
      
 31 
     | 
    
         
            +
             
     | 
| 
      
 32 
     | 
    
         
            +
                  schema schema.strict
         
     | 
| 
      
 33 
     | 
    
         
            +
             
     | 
| 
      
 34 
     | 
    
         
            +
                  attribute :url, Types::String
         
     | 
| 
      
 35 
     | 
    
         
            +
                  attribute :fallback_to_cache, Types::String.default("on-error")
         
     | 
| 
      
 36 
     | 
    
         
            +
                  attribute :use_cache, Types::String.default("if-present")
         
     | 
| 
      
 37 
     | 
    
         
            +
                  attribute :skills, Types::String.default("exclude")
         
     | 
| 
      
 38 
     | 
    
         
            +
                  attribute :inferred_salary, Types::String.default("exclude")
         
     | 
| 
      
 39 
     | 
    
         
            +
                  attribute :personal_email, Types::String.default("exclude")
         
     | 
| 
      
 40 
     | 
    
         
            +
                  attribute :personal_contact_number, Types::String.default("exclude")
         
     | 
| 
      
 41 
     | 
    
         
            +
                  attribute :twitter_profile_id, Types::String.default("exclude")
         
     | 
| 
      
 42 
     | 
    
         
            +
                  attribute :facebook_profile_id, Types::String.default("exclude")
         
     | 
| 
      
 43 
     | 
    
         
            +
                  attribute :github_profile_id, Types::String.default("exclude")
         
     | 
| 
      
 44 
     | 
    
         
            +
                  attribute :extra, Types::String.default("exclude")
         
     | 
| 
      
 45 
     | 
    
         
            +
             
     | 
| 
      
 46 
     | 
    
         
            +
                  def self.new(input)
         
     | 
| 
      
 47 
     | 
    
         
            +
                    validation = self.contract_object.new.call(input)
         
     | 
| 
      
 48 
     | 
    
         
            +
                    raise ArgumentError, validation.errors.to_h.inspect unless validation.success?
         
     | 
| 
      
 49 
     | 
    
         
            +
                    super(input)
         
     | 
| 
      
 50 
     | 
    
         
            +
                  end
         
     | 
| 
      
 51 
     | 
    
         
            +
                end
         
     | 
| 
      
 52 
     | 
    
         
            +
              end
         
     | 
| 
      
 53 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,48 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # frozen_string_literal: true
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            require "dry-validation"
         
     | 
| 
      
 4 
     | 
    
         
            +
            require "roseflow/proxycurl/object"
         
     | 
| 
      
 5 
     | 
    
         
            +
            require "roseflow/linkedin/person"
         
     | 
| 
      
 6 
     | 
    
         
            +
            require "roseflow/types"
         
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
      
 8 
     | 
    
         
            +
            module Roseflow
         
     | 
| 
      
 9 
     | 
    
         
            +
              module LinkedIn
         
     | 
| 
      
 10 
     | 
    
         
            +
                class Person
         
     | 
| 
      
 11 
     | 
    
         
            +
                  class RoleQuery < Proxycurl::ProxycurlObject
         
     | 
| 
      
 12 
     | 
    
         
            +
                    class RoleQueryContract < Dry::Validation::Contract
         
     | 
| 
      
 13 
     | 
    
         
            +
                      params do
         
     | 
| 
      
 14 
     | 
    
         
            +
                        required(:role).filled(:string)
         
     | 
| 
      
 15 
     | 
    
         
            +
                        required(:company_name).filled(:string)
         
     | 
| 
      
 16 
     | 
    
         
            +
                        optional(:enrich).filled(:bool)
         
     | 
| 
      
 17 
     | 
    
         
            +
                      end
         
     | 
| 
      
 18 
     | 
    
         
            +
                    end
         
     | 
| 
      
 19 
     | 
    
         
            +
             
     | 
| 
      
 20 
     | 
    
         
            +
                    contract_object RoleQueryContract
         
     | 
| 
      
 21 
     | 
    
         
            +
             
     | 
| 
      
 22 
     | 
    
         
            +
                    schema schema.strict
         
     | 
| 
      
 23 
     | 
    
         
            +
             
     | 
| 
      
 24 
     | 
    
         
            +
                    attribute :role, Types::String
         
     | 
| 
      
 25 
     | 
    
         
            +
                    attribute :company_name, Types::String
         
     | 
| 
      
 26 
     | 
    
         
            +
                    attribute? :enrich, Types::Bool.default(false)
         
     | 
| 
      
 27 
     | 
    
         
            +
             
     | 
| 
      
 28 
     | 
    
         
            +
                    def self.new(input)
         
     | 
| 
      
 29 
     | 
    
         
            +
                      validation = self.contract_object.new.call(input)
         
     | 
| 
      
 30 
     | 
    
         
            +
                      raise ArgumentError, validation.errors.to_h.inspect unless validation.success?
         
     | 
| 
      
 31 
     | 
    
         
            +
                      super(input)
         
     | 
| 
      
 32 
     | 
    
         
            +
                    end
         
     | 
| 
      
 33 
     | 
    
         
            +
             
     | 
| 
      
 34 
     | 
    
         
            +
                    def to_request_params
         
     | 
| 
      
 35 
     | 
    
         
            +
                      params = {
         
     | 
| 
      
 36 
     | 
    
         
            +
                        company_name: company_name,
         
     | 
| 
      
 37 
     | 
    
         
            +
                        role: role,
         
     | 
| 
      
 38 
     | 
    
         
            +
                        enrich_profile: enrich == true ? "enrich" : "skip",
         
     | 
| 
      
 39 
     | 
    
         
            +
                      }
         
     | 
| 
      
 40 
     | 
    
         
            +
             
     | 
| 
      
 41 
     | 
    
         
            +
                      params.each_pair do |key, value|
         
     | 
| 
      
 42 
     | 
    
         
            +
                        params.delete(key) unless value
         
     | 
| 
      
 43 
     | 
    
         
            +
                      end
         
     | 
| 
      
 44 
     | 
    
         
            +
                    end
         
     | 
| 
      
 45 
     | 
    
         
            +
                  end
         
     | 
| 
      
 46 
     | 
    
         
            +
                end
         
     | 
| 
      
 47 
     | 
    
         
            +
              end
         
     | 
| 
      
 48 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,50 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # frozen_string_literal: true
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            require "roseflow/linkedin/person/lookup_query"
         
     | 
| 
      
 4 
     | 
    
         
            +
            require "roseflow/linkedin/person/profile_query"
         
     | 
| 
      
 5 
     | 
    
         
            +
            require "roseflow/linkedin/person/role_query"
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
            module Roseflow
         
     | 
| 
      
 8 
     | 
    
         
            +
              module LinkedIn
         
     | 
| 
      
 9 
     | 
    
         
            +
                class Person
         
     | 
| 
      
 10 
     | 
    
         
            +
                  def initialize(connection)
         
     | 
| 
      
 11 
     | 
    
         
            +
                    @connection = connection
         
     | 
| 
      
 12 
     | 
    
         
            +
                  end
         
     | 
| 
      
 13 
     | 
    
         
            +
             
     | 
| 
      
 14 
     | 
    
         
            +
                  def find(url, **options)
         
     | 
| 
      
 15 
     | 
    
         
            +
                    query = ProfileQuery.new(url: url, **options)
         
     | 
| 
      
 16 
     | 
    
         
            +
                    response = @connection.get("v2/linkedin", query.to_h)
         
     | 
| 
      
 17 
     | 
    
         
            +
                    return Person::Object.new(JSON.parse(response.body).merge(profile_url: url)) if person_found?(response)
         
     | 
| 
      
 18 
     | 
    
         
            +
                    return nil if person_not_found?(response)
         
     | 
| 
      
 19 
     | 
    
         
            +
                  end
         
     | 
| 
      
 20 
     | 
    
         
            +
             
     | 
| 
      
 21 
     | 
    
         
            +
                  def lookup(query)
         
     | 
| 
      
 22 
     | 
    
         
            +
                    query = LookupQuery.new(query)
         
     | 
| 
      
 23 
     | 
    
         
            +
                    response = @connection.get("linkedin/profile/resolve", query.to_request_params)
         
     | 
| 
      
 24 
     | 
    
         
            +
                    return JSON.parse(response.body).dig("url") if person_found?(response)
         
     | 
| 
      
 25 
     | 
    
         
            +
                    return nil if person_not_found?(response)
         
     | 
| 
      
 26 
     | 
    
         
            +
                  end
         
     | 
| 
      
 27 
     | 
    
         
            +
             
     | 
| 
      
 28 
     | 
    
         
            +
                  def role(query)
         
     | 
| 
      
 29 
     | 
    
         
            +
                    query = RoleQuery.new(query)
         
     | 
| 
      
 30 
     | 
    
         
            +
                    response = @connection.get("find/company/role/", query.to_request_params)
         
     | 
| 
      
 31 
     | 
    
         
            +
                    if person_found?(response)
         
     | 
| 
      
 32 
     | 
    
         
            +
                      url = JSON.parse(response.body).dig("linkedin_profile_url")
         
     | 
| 
      
 33 
     | 
    
         
            +
                      return find(url)
         
     | 
| 
      
 34 
     | 
    
         
            +
                    end
         
     | 
| 
      
 35 
     | 
    
         
            +
             
     | 
| 
      
 36 
     | 
    
         
            +
                    return nil if person_not_found?(response)
         
     | 
| 
      
 37 
     | 
    
         
            +
                  end
         
     | 
| 
      
 38 
     | 
    
         
            +
             
     | 
| 
      
 39 
     | 
    
         
            +
                  private
         
     | 
| 
      
 40 
     | 
    
         
            +
             
     | 
| 
      
 41 
     | 
    
         
            +
                  def person_found?(response)
         
     | 
| 
      
 42 
     | 
    
         
            +
                    response.success? && response.status == 200
         
     | 
| 
      
 43 
     | 
    
         
            +
                  end
         
     | 
| 
      
 44 
     | 
    
         
            +
             
     | 
| 
      
 45 
     | 
    
         
            +
                  def person_not_found?(response)
         
     | 
| 
      
 46 
     | 
    
         
            +
                    response.success? && response.status == 404
         
     | 
| 
      
 47 
     | 
    
         
            +
                  end
         
     | 
| 
      
 48 
     | 
    
         
            +
                end
         
     | 
| 
      
 49 
     | 
    
         
            +
              end
         
     | 
| 
      
 50 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,27 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # frozen_string_literal: true
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            module Roseflow
         
     | 
| 
      
 4 
     | 
    
         
            +
              module Proxycurl
         
     | 
| 
      
 5 
     | 
    
         
            +
                class Client
         
     | 
| 
      
 6 
     | 
    
         
            +
                  def initialize(config = Config.new)
         
     | 
| 
      
 7 
     | 
    
         
            +
                    @config = config
         
     | 
| 
      
 8 
     | 
    
         
            +
                  end
         
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
      
 10 
     | 
    
         
            +
                  private
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
                  def connection
         
     | 
| 
      
 13 
     | 
    
         
            +
                    @connection ||= Faraday.new(
         
     | 
| 
      
 14 
     | 
    
         
            +
                      url: proxycurl_base_url,
         
     | 
| 
      
 15 
     | 
    
         
            +
                    ) do |faraday|
         
     | 
| 
      
 16 
     | 
    
         
            +
                      faraday.request :authorization, :Bearer, -> { config.api_key }
         
     | 
| 
      
 17 
     | 
    
         
            +
                      faraday.request :url_encoded
         
     | 
| 
      
 18 
     | 
    
         
            +
                      faraday.adapter Faraday.default_adapter
         
     | 
| 
      
 19 
     | 
    
         
            +
                    end
         
     | 
| 
      
 20 
     | 
    
         
            +
                  end
         
     | 
| 
      
 21 
     | 
    
         
            +
             
     | 
| 
      
 22 
     | 
    
         
            +
                  def proxycurl_base_url
         
     | 
| 
      
 23 
     | 
    
         
            +
                    @config.base_url || Config::DEFAULT_BASE_URL
         
     | 
| 
      
 24 
     | 
    
         
            +
                  end
         
     | 
| 
      
 25 
     | 
    
         
            +
                end
         
     | 
| 
      
 26 
     | 
    
         
            +
              end
         
     | 
| 
      
 27 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,17 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # frozen_string_literal: true
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            require "anyway_config"
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
            module Roseflow
         
     | 
| 
      
 6 
     | 
    
         
            +
              module Proxycurl
         
     | 
| 
      
 7 
     | 
    
         
            +
                class Config < Anyway::Config
         
     | 
| 
      
 8 
     | 
    
         
            +
                  DEFAULT_BASE_URL = "https://nubela.co/proxycurl/api/"
         
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
      
 10 
     | 
    
         
            +
                  config_name :proxycurl
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
                  attr_config :api_key, :base_url
         
     | 
| 
      
 13 
     | 
    
         
            +
             
     | 
| 
      
 14 
     | 
    
         
            +
                  required :api_key
         
     | 
| 
      
 15 
     | 
    
         
            +
                end
         
     | 
| 
      
 16 
     | 
    
         
            +
              end
         
     | 
| 
      
 17 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,18 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # frozen_string_literal: true
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            module Roseflow
         
     | 
| 
      
 4 
     | 
    
         
            +
              module Proxycurl
         
     | 
| 
      
 5 
     | 
    
         
            +
                def self.gem_version
         
     | 
| 
      
 6 
     | 
    
         
            +
                  Gem::Version.new(VERSION::STRING)
         
     | 
| 
      
 7 
     | 
    
         
            +
                end
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
                module VERSION
         
     | 
| 
      
 10 
     | 
    
         
            +
                  MAJOR = 0
         
     | 
| 
      
 11 
     | 
    
         
            +
                  MINOR = 5
         
     | 
| 
      
 12 
     | 
    
         
            +
                  PATCH = 0
         
     | 
| 
      
 13 
     | 
    
         
            +
                  PRE = nil
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
                  STRING = [MAJOR, MINOR, PATCH, PRE].compact.join(".")
         
     | 
| 
      
 16 
     | 
    
         
            +
                end
         
     | 
| 
      
 17 
     | 
    
         
            +
              end
         
     | 
| 
      
 18 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,49 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # frozen_string_literal: true
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            require_relative "lib/roseflow/proxycurl/version"
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
            Gem::Specification.new do |spec|
         
     | 
| 
      
 6 
     | 
    
         
            +
              spec.name = "roseflow-proxycurl"
         
     | 
| 
      
 7 
     | 
    
         
            +
              spec.version = Roseflow::Proxycurl.gem_version
         
     | 
| 
      
 8 
     | 
    
         
            +
              spec.authors = ["Lauri Jutila"]
         
     | 
| 
      
 9 
     | 
    
         
            +
              spec.email = ["ljuti@roseflow.ai"]
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
              spec.summary = "Proxycurl integration for Roseflow."
         
     | 
| 
      
 12 
     | 
    
         
            +
              spec.description = "Proxycurl integration for Roseflow."
         
     | 
| 
      
 13 
     | 
    
         
            +
              spec.homepage = "https://github.com/roseflow-ai/roseflow-proxycurl"
         
     | 
| 
      
 14 
     | 
    
         
            +
              spec.license = "MIT"
         
     | 
| 
      
 15 
     | 
    
         
            +
              spec.required_ruby_version = ">= 3.2.0"
         
     | 
| 
      
 16 
     | 
    
         
            +
             
     | 
| 
      
 17 
     | 
    
         
            +
              spec.metadata["homepage_uri"] = spec.homepage
         
     | 
| 
      
 18 
     | 
    
         
            +
              spec.metadata["source_code_uri"] = "https://github.com/roseflow-ai/roseflow-proxycurl"
         
     | 
| 
      
 19 
     | 
    
         
            +
              spec.metadata["changelog_uri"] = "https://github.com/roseflow-ai/roseflow-proxycurl/blob/master/CHANGELOG.md"
         
     | 
| 
      
 20 
     | 
    
         
            +
             
     | 
| 
      
 21 
     | 
    
         
            +
              # Specify which files should be added to the gem when it is released.
         
     | 
| 
      
 22 
     | 
    
         
            +
              # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
         
     | 
| 
      
 23 
     | 
    
         
            +
              spec.files = Dir.chdir(__dir__) do
         
     | 
| 
      
 24 
     | 
    
         
            +
                `git ls-files -z`.split("\x0").reject do |f|
         
     | 
| 
      
 25 
     | 
    
         
            +
                  (File.expand_path(f) == __FILE__) || f.start_with?(*%w[bin/ test/ spec/ features/ .git .circleci appveyor])
         
     | 
| 
      
 26 
     | 
    
         
            +
                end
         
     | 
| 
      
 27 
     | 
    
         
            +
              end
         
     | 
| 
      
 28 
     | 
    
         
            +
              spec.bindir = "exe"
         
     | 
| 
      
 29 
     | 
    
         
            +
              spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
         
     | 
| 
      
 30 
     | 
    
         
            +
              spec.require_paths = ["lib"]
         
     | 
| 
      
 31 
     | 
    
         
            +
             
     | 
| 
      
 32 
     | 
    
         
            +
              # Uncomment to register a new dependency of your gem
         
     | 
| 
      
 33 
     | 
    
         
            +
              spec.add_dependency "activesupport", "~> 6.0"
         
     | 
| 
      
 34 
     | 
    
         
            +
              spec.add_dependency "anyway_config", "~> 2.0"
         
     | 
| 
      
 35 
     | 
    
         
            +
              spec.add_dependency "dry-struct", "~> 1.6"
         
     | 
| 
      
 36 
     | 
    
         
            +
              spec.add_dependency "dry-transformer", "~> 1.0"
         
     | 
| 
      
 37 
     | 
    
         
            +
              spec.add_dependency "dry-validation", "~> 1.10"
         
     | 
| 
      
 38 
     | 
    
         
            +
              spec.add_dependency "faraday", "~> 2.0"
         
     | 
| 
      
 39 
     | 
    
         
            +
              spec.add_dependency "faraday-retry", "~> 2.0"
         
     | 
| 
      
 40 
     | 
    
         
            +
             
     | 
| 
      
 41 
     | 
    
         
            +
              spec.add_development_dependency "awesome_print"
         
     | 
| 
      
 42 
     | 
    
         
            +
              spec.add_development_dependency "pry"
         
     | 
| 
      
 43 
     | 
    
         
            +
              spec.add_development_dependency "webmock"
         
     | 
| 
      
 44 
     | 
    
         
            +
              spec.add_development_dependency "vcr"
         
     | 
| 
      
 45 
     | 
    
         
            +
              spec.add_development_dependency "roseflow"
         
     | 
| 
      
 46 
     | 
    
         
            +
             
     | 
| 
      
 47 
     | 
    
         
            +
              # For more information and examples about making a new gem, check out our
         
     | 
| 
      
 48 
     | 
    
         
            +
              # guide at: https://bundler.io/guides/creating_gem.html
         
     | 
| 
      
 49 
     | 
    
         
            +
            end
         
     |