class PsUtilities::Connection

The PsUtilities, makes it east to work with the Powerschool API @since 0.1.0

Attributes

api_data[R]
auth_info[R]
auth_path[R]
auth_token[R]
base_uri[R]
client[R]
client_id[R]
client_secret[R]
headers[R]
version[R]

Public Class Methods

new( api_info: {}, client_info: {}) click to toggle source

@param api_info: [Hash] - allows override of api settings :base_uri (overrides ENV) and :auth_path (overrides ENV) @param client_info: [Hash] - allows override of client login values :client_id (overrides ENV) & :client_secret (overrides ENV) @note preference is to use environment variables to initialize your server. def initialize( header_info: {}, api_info: {}, client_info: {})

# File lib/ps_utilities/connection.rb, line 40
def initialize( api_info: {}, client_info: {})
  @version       = "v#{PsUtilities::Version::VERSION}"
  @client        = client_defaults.merge(client_info)
  @client_id     = client[:client_id]
  @client_secret = client[:client_secret]
  @api_data      = api_defaults.merge(api_info)
  @base_uri      = api_data[:base_uri]
  @auth_path     = api_data[:auth_endpoint]
  @headers       = header_defaults  # Auth key is added when authenticate is executed
  # @headers['Authorization'] = header_info['Authorization'] if header_info['Authorization']

  raise ArgumentError, "missing client_secret" if client_secret.nil? or client_secret.empty?
  raise ArgumentError, "missing client_id"     if client_id.nil? or client_id.empty?
  raise ArgumentError, "missing auth endpoint" if auth_path.nil? or auth_path.empty?
  raise ArgumentError, "missing base_uri"      if base_uri.nil? or base_uri.empty?
end

Public Instance Methods

run(command: nil, api_path: "", options: {}, params: {}) click to toggle source

this runs the various options: @param command: [Symbol] - commands include direct api calls: :authenticate, :delete, :get, :patch, :post, :put (these require api_path: and options: params) & also pre-built commands - see included methods (they require params:) @param api_path: [String] - this is the api_endpoint (only needed for direct api calls) @param options: [Hash] - this is the data body or the query options (needed for direct api calls) @param params: [Hash] - this is the data needed for using pre-built commands - see the individual command for details @note with no command an authenticatation check is done

# File lib/ps_utilities/connection.rb, line 63
def run(command: nil, api_path: "", options: {}, params: {})
  authenticate                            unless auth_valid?

  case command
  when nil, :authenticate
    authenticate
  when :delete, :get, :patch, :post, :put
    api(command, api_path, options)       unless api_path.empty?
    # TODO: panick if api_path empty
  else
    send(command, params)
  end
  rescue ArgumentError => error
    return {"error_message" => error.message}
end

Private Instance Methods

api(verb, api_path, options={}) click to toggle source

Direct API access @param verb [Symbol] hmtl verbs (:delete, :get, :patch, :post, :put) @param options [Hash] allowed keys are {query: {}, body: {}} - uses :query for gets, and use :body for put and post @return [HTTParty] - useful things to access include: obj.parsed_response (to access returned data) & obj.code to be sure the response was successful “200”

# File lib/ps_utilities/connection.rb, line 89
def api(verb, api_path, options={})
  count   = 0
  retries = 3
  ps_url  = base_uri + api_path
  options = options.merge(headers)
  begin
    HTTParty.send(verb, ps_url, options)
  rescue Net::ReadTimeout, Net::OpenTimeout
    if count < retries
      count += 1
      retry
    else
      { error: "no response (timeout) from URL: #{url}"  }
    end
  end
end
api_defaults() click to toggle source
# File lib/ps_utilities/connection.rb, line 170
def api_defaults
  { base_uri:       ENV['PS_BASE_URI'],
    auth_endpoint:  ENV['PS_AUTH_ENDPOINT'] || '/oauth/access_token',
  }
end
auth_headers(credentials = client) click to toggle source
# File lib/ps_utilities/connection.rb, line 150
def auth_headers(credentials = client)
  { 'ContentType' => 'application/x-www-form-urlencoded;charset=UTF-8',
    'Accept' => 'application/json',
    'Authorization' => 'Basic ' + encode64_client(credentials)
  }
  # with(headers: {'Authorization' => "Basic #{ Base64.strict_encode64('user:pass').chomp}"})
end
auth_valid?(auth = auth_info) click to toggle source
# File lib/ps_utilities/connection.rb, line 140
def auth_valid?(auth = auth_info)
  return false if auth.nil?
  return false if auth.empty?
  return false if auth['access_token'].nil?
  return false if auth['access_token'].empty?
  return false if auth['token_expires'].nil?
  return false if auth['token_expires'] < Time.now
  return true
end
authenticate() click to toggle source

gets API auth token and puts in header HASH for future requests with PS server @return [Hash] - of auth token and time to live from powerschol server {'access_token' => “addsfabe-aads-4444-bbbb-444411ffffbb”,

'token_type' => "Bearer",
'expires_in' => "2504956"
'token_expires' => (Time.now + 3600)}

@note - to enable PS API - In PowerSchool go to System>System Settings>Plugin Management Configuration>your plugin>Data Provider Configuration to manually check plugin expiration date

# File lib/ps_utilities/connection.rb, line 124
def authenticate
  ps_url   = base_uri + auth_path
  response = HTTParty.post( ps_url,
                            { headers: auth_headers,
                              body: 'grant_type=client_credentials'} )
  if response.code.to_s.eql? "200"
    @auth_info = response.parsed_response
    @auth_info['token_expires'] = Time.now + response.parsed_response['expires_in'].to_i
    @headers[:headers].merge!('Authorization' => 'Bearer ' + auth_info['access_token'])
    return auth_info
  else
    # throw error if - error returned -- nothing else will work
    raise AuthError.new("No Auth Token Returned", ps_url, client )
  end
end
authorized_token() click to toggle source
# File lib/ps_utilities/connection.rb, line 81
def authorized_token
  "#{auth_info['access_token']}"
end
client_defaults() click to toggle source
# File lib/ps_utilities/connection.rb, line 164
def client_defaults
  { client_id:      ENV['PS_CLIENT_ID'],
    client_secret:  ENV['PS_CLIENT_SECRET'],
  }
end
encode64_client(credentials = client) click to toggle source
# File lib/ps_utilities/connection.rb, line 158
def encode64_client(credentials = client)
  ps_auth_text = [ credentials[:client_id], credentials[:client_secret] ].join(':')
  Base64.encode64(ps_auth_text).gsub(/\n/, '')
  # Base64.encode64(ps_auth_text).chomp
end
header_defaults() click to toggle source

by this code sends and recieves json data - only overide if building your own data and sending directly via the API methods :get, :put, :post, etc. @note do not override these Settings - if using the pre-build commands

# File lib/ps_utilities/connection.rb, line 108
def header_defaults
  { headers:
    { 'User-Agent' => "PsUtilities - #{version}",
      'Accept' => 'application/json',
      'Content-Type' => 'application/json'
    }
  }
end