xporter_on_demand 0.1.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/.gitignore +9 -0
- data/.travis.yml +5 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +21 -0
- data/README.md +28 -0
- data/Rakefile +10 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/lib/xporter_on_demand/api.rb +32 -0
- data/lib/xporter_on_demand/client.rb +43 -0
- data/lib/xporter_on_demand/endpoint.rb +53 -0
- data/lib/xporter_on_demand/factory.rb +19 -0
- data/lib/xporter_on_demand/result/base.rb +26 -0
- data/lib/xporter_on_demand/result/result_set.rb +82 -0
- data/lib/xporter_on_demand/result/serialiser.rb +57 -0
- data/lib/xporter_on_demand/token.rb +20 -0
- data/lib/xporter_on_demand/utils.rb +68 -0
- data/lib/xporter_on_demand/version.rb +3 -0
- data/lib/xporter_on_demand.rb +22 -0
- data/xporter_on_demand.gemspec +30 -0
- metadata +166 -0
    
        checksums.yaml
    ADDED
    
    | @@ -0,0 +1,7 @@ | |
| 1 | 
            +
            ---
         | 
| 2 | 
            +
            SHA1:
         | 
| 3 | 
            +
              metadata.gz: ceaf91f7c0ce11f34fde81948b9995d0d6ca9897
         | 
| 4 | 
            +
              data.tar.gz: a815f2fa6e86d7fafcb1757e9082c8b6ca5b30cb
         | 
| 5 | 
            +
            SHA512:
         | 
| 6 | 
            +
              metadata.gz: 929d0d0e4609629fca2d12742b789e0f5983187a0b7c6fcd6065c2b996fa4313a98d7240606d2c6dc6012c59df409174840ceb007f6418fbb03d3cdc36ed3e9a
         | 
| 7 | 
            +
              data.tar.gz: de14cee9e7c8b1fc5b606b9e48cb0b57de480e8ec2bcc82398eb6ea914dad412f36d6289df2aa1ec2673887a4fab5b0ae41da46d734241c2303895f8e2465fd9
         | 
    
        data/.gitignore
    ADDED
    
    
    
        data/.travis.yml
    ADDED
    
    
    
        data/Gemfile
    ADDED
    
    
    
        data/LICENSE.txt
    ADDED
    
    | @@ -0,0 +1,21 @@ | |
| 1 | 
            +
            The MIT License (MIT)
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            Copyright (c) 2017 Jordan Green
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            Permission is hereby granted, free of charge, to any person obtaining a copy
         | 
| 6 | 
            +
            of this software and associated documentation files (the "Software"), to deal
         | 
| 7 | 
            +
            in the Software without restriction, including without limitation the rights
         | 
| 8 | 
            +
            to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
         | 
| 9 | 
            +
            copies of the Software, and to permit persons to whom the Software is
         | 
| 10 | 
            +
            furnished to do so, subject to the following conditions:
         | 
| 11 | 
            +
             | 
| 12 | 
            +
            The above copyright notice and this permission notice shall be included in
         | 
| 13 | 
            +
            all copies or substantial portions of the Software.
         | 
| 14 | 
            +
             | 
| 15 | 
            +
            THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
         | 
| 16 | 
            +
            IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
         | 
| 17 | 
            +
            FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
         | 
| 18 | 
            +
            AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
         | 
| 19 | 
            +
            LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
         | 
| 20 | 
            +
            OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
         | 
| 21 | 
            +
            THE SOFTWARE.
         | 
    
        data/README.md
    ADDED
    
    | @@ -0,0 +1,28 @@ | |
| 1 | 
            +
            # A Ruby client for the [XporterOnDemand API](https://xporter.groupcall.com/)
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            ## Installation
         | 
| 4 | 
            +
            ```
         | 
| 5 | 
            +
            gem install xod_client
         | 
| 6 | 
            +
            ```
         | 
| 7 | 
            +
             | 
| 8 | 
            +
            ## Getting started
         | 
| 9 | 
            +
            ```ruby
         | 
| 10 | 
            +
            require 'xporter_on_demand'
         | 
| 11 | 
            +
             | 
| 12 | 
            +
            relying_party = "app.example.com"   # Your relying party
         | 
| 13 | 
            +
            school_estab  = "1234567"           # School establishment number
         | 
| 14 | 
            +
            estab_secret  = "YOUR SECRET HERE"  # Supplied school secret
         | 
| 15 | 
            +
             | 
| 16 | 
            +
            # Retrieve an IDAAS Authentication token
         | 
| 17 | 
            +
            token  = XporterOnDemand::Token.new(school_estab, relying_party, estab_secret).retrieve
         | 
| 18 | 
            +
            # Initialize a client with the token
         | 
| 19 | 
            +
            client = XporterOnDemand::Client.new(token.token)
         | 
| 20 | 
            +
             | 
| 21 | 
            +
            # Craft a query with your desired options & parameters
         | 
| 22 | 
            +
            students_endpoint = XporterOnDemand::Endpoint.create(:students, options: [:include_group_ids, :include_att_stats], parameters: { student_status: 'OnRoll' })
         | 
| 23 | 
            +
             | 
| 24 | 
            +
            # Fetch the first page of results
         | 
| 25 | 
            +
            student_results = client.query(students_endpoint)
         | 
| 26 | 
            +
            # Retrieve all pages
         | 
| 27 | 
            +
            student_results.fetch_all
         | 
| 28 | 
            +
            ```
         | 
    
        data/Rakefile
    ADDED
    
    
    
        data/bin/console
    ADDED
    
    | @@ -0,0 +1,14 @@ | |
| 1 | 
            +
            #!/usr/bin/env ruby
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            require "bundler/setup"
         | 
| 4 | 
            +
            require "xporter_on_demand"
         | 
| 5 | 
            +
             | 
| 6 | 
            +
            # You can add fixtures and/or initialization code here to make experimenting
         | 
| 7 | 
            +
            # with your gem easier. You can also use a different console, if you like.
         | 
| 8 | 
            +
             | 
| 9 | 
            +
            # (If you use this, don't forget to add pry to your Gemfile!)
         | 
| 10 | 
            +
            # require "pry"
         | 
| 11 | 
            +
            # Pry.start
         | 
| 12 | 
            +
             | 
| 13 | 
            +
            require "irb"
         | 
| 14 | 
            +
            IRB.start(__FILE__)
         | 
    
        data/bin/setup
    ADDED
    
    
| @@ -0,0 +1,32 @@ | |
| 1 | 
            +
            module XporterOnDemand
         | 
| 2 | 
            +
              module API
         | 
| 3 | 
            +
                def fetch(endpoint)
         | 
| 4 | 
            +
                  raise ArgumentError, "endpoint must contain 'id' parameter" unless endpoint.id
         | 
| 5 | 
            +
                  create_result_set(get_endpoint(endpoint), endpoint)
         | 
| 6 | 
            +
                end
         | 
| 7 | 
            +
             | 
| 8 | 
            +
                def query(endpoint)
         | 
| 9 | 
            +
                  create_result_set(get_endpoint(endpoint), endpoint)
         | 
| 10 | 
            +
                end
         | 
| 11 | 
            +
             | 
| 12 | 
            +
                def changed_rows(endpoint)
         | 
| 13 | 
            +
                  raise ArgumentError, "endpoint must contain 'changed_rows' parameter" unless endpoint.parameters[:changed_rows]
         | 
| 14 | 
            +
                  create_result_set(get_endpoint(endpoint), endpoint)
         | 
| 15 | 
            +
                end
         | 
| 16 | 
            +
             | 
| 17 | 
            +
                def db_status(resource)
         | 
| 18 | 
            +
                  create_result_set(get(@uri + resource.to_s.camelize + "/?onlyGetDbStatus=true"))
         | 
| 19 | 
            +
                end
         | 
| 20 | 
            +
             | 
| 21 | 
            +
                def get_endpoint(endpoint)
         | 
| 22 | 
            +
                  get(@uri + endpoint.build_query)
         | 
| 23 | 
            +
                end
         | 
| 24 | 
            +
             | 
| 25 | 
            +
                private
         | 
| 26 | 
            +
                  def create_result_set(results, endpoint = nil)
         | 
| 27 | 
            +
                    XporterOnDemand::ResultSet.new(results).tap do |rs|
         | 
| 28 | 
            +
                      rs.attach_stuff(self, endpoint) if endpoint
         | 
| 29 | 
            +
                    end
         | 
| 30 | 
            +
                  end
         | 
| 31 | 
            +
              end
         | 
| 32 | 
            +
            end
         | 
| @@ -0,0 +1,43 @@ | |
| 1 | 
            +
            require 'httpi'
         | 
| 2 | 
            +
            require 'json'
         | 
| 3 | 
            +
            require 'active_support/core_ext/string'
         | 
| 4 | 
            +
            require 'xporter_on_demand/utils'
         | 
| 5 | 
            +
             | 
| 6 | 
            +
            module XporterOnDemand
         | 
| 7 | 
            +
              class Client
         | 
| 8 | 
            +
                include XporterOnDemand::API
         | 
| 9 | 
            +
                include XporterOnDemand::Utils
         | 
| 10 | 
            +
             | 
| 11 | 
            +
                attr_reader :token, :available_scopes, :estab, :uri
         | 
| 12 | 
            +
             | 
| 13 | 
            +
                def initialize(token = nil, args = {})
         | 
| 14 | 
            +
                  @token            = token
         | 
| 15 | 
            +
                  @args             = args
         | 
| 16 | 
            +
             | 
| 17 | 
            +
                  details           = token_details
         | 
| 18 | 
            +
                  @available_scopes = details["Scopes"]
         | 
| 19 | 
            +
                  @estab            = @args.delete(:estab)
         | 
| 20 | 
            +
                  @estab            ||= details["Estab"]
         | 
| 21 | 
            +
             | 
| 22 | 
            +
                  args[:edubase] ? edubase_client : school_client
         | 
| 23 | 
            +
                end
         | 
| 24 | 
            +
             | 
| 25 | 
            +
                %i(token_details scopes queries logs usage).each do |endpoint|
         | 
| 26 | 
            +
                  define_method(endpoint){ get_info(endpoint.to_s.camelcase) }
         | 
| 27 | 
            +
                end
         | 
| 28 | 
            +
             | 
| 29 | 
            +
                def school_client
         | 
| 30 | 
            +
                  @uri = API_PATH + "School/" + estab + "/"
         | 
| 31 | 
            +
                end
         | 
| 32 | 
            +
             | 
| 33 | 
            +
                # This is not finished and probably won't even work.
         | 
| 34 | 
            +
                def edubase_client
         | 
| 35 | 
            +
                  @uri = API_PATH + "RunQuery/?"
         | 
| 36 | 
            +
                end
         | 
| 37 | 
            +
             | 
| 38 | 
            +
                private
         | 
| 39 | 
            +
                  def get_info(endpoint)
         | 
| 40 | 
            +
                    get(url: API_PATH + endpoint)
         | 
| 41 | 
            +
                  end
         | 
| 42 | 
            +
              end
         | 
| 43 | 
            +
            end
         | 
| @@ -0,0 +1,53 @@ | |
| 1 | 
            +
            require 'xporter_on_demand/factory'
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            module XporterOnDemand
         | 
| 4 | 
            +
              class Endpoint
         | 
| 5 | 
            +
                include XporterOnDemand::Utils
         | 
| 6 | 
            +
             | 
| 7 | 
            +
                attr_accessor :endpoint, :options, :parameters, :pagination, :uri, :id
         | 
| 8 | 
            +
             | 
| 9 | 
            +
                def self.create(endpoint, args = {})
         | 
| 10 | 
            +
                  endpoint_name = endpoint.to_s.classify
         | 
| 11 | 
            +
             | 
| 12 | 
            +
                  unless const_defined?(endpoint_name, false)
         | 
| 13 | 
            +
                    class_name = Class.new(self)
         | 
| 14 | 
            +
                    endpoint_class = const_set(endpoint_name, class_name)
         | 
| 15 | 
            +
                  end
         | 
| 16 | 
            +
             | 
| 17 | 
            +
                  const_get(endpoint_name).new(args).tap do |s|
         | 
| 18 | 
            +
                    s.instance_variable_set(:@endpoint, endpoint)
         | 
| 19 | 
            +
                  end
         | 
| 20 | 
            +
                end
         | 
| 21 | 
            +
             | 
| 22 | 
            +
                def initialize(args = {})
         | 
| 23 | 
            +
                  @options    = args.fetch(:options, [])
         | 
| 24 | 
            +
                  @parameters = args.fetch(:parameters, {})
         | 
| 25 | 
            +
             | 
| 26 | 
            +
                  @parameters[:page]      ||= 1
         | 
| 27 | 
            +
                  @parameters[:page_size] ||= 25
         | 
| 28 | 
            +
             | 
| 29 | 
            +
                  @id = args[:id]
         | 
| 30 | 
            +
             | 
| 31 | 
            +
                  # Check that all the options are valid?
         | 
| 32 | 
            +
                  # Check that the parameters are valid?
         | 
| 33 | 
            +
                  # Check the pagination params are valid?
         | 
| 34 | 
            +
                end
         | 
| 35 | 
            +
             | 
| 36 | 
            +
                def build_query
         | 
| 37 | 
            +
                  URI.escape(resource + "?" + build_parameters)
         | 
| 38 | 
            +
                end
         | 
| 39 | 
            +
             | 
| 40 | 
            +
                private
         | 
| 41 | 
            +
                  def resource
         | 
| 42 | 
            +
                    endpoint.to_s.camelize + "/" + (@id || "")
         | 
| 43 | 
            +
                  end
         | 
| 44 | 
            +
             | 
| 45 | 
            +
                  def build_options
         | 
| 46 | 
            +
                    @options.any? ? ["options=" + @options.map{ |o| parameterize(o) }.join(',')] : []
         | 
| 47 | 
            +
                  end
         | 
| 48 | 
            +
             | 
| 49 | 
            +
                  def build_parameters
         | 
| 50 | 
            +
                    (@parameters.map{ |k, v| parameterize(k) + "=" + v.to_s } + build_options).join('&')
         | 
| 51 | 
            +
                  end
         | 
| 52 | 
            +
              end
         | 
| 53 | 
            +
            end
         | 
| @@ -0,0 +1,19 @@ | |
| 1 | 
            +
            module XporterOnDemand
         | 
| 2 | 
            +
              module Factory
         | 
| 3 | 
            +
                def self.create(name, superclass, args = {})
         | 
| 4 | 
            +
                  i_vars    = args.delete(:i_vars) || {}
         | 
| 5 | 
            +
                  namespace = args.delete(:namespace) || superclass
         | 
| 6 | 
            +
             | 
| 7 | 
            +
                  unless namespace.const_defined?(name, false)
         | 
| 8 | 
            +
                    s_class  = Class.new(superclass)
         | 
| 9 | 
            +
                    namespace.const_set(name, s_class)
         | 
| 10 | 
            +
                  end
         | 
| 11 | 
            +
             | 
| 12 | 
            +
                  namespace.const_get(name).new(args).tap do |klass|
         | 
| 13 | 
            +
                    i_vars.each do |i_var, value|
         | 
| 14 | 
            +
                      klass.instance_variable_set(i_var, value)
         | 
| 15 | 
            +
                    end
         | 
| 16 | 
            +
                  end
         | 
| 17 | 
            +
                end
         | 
| 18 | 
            +
              end
         | 
| 19 | 
            +
            end
         | 
| @@ -0,0 +1,26 @@ | |
| 1 | 
            +
            module XporterOnDemand
         | 
| 2 | 
            +
              module Result
         | 
| 3 | 
            +
                class Base
         | 
| 4 | 
            +
                  include XporterOnDemand::Utils
         | 
| 5 | 
            +
             | 
| 6 | 
            +
                  def initialize(args = {})
         | 
| 7 | 
            +
                    result = args.delete(:result)
         | 
| 8 | 
            +
                    assign_attributes(result)
         | 
| 9 | 
            +
                  end
         | 
| 10 | 
            +
             | 
| 11 | 
            +
                  def type
         | 
| 12 | 
            +
                    self.class.name.demodulize
         | 
| 13 | 
            +
                  end
         | 
| 14 | 
            +
             | 
| 15 | 
            +
                  def update(other_result)
         | 
| 16 | 
            +
                    return if other_result.type != type ||\
         | 
| 17 | 
            +
                              other_result.id != id ||\
         | 
| 18 | 
            +
                              other_result.last_updated <= last_updated
         | 
| 19 | 
            +
             | 
| 20 | 
            +
                    attributes.each do |attribute|
         | 
| 21 | 
            +
                      send("#{attribute}=", other_result.send(attribute))
         | 
| 22 | 
            +
                    end
         | 
| 23 | 
            +
                  end
         | 
| 24 | 
            +
                end
         | 
| 25 | 
            +
              end
         | 
| 26 | 
            +
            end
         | 
| @@ -0,0 +1,82 @@ | |
| 1 | 
            +
            module XporterOnDemand
         | 
| 2 | 
            +
              class ResultSet
         | 
| 3 | 
            +
                include Enumerable
         | 
| 4 | 
            +
                include XporterOnDemand::Utils
         | 
| 5 | 
            +
             | 
| 6 | 
            +
                attr_accessor :results, :school, :endpoint
         | 
| 7 | 
            +
             | 
| 8 | 
            +
                def initialize(result_hash)
         | 
| 9 | 
            +
                  results = create_results(result_hash)
         | 
| 10 | 
            +
                  assign_attributes results
         | 
| 11 | 
            +
                end
         | 
| 12 | 
            +
             | 
| 13 | 
            +
                def each
         | 
| 14 | 
            +
                  all.each{ |result| yield result }
         | 
| 15 | 
            +
                end
         | 
| 16 | 
            +
             | 
| 17 | 
            +
                def all
         | 
| 18 | 
            +
                  attributes.reject{ |a| META_KEYS.include? a.camelcase }.flat_map{ |a| send(a) }
         | 
| 19 | 
            +
                end
         | 
| 20 | 
            +
             | 
| 21 | 
            +
                def length
         | 
| 22 | 
            +
                  all.length
         | 
| 23 | 
            +
                end
         | 
| 24 | 
            +
             | 
| 25 | 
            +
                def fetch_all
         | 
| 26 | 
            +
                  return self unless try :pagination
         | 
| 27 | 
            +
                  og_page = pagination.page_number
         | 
| 28 | 
            +
             | 
| 29 | 
            +
                  pagination.page_count.times do |i|
         | 
| 30 | 
            +
                    # Skip if we've already got this page
         | 
| 31 | 
            +
                    next if og_page == i + 1
         | 
| 32 | 
            +
             | 
| 33 | 
            +
                    endpoint.parameters[:page] = i + 1
         | 
| 34 | 
            +
             | 
| 35 | 
            +
                    results_hash = create_results(school.get_endpoint(endpoint))
         | 
| 36 | 
            +
             | 
| 37 | 
            +
                    results_hash.each do |type, results|
         | 
| 38 | 
            +
                      if META_KEYS.include? type.camelcase
         | 
| 39 | 
            +
                        assign_attributes(type => results)
         | 
| 40 | 
            +
                      elsif self.respond_to?(type)
         | 
| 41 | 
            +
                        results.each do |result|
         | 
| 42 | 
            +
                          if result.respond_to?(:id) && existing_result = send(type).find{ |r| r.id == result.id }
         | 
| 43 | 
            +
                            existing_result.update(result)
         | 
| 44 | 
            +
                          else
         | 
| 45 | 
            +
                            send(type).append(result)
         | 
| 46 | 
            +
                          end
         | 
| 47 | 
            +
                        end
         | 
| 48 | 
            +
                      else
         | 
| 49 | 
            +
                        assign_attributes(type => results)
         | 
| 50 | 
            +
                      end
         | 
| 51 | 
            +
                    end
         | 
| 52 | 
            +
                  end
         | 
| 53 | 
            +
                  self
         | 
| 54 | 
            +
                end
         | 
| 55 | 
            +
             | 
| 56 | 
            +
                def attach_stuff(sch, ep)
         | 
| 57 | 
            +
                  self.school = sch
         | 
| 58 | 
            +
                  self.endpoint = ep.dup
         | 
| 59 | 
            +
                end
         | 
| 60 | 
            +
             | 
| 61 | 
            +
                private
         | 
| 62 | 
            +
                  def create_results(result_hash)
         | 
| 63 | 
            +
                    result_hash.map do |namespace, objects|
         | 
| 64 | 
            +
                      type = namespace.underscore.camelize
         | 
| 65 | 
            +
                      result_objects = objects.flat_map{ |object| create_result(type, object) }
         | 
| 66 | 
            +
             | 
| 67 | 
            +
                      [namespace.underscore, result_objects]
         | 
| 68 | 
            +
                    end.to_h
         | 
| 69 | 
            +
                  end
         | 
| 70 | 
            +
             | 
| 71 | 
            +
                  # def create_result(type, object)
         | 
| 72 | 
            +
                  #   Factory.create(
         | 
| 73 | 
            +
                  #     META_KEYS.include?(type) ? type : type.singularize,
         | 
| 74 | 
            +
                  #     XporterOnDemand::Result::Base,
         | 
| 75 | 
            +
                  #     {
         | 
| 76 | 
            +
                  #       namespace: XporterOnDemand::Result,
         | 
| 77 | 
            +
                  #       result: object
         | 
| 78 | 
            +
                  #     }
         | 
| 79 | 
            +
                  #   )
         | 
| 80 | 
            +
                  # end
         | 
| 81 | 
            +
              end
         | 
| 82 | 
            +
            end
         | 
| @@ -0,0 +1,57 @@ | |
| 1 | 
            +
            module XporterOnDemand
         | 
| 2 | 
            +
              module Result
         | 
| 3 | 
            +
                class Serialiser
         | 
| 4 | 
            +
                  FORMAT_REGISTRY = Hash.new{ |h, k| h[k] = { type: :default } }.update(
         | 
| 5 | 
            +
                    active:                 { type: :boolean },
         | 
| 6 | 
            +
                    date:                   { type: :date },
         | 
| 7 | 
            +
                    dateof_birth:           { type: :date },
         | 
| 8 | 
            +
                    date_of_birth:          { type: :date },
         | 
| 9 | 
            +
                    date_time:              { type: :date_time },
         | 
| 10 | 
            +
                    eal:                    { type: :boolean },
         | 
| 11 | 
            +
                    expires:                { type: :date_time },
         | 
| 12 | 
            +
                    fsm_eligible:           { type: :boolean },
         | 
| 13 | 
            +
                    fsm_ever6:              { type: :boolean },
         | 
| 14 | 
            +
                    gifted:                 { type: :boolean },
         | 
| 15 | 
            +
                    in_lea_care:            { type: :boolean },
         | 
| 16 | 
            +
                    last_updated:           { type: :date_time },
         | 
| 17 | 
            +
                    par_resp:               { type: :boolean },
         | 
| 18 | 
            +
                    pupil_premium:          { type: :boolean },
         | 
| 19 | 
            +
                    service_child:          { type: :boolean },
         | 
| 20 | 
            +
                    uniform_allowance:      { type: :boolean }
         | 
| 21 | 
            +
                  )
         | 
| 22 | 
            +
             | 
| 23 | 
            +
                  FORMATTERS = {
         | 
| 24 | 
            +
                    boolean:   ->(v){ !!v.nonzero? },
         | 
| 25 | 
            +
                    csv:       ->(v){ v.split(',') rescue [] },
         | 
| 26 | 
            +
                    date:      ->(v){ Date.parse(v) rescue nil },
         | 
| 27 | 
            +
                    date_time: ->(v){ DateTime.parse(v) rescue nil },
         | 
| 28 | 
            +
                    default:   ->(v){ v },
         | 
| 29 | 
            +
                  }
         | 
| 30 | 
            +
             | 
| 31 | 
            +
                  def self.serialise(attributes)
         | 
| 32 | 
            +
                    object_array = attributes.map do |attribute, value|
         | 
| 33 | 
            +
                      key = attribute.underscore
         | 
| 34 | 
            +
                      format = get_format(key)
         | 
| 35 | 
            +
             | 
| 36 | 
            +
                      [key, FORMATTERS[format].call(value)]
         | 
| 37 | 
            +
                    end
         | 
| 38 | 
            +
                    object_array.to_h
         | 
| 39 | 
            +
                  end
         | 
| 40 | 
            +
             | 
| 41 | 
            +
                  private
         | 
| 42 | 
            +
                    def self.get_format(key)
         | 
| 43 | 
            +
                      if key =~ /_ids\z/
         | 
| 44 | 
            +
                        :csv
         | 
| 45 | 
            +
                      elsif key =~ /(_?date\z|(start|end)\z)/
         | 
| 46 | 
            +
                        :date
         | 
| 47 | 
            +
                      elsif key =~ /_date_time\z/
         | 
| 48 | 
            +
                        :date_time
         | 
| 49 | 
            +
                      elsif key =~ /\Ais_/
         | 
| 50 | 
            +
                        :boolean
         | 
| 51 | 
            +
                      else
         | 
| 52 | 
            +
                        FORMAT_REGISTRY[key.to_sym][:type]
         | 
| 53 | 
            +
                      end
         | 
| 54 | 
            +
                    end
         | 
| 55 | 
            +
                end
         | 
| 56 | 
            +
              end
         | 
| 57 | 
            +
            end
         | 
| @@ -0,0 +1,20 @@ | |
| 1 | 
            +
            module XporterOnDemand
         | 
| 2 | 
            +
              class Token < Client
         | 
| 3 | 
            +
                def initialize(*args)
         | 
| 4 | 
            +
                  @options = args.last.is_a?(Hash) ? args.pop : {}
         | 
| 5 | 
            +
                  @options[:url] ||= STS_PATH
         | 
| 6 | 
            +
             | 
| 7 | 
            +
                  @request_body = {}
         | 
| 8 | 
            +
                  %w(estab relyingParty password thirdpartyid).each_with_index{ |k, i| @request_body[k] = args[i] }
         | 
| 9 | 
            +
             | 
| 10 | 
            +
                  @request_body["thirdpartyid"] ||= "XporterOnDemand"
         | 
| 11 | 
            +
                  raise ArgumentError, "must supply all the sniz" unless @request_body.none?{ |k, v| v.nil? }
         | 
| 12 | 
            +
                end
         | 
| 13 | 
            +
             | 
| 14 | 
            +
                def retrieve
         | 
| 15 | 
            +
                  result = post(@options.merge(body: @request_body.to_json))
         | 
| 16 | 
            +
                  assign_attributes(result)
         | 
| 17 | 
            +
                  self
         | 
| 18 | 
            +
                end
         | 
| 19 | 
            +
              end
         | 
| 20 | 
            +
            end
         | 
| @@ -0,0 +1,68 @@ | |
| 1 | 
            +
            module XporterOnDemand
         | 
| 2 | 
            +
              module Utils
         | 
| 3 | 
            +
                [:get, :post].each do |verb|
         | 
| 4 | 
            +
                  define_method(verb) do |*args|
         | 
| 5 | 
            +
                    request = configure_request(*args)
         | 
| 6 | 
            +
                    response = HTTPI.request(verb, request)
         | 
| 7 | 
            +
                    handle_exceptions(response)
         | 
| 8 | 
            +
                    JSON.parse(response.body.presence || {})
         | 
| 9 | 
            +
                  end
         | 
| 10 | 
            +
                end
         | 
| 11 | 
            +
             | 
| 12 | 
            +
                def configure_request(*args)
         | 
| 13 | 
            +
                  request = HTTPI::Request.new(*args)
         | 
| 14 | 
            +
                  request.headers["Content-Type"] = "application/json"
         | 
| 15 | 
            +
                  request.headers["Authorization"] = "Idaas " + @token if @token
         | 
| 16 | 
            +
                  request
         | 
| 17 | 
            +
                end
         | 
| 18 | 
            +
             | 
| 19 | 
            +
                def handle_exceptions(response)
         | 
| 20 | 
            +
                  response_body = JSON.parse(response.body || {})
         | 
| 21 | 
            +
                  raise response_body["ExceptionMessage"] if response_body["ExceptionMessage"]
         | 
| 22 | 
            +
                end
         | 
| 23 | 
            +
             | 
| 24 | 
            +
                def parameterize(sym)
         | 
| 25 | 
            +
                  sym.to_s.camelize(:lower)
         | 
| 26 | 
            +
                end
         | 
| 27 | 
            +
             | 
| 28 | 
            +
                def assign_attributes(attributes)
         | 
| 29 | 
            +
                  unless instance_variable_defined?("@attributes")
         | 
| 30 | 
            +
                    instance_variable_set("@attributes", [])
         | 
| 31 | 
            +
                    self.class.send(:attr_reader, :attributes)
         | 
| 32 | 
            +
                  end
         | 
| 33 | 
            +
             | 
| 34 | 
            +
                  XporterOnDemand::Result::Serialiser.serialise(attributes).each do |name, value|
         | 
| 35 | 
            +
                    method_name = name.camelize.underscore
         | 
| 36 | 
            +
                    unless META_KEYS.include?(name.camelize)
         | 
| 37 | 
            +
                      method_name = method_name.singularize if value.is_a?(Array) && value.length == 1
         | 
| 38 | 
            +
                    end
         | 
| 39 | 
            +
             | 
| 40 | 
            +
                    instance_variable_set("@#{method_name}", unwrap(value))
         | 
| 41 | 
            +
                    self.class.send(:attr_reader, method_name)
         | 
| 42 | 
            +
             | 
| 43 | 
            +
                    @attributes |= [method_name]
         | 
| 44 | 
            +
                  end
         | 
| 45 | 
            +
                end
         | 
| 46 | 
            +
             | 
| 47 | 
            +
                def create_result(type, object)
         | 
| 48 | 
            +
                  Factory.create(
         | 
| 49 | 
            +
                    META_KEYS.include?(type) ? type : type.singularize,
         | 
| 50 | 
            +
                    XporterOnDemand::Result::Base,
         | 
| 51 | 
            +
                    {
         | 
| 52 | 
            +
                      namespace: XporterOnDemand::Result,
         | 
| 53 | 
            +
                      result: object,
         | 
| 54 | 
            +
                    }
         | 
| 55 | 
            +
                  )
         | 
| 56 | 
            +
                end
         | 
| 57 | 
            +
             | 
| 58 | 
            +
                def unwrap(enum)
         | 
| 59 | 
            +
                  if enum.is_a?(Array)
         | 
| 60 | 
            +
                    enum.length <= 1 ? enum.first || [] : enum
         | 
| 61 | 
            +
                  elsif enum.is_a?(Hash)
         | 
| 62 | 
            +
                    enum.length == 1 ? unwrap(enum[enum.keys.first]) : enum
         | 
| 63 | 
            +
                  else
         | 
| 64 | 
            +
                    enum
         | 
| 65 | 
            +
                  end
         | 
| 66 | 
            +
                end
         | 
| 67 | 
            +
              end
         | 
| 68 | 
            +
            end
         | 
| @@ -0,0 +1,22 @@ | |
| 1 | 
            +
            # require "xporter_on_demand/version"
         | 
| 2 | 
            +
            # require 'xporter_on_demand/client'
         | 
| 3 | 
            +
            # require 'xporter_on_demand/token'
         | 
| 4 | 
            +
            # # require 'xporter_on_demand/utils'
         | 
| 5 | 
            +
            # require 'xporter_on_demand/result/serialiser'
         | 
| 6 | 
            +
             | 
| 7 | 
            +
            require 'xporter_on_demand/api'
         | 
| 8 | 
            +
            require 'xporter_on_demand/client'
         | 
| 9 | 
            +
            require 'xporter_on_demand/endpoint'
         | 
| 10 | 
            +
            require 'xporter_on_demand/factory'
         | 
| 11 | 
            +
            require 'xporter_on_demand/token'
         | 
| 12 | 
            +
            require 'xporter_on_demand/utils'
         | 
| 13 | 
            +
            require 'xporter_on_demand/version'
         | 
| 14 | 
            +
            require 'xporter_on_demand/result/base'
         | 
| 15 | 
            +
            require 'xporter_on_demand/result/result_set'
         | 
| 16 | 
            +
            require 'xporter_on_demand/result/serialiser'
         | 
| 17 | 
            +
             | 
| 18 | 
            +
            module XporterOnDemand
         | 
| 19 | 
            +
              API_PATH  = "https://xporter.groupcall.com/api/v1/"
         | 
| 20 | 
            +
              STS_PATH  = "https://login.groupcall.com/idaas/sts/STS/GetToken"
         | 
| 21 | 
            +
              META_KEYS = %w(ChangedRows DbStatus Meta Pagination)
         | 
| 22 | 
            +
            end
         | 
| @@ -0,0 +1,30 @@ | |
| 1 | 
            +
            # coding: utf-8
         | 
| 2 | 
            +
            lib = File.expand_path("../lib", __FILE__)
         | 
| 3 | 
            +
            $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
         | 
| 4 | 
            +
            require "xporter_on_demand/version"
         | 
| 5 | 
            +
             | 
| 6 | 
            +
            Gem::Specification.new do |spec|
         | 
| 7 | 
            +
              spec.name          = "xporter_on_demand"
         | 
| 8 | 
            +
              spec.version       = XporterOnDemand::VERSION
         | 
| 9 | 
            +
              spec.authors       = ["Jordan Green"]
         | 
| 10 | 
            +
              spec.email         = ["jordan.green@meritec.co.uk"]
         | 
| 11 | 
            +
             | 
| 12 | 
            +
              spec.summary       = %q{Ruby client for the Xporter on Demand API.}
         | 
| 13 | 
            +
              spec.homepage      = "https://github.com/meritec/xporter_on_demand"
         | 
| 14 | 
            +
              spec.license       = "MIT"
         | 
| 15 | 
            +
             | 
| 16 | 
            +
              spec.files         = `git ls-files -z`.split("\x0").reject do |f|
         | 
| 17 | 
            +
                f.match(%r{^(test|spec|features)/})
         | 
| 18 | 
            +
              end
         | 
| 19 | 
            +
              spec.bindir        = "exe"
         | 
| 20 | 
            +
              spec.executables   = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
         | 
| 21 | 
            +
              spec.require_paths = ["lib"]
         | 
| 22 | 
            +
             | 
| 23 | 
            +
              spec.add_runtime_dependency 'httpi', '~> 2.4.2', '>= 2.4.2'
         | 
| 24 | 
            +
              # Gotta use httpclient cos net_http don't like the __foo__ JSON keys
         | 
| 25 | 
            +
              spec.add_runtime_dependency 'httpclient', '~> 2.8.3', '>= 2.8.3'
         | 
| 26 | 
            +
              spec.add_runtime_dependency 'activesupport', '~> 5.0.0.1', '>= 5.0.0.1'
         | 
| 27 | 
            +
              spec.add_development_dependency "bundler", "~> 1.15"
         | 
| 28 | 
            +
              spec.add_development_dependency "rake", "~> 10.0"
         | 
| 29 | 
            +
              spec.add_development_dependency "minitest", "~> 5.0"
         | 
| 30 | 
            +
            end
         | 
    
        metadata
    ADDED
    
    | @@ -0,0 +1,166 @@ | |
| 1 | 
            +
            --- !ruby/object:Gem::Specification
         | 
| 2 | 
            +
            name: xporter_on_demand
         | 
| 3 | 
            +
            version: !ruby/object:Gem::Version
         | 
| 4 | 
            +
              version: 0.1.0
         | 
| 5 | 
            +
            platform: ruby
         | 
| 6 | 
            +
            authors:
         | 
| 7 | 
            +
            - Jordan Green
         | 
| 8 | 
            +
            autorequire: 
         | 
| 9 | 
            +
            bindir: exe
         | 
| 10 | 
            +
            cert_chain: []
         | 
| 11 | 
            +
            date: 2017-12-04 00:00:00.000000000 Z
         | 
| 12 | 
            +
            dependencies:
         | 
| 13 | 
            +
            - !ruby/object:Gem::Dependency
         | 
| 14 | 
            +
              name: httpi
         | 
| 15 | 
            +
              requirement: !ruby/object:Gem::Requirement
         | 
| 16 | 
            +
                requirements:
         | 
| 17 | 
            +
                - - "~>"
         | 
| 18 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 19 | 
            +
                    version: 2.4.2
         | 
| 20 | 
            +
                - - ">="
         | 
| 21 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 22 | 
            +
                    version: 2.4.2
         | 
| 23 | 
            +
              type: :runtime
         | 
| 24 | 
            +
              prerelease: false
         | 
| 25 | 
            +
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 26 | 
            +
                requirements:
         | 
| 27 | 
            +
                - - "~>"
         | 
| 28 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 29 | 
            +
                    version: 2.4.2
         | 
| 30 | 
            +
                - - ">="
         | 
| 31 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 32 | 
            +
                    version: 2.4.2
         | 
| 33 | 
            +
            - !ruby/object:Gem::Dependency
         | 
| 34 | 
            +
              name: httpclient
         | 
| 35 | 
            +
              requirement: !ruby/object:Gem::Requirement
         | 
| 36 | 
            +
                requirements:
         | 
| 37 | 
            +
                - - "~>"
         | 
| 38 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 39 | 
            +
                    version: 2.8.3
         | 
| 40 | 
            +
                - - ">="
         | 
| 41 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 42 | 
            +
                    version: 2.8.3
         | 
| 43 | 
            +
              type: :runtime
         | 
| 44 | 
            +
              prerelease: false
         | 
| 45 | 
            +
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 46 | 
            +
                requirements:
         | 
| 47 | 
            +
                - - "~>"
         | 
| 48 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 49 | 
            +
                    version: 2.8.3
         | 
| 50 | 
            +
                - - ">="
         | 
| 51 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 52 | 
            +
                    version: 2.8.3
         | 
| 53 | 
            +
            - !ruby/object:Gem::Dependency
         | 
| 54 | 
            +
              name: activesupport
         | 
| 55 | 
            +
              requirement: !ruby/object:Gem::Requirement
         | 
| 56 | 
            +
                requirements:
         | 
| 57 | 
            +
                - - "~>"
         | 
| 58 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 59 | 
            +
                    version: 5.0.0.1
         | 
| 60 | 
            +
                - - ">="
         | 
| 61 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 62 | 
            +
                    version: 5.0.0.1
         | 
| 63 | 
            +
              type: :runtime
         | 
| 64 | 
            +
              prerelease: false
         | 
| 65 | 
            +
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 66 | 
            +
                requirements:
         | 
| 67 | 
            +
                - - "~>"
         | 
| 68 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 69 | 
            +
                    version: 5.0.0.1
         | 
| 70 | 
            +
                - - ">="
         | 
| 71 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 72 | 
            +
                    version: 5.0.0.1
         | 
| 73 | 
            +
            - !ruby/object:Gem::Dependency
         | 
| 74 | 
            +
              name: bundler
         | 
| 75 | 
            +
              requirement: !ruby/object:Gem::Requirement
         | 
| 76 | 
            +
                requirements:
         | 
| 77 | 
            +
                - - "~>"
         | 
| 78 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 79 | 
            +
                    version: '1.15'
         | 
| 80 | 
            +
              type: :development
         | 
| 81 | 
            +
              prerelease: false
         | 
| 82 | 
            +
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 83 | 
            +
                requirements:
         | 
| 84 | 
            +
                - - "~>"
         | 
| 85 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 86 | 
            +
                    version: '1.15'
         | 
| 87 | 
            +
            - !ruby/object:Gem::Dependency
         | 
| 88 | 
            +
              name: rake
         | 
| 89 | 
            +
              requirement: !ruby/object:Gem::Requirement
         | 
| 90 | 
            +
                requirements:
         | 
| 91 | 
            +
                - - "~>"
         | 
| 92 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 93 | 
            +
                    version: '10.0'
         | 
| 94 | 
            +
              type: :development
         | 
| 95 | 
            +
              prerelease: false
         | 
| 96 | 
            +
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 97 | 
            +
                requirements:
         | 
| 98 | 
            +
                - - "~>"
         | 
| 99 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 100 | 
            +
                    version: '10.0'
         | 
| 101 | 
            +
            - !ruby/object:Gem::Dependency
         | 
| 102 | 
            +
              name: minitest
         | 
| 103 | 
            +
              requirement: !ruby/object:Gem::Requirement
         | 
| 104 | 
            +
                requirements:
         | 
| 105 | 
            +
                - - "~>"
         | 
| 106 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 107 | 
            +
                    version: '5.0'
         | 
| 108 | 
            +
              type: :development
         | 
| 109 | 
            +
              prerelease: false
         | 
| 110 | 
            +
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 111 | 
            +
                requirements:
         | 
| 112 | 
            +
                - - "~>"
         | 
| 113 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 114 | 
            +
                    version: '5.0'
         | 
| 115 | 
            +
            description: 
         | 
| 116 | 
            +
            email:
         | 
| 117 | 
            +
            - jordan.green@meritec.co.uk
         | 
| 118 | 
            +
            executables: []
         | 
| 119 | 
            +
            extensions: []
         | 
| 120 | 
            +
            extra_rdoc_files: []
         | 
| 121 | 
            +
            files:
         | 
| 122 | 
            +
            - ".gitignore"
         | 
| 123 | 
            +
            - ".travis.yml"
         | 
| 124 | 
            +
            - Gemfile
         | 
| 125 | 
            +
            - LICENSE.txt
         | 
| 126 | 
            +
            - README.md
         | 
| 127 | 
            +
            - Rakefile
         | 
| 128 | 
            +
            - bin/console
         | 
| 129 | 
            +
            - bin/setup
         | 
| 130 | 
            +
            - lib/xporter_on_demand.rb
         | 
| 131 | 
            +
            - lib/xporter_on_demand/api.rb
         | 
| 132 | 
            +
            - lib/xporter_on_demand/client.rb
         | 
| 133 | 
            +
            - lib/xporter_on_demand/endpoint.rb
         | 
| 134 | 
            +
            - lib/xporter_on_demand/factory.rb
         | 
| 135 | 
            +
            - lib/xporter_on_demand/result/base.rb
         | 
| 136 | 
            +
            - lib/xporter_on_demand/result/result_set.rb
         | 
| 137 | 
            +
            - lib/xporter_on_demand/result/serialiser.rb
         | 
| 138 | 
            +
            - lib/xporter_on_demand/token.rb
         | 
| 139 | 
            +
            - lib/xporter_on_demand/utils.rb
         | 
| 140 | 
            +
            - lib/xporter_on_demand/version.rb
         | 
| 141 | 
            +
            - xporter_on_demand.gemspec
         | 
| 142 | 
            +
            homepage: https://github.com/meritec/xporter_on_demand
         | 
| 143 | 
            +
            licenses:
         | 
| 144 | 
            +
            - MIT
         | 
| 145 | 
            +
            metadata: {}
         | 
| 146 | 
            +
            post_install_message: 
         | 
| 147 | 
            +
            rdoc_options: []
         | 
| 148 | 
            +
            require_paths:
         | 
| 149 | 
            +
            - lib
         | 
| 150 | 
            +
            required_ruby_version: !ruby/object:Gem::Requirement
         | 
| 151 | 
            +
              requirements:
         | 
| 152 | 
            +
              - - ">="
         | 
| 153 | 
            +
                - !ruby/object:Gem::Version
         | 
| 154 | 
            +
                  version: '0'
         | 
| 155 | 
            +
            required_rubygems_version: !ruby/object:Gem::Requirement
         | 
| 156 | 
            +
              requirements:
         | 
| 157 | 
            +
              - - ">="
         | 
| 158 | 
            +
                - !ruby/object:Gem::Version
         | 
| 159 | 
            +
                  version: '0'
         | 
| 160 | 
            +
            requirements: []
         | 
| 161 | 
            +
            rubyforge_project: 
         | 
| 162 | 
            +
            rubygems_version: 2.6.12
         | 
| 163 | 
            +
            signing_key: 
         | 
| 164 | 
            +
            specification_version: 4
         | 
| 165 | 
            +
            summary: Ruby client for the Xporter on Demand API.
         | 
| 166 | 
            +
            test_files: []
         |