Ruby - multidimensional hash - ruby

How do I make this multidimensional? Each search result entry has multiple attributes :attributes => ['sAMAccountName','givenName','SN','mail']. and there can be many entries in the result. This code is good for creating only one entry with multiple attributes.
def self.Find(attribute, loginID)
conn = Net::LDAP.new :host => SERVER,
:port => PORT,
:base => BASE,
:auth => {
:username => 'admin',
:password => 'admin',
:method => :simple
}
if conn.bind
result = HashWithIndifferentAccess.new
conn.search( :base => LDAPBASE,
:filter => Net::LDAP::Filter.eq( attribute, loginID+"*" ),
:attributes => ['sAMAccountName','givenName','SN','mail'],
:return_result => true
).each do |entries|
entries.each do |attribute, values|
values.each do |value|
result[attribute] = value
end
end
end
result
end
end
The actual response I get from ldap is like this -
puts result.to_s
{
"dn"=>"CN=somename\\, somefirstname,OU=Users,DC=site,DC=com",
"sn"=>"somename",
"givenname"=>"somefirstname",
"samaccountname"=>"someuserid",
"mail"=>"someone#somthing.com"
}
Since the search is has * wildcard to find all matching entries. Ldap will return multiple entries in the format above. similar to this -
{
"dn"=>"CN=somename\\, somefirstname1,OU=Users,DC=site,DC=com",
"sn"=>"somename1",
"givenname"=>"somefirstname1",
"samaccountname"=>"someuserid1",
"mail"=>"someone1#somthing.com"
},
{
"dn"=>"CN=somename\\, somefirstname2,OU=Users,DC=site,DC=com",
"sn"=>"somename2",
"givenname"=>"somefirstname2",
"samaccountname"=>"someuserid2",
"mail"=>"someone2#somthing.com"
},
{
"dn"=>"CN=somename\\, somefirstname3,OU=Users,DC=site,DC=com",
"sn"=>"somename3",
"givenname"=>"somefirstname3",
"samaccountname"=>"someuserid3",
"mail"=>"someone3#somthing.com"
},
A[a=>1,b=>11,c=>111]
B[a=>2,b=>22,c=>222]
C[a=>3,b=>33,c=>333]
D[a=>4,b=>44,c=>444]

I'm not sure that I understood the question.
def self.Find(attribute, loginID)
conn = Net::LDAP.new :host => SERVER,
:port => PORT,
:base => BASE,
:auth => {
:username => 'admin',
:password => 'admin',
:method => :simple
}
if conn.bind
conn.search( :base => LDAPBASE,
:filter => Net::LDAP::Filter.eq( attribute, loginID+"*" ),
:attributes => ['sAMAccountName','givenName','SN','mail'],
:return_result => true
).reduce(Array.new) do |acc, el|
#
# Any modification of the entry must be here
#
acc + [el]
end
end
end
end
I think Array.map is good choice too
My assumption:
conn.search return Array of Hash
the form of result you want:
[
{"uid":"123","displayName":"User 123","mail":"123#example.com"},
{"uid":"456","displayName":"User 456","mail":"456#example.com"},
{"uid":"789","displayName":"User 789","mail":"789#example.com"}
]

Related

how to create a filter of net-ldap for Ruby

I have a working ldap search query
ldapsearch -H ldaps://ldap.google.com -b dc=pangeare,dc=com '(memberOf=cn=pcore_readonly,ou=Groups,dc=pangeare,dc=com)'
I wonder how should I create the corresponding filter in ruby net-ldap:
treebase="dc=pangeare,dc=com"
filter = Net::LDAP::Filter.XXXXXXXXXX
ldap.search(:base => treebase, :filter=> filter, :return_result => true) do |entry|
entry.each do |attr,values|
puts "DN: #{entry.dn}"
Net::LDAP::Filter#eq should be what your looking for
require 'net/ldap'
host = 'ldap.google.com'
port = 636
auth = {
:method => :simple, # or :simple_tls ? (I don't know Google's LDAP)
:username => 'uid=username,dc=xxx,dc=xxx',
:password => 'password'
}
ldap = Net::LDAP.new( :host => host, :port => port, :auth => auth)
base = 'dc=pangeare,dc=com'
filter = Net::LDAP::Filter.eq('memberOf','cn=pcore_readonly,ou=Groups,dc=pangeare,dc=com')
ldap.search(:base => base, :filter => filter) do |entry|
p entry
end
Or you can just use Net::LDAP::Filter#construct:
filter = Net::LDAP::Filter.construct('(memberOf=cn=pcore_readonly,ou=Groups,dc=pangeare,dc=com)')

Oauth2 error with MapMyFitness API

I'm trying to use the MapMyFitness API (www.mapmyapi.com) with Ruby on Rails 3.2 and the oauth2 gem. First, my app generates the auth_url in "get_auth_url". The browser then navigates to it and a callback is returned to "mapmyfitness_callback" once authenticated. The "mapmyfitness_callback" also gets the list of "workouts" and those are displayed in the browser.
The problem is when the user selects a workout to download. To retrieve the selected workout, I call "get_workout". However, I'm having difficulties getting the appropriate token for the request.
The line below crashes:
workout_data = access_token.get('/v7.0/workout/' + workout_id, :params => { 'field_set' => 'time_series' }, :headers => {'Api-Key' => ENV['MMF_API_KEY'], 'Authorization' => auth_token}).body
with: OAuth2::Error (:
{"oauth1_error":"Malformed authorization header","oauth1_error_code":"OAUTH1:UNKNOWN"}):
app/controllers/telemetry_controller.rb:60:in `get_workout'
The entire controller code:
require 'oauth2'
class TelemetryController < ApplicationController
def get_auth_url
auth_url = mmf_client.auth_code.authorize_url(:redirect_uri => 'http://localhost:3000/telemetry/mapmyfitness_callback')
respond_to do |format|
format.json{ render :json => {:auth_url => auth_url}.to_json }
end
end
def mapmyfitness_callback
# Get user
#code = params[:code]
token = mmf_client.auth_code.get_token(#code, :redirect_uri => 'http://localhost:3000/telemetry/mapmyfitness_callback', :headers => {'Api-Key' => ENV['MMF_API_KEY']})
mmf_user = JSON.parse(token.get('/v7.0/user/self', :headers => {'Api-Key' => ENV['MMF_API_KEY'], 'Authorization' => #code}).body)
mmf_user_id = mmf_user['id']
#auth_token = token.token
# Get workouts
mmf_workouts = JSON.parse(token.get('/v7.0/workout', :params => { 'user' => mmf_user_id }, :headers => {'Api-Key' => ENV['MMF_API_KEY'], 'Authorization' => #code}).body)
#workout_list = Array.new
mmf_workouts['_embedded']['workouts'].each do |workout|
workout_data = {:name => workout['name'],
:id => workout['_links']['self'][0]['id']}
#workout_list.push(workout_data)
end
render :layout => false
end
def get_workout
code = params[:code]
auth_token = params[:auth_token]
access_token = OAuth2::AccessToken.new(mmf_client, auth_token, {
:mode => :query,
:param_name => "oauth2_access_token",
})
puts access_token.to_yaml
# Get workout
workout_id = params[:workout_id]
workout_data = access_token.get('/v7.0/workout/' + workout_id, :params => { 'field_set' => 'time_series' }, :headers => {'Api-Key' => ENV['MMF_API_KEY'], 'Authorization' => auth_token}).body
respond_to do |format|
format.json{ render :json => {:mmf_workout_data => workout_data}.to_json }
end
end
private
def mmf_client
client = OAuth2::Client.new(
ENV['MMF_API_KEY'],
ENV['MMF_SECRET_KEY'],
:authorize_url => "https://www.mapmyfitness.com/v7.0/oauth2/authorize/",
:token_url => "https://oauth2-api.mapmyapi.com/v7.0/oauth2/access_token/",
:site => "https://oauth2-api.mapmyapi.com"
)
end
end
I figured it out. get_workout needs to be like this:
def get_workout
auth_token = params[:auth_token]
token = OAuth2::AccessToken.new(mmf_client, auth_token)
# Get workout
workout_id = params[:workout_id]
workout_data = token.get('/v7.0/workout/' + workout_id, :params => { 'field_set' => 'time_series' }, :headers => {'Api-Key' => ENV['MMF_API_KEY'], 'Authorization' => auth_token}).body
respond_to do |format|
format.json{ render :json => {:mmf_workout_data => workout_data}.to_json }
end
end
The problem with your call to AccessToken.new is the "param_name".
from the docs (http://www.rubydoc.info/github/intridea/oauth2/ebe4be038ec14b349682/OAuth2/AccessToken)
:param_name (String) — default: 'bearer_token' — the parameter name to use for transmission of the Access Token value in :body or :query transmission mode
The default value is "bearer_token", as it should be, but, here, you were changing it to "oauth2_access_token".

Can't get value from nested pair in Omniauth hash.

I'll try to keep this simple, my previous wording was maybe a bit too verbose:
Here is the example Omniauth hash: https://github.com/mkdynamic/omniauth-facebook
I can access and save some values from this but not others. The field is writable, so I know its just my syntax (beginner, sorry!)
{
:provider => 'facebook',
:uid => '1234567',
:info => {
:nickname => 'jbloggs',
:email => 'joe#bloggs.com',
:name => 'Joe Bloggs',
:first_name => 'Joe',
:last_name => 'Bloggs',
:image => 'http://graph.facebook.com/1234567/picture?type=square',
:urls => { :Facebook => 'http://www.facebook.com/jbloggs' },
:location => 'Palo Alto, California',
:verified => true
},
:credentials => {
:token => 'ABCDEF...', # OAuth 2.0 access_token, which you may wish to store
:expires_at => 1321747205, # when the access token expires (it always will)
:expires => true # this will always be true
},
:extra => {
:raw_info => {
:id => '1234567',
:name => 'Joe Bloggs',
:first_name => 'Joe',
:last_name => 'Bloggs',
:link => 'http://www.facebook.com/jbloggs',
:username => 'jbloggs',
:location => { :id => '123456789', :name => 'Palo Alto, California' },
:gender => 'male',
:email => 'joe#bloggs.com',
:timezone => -8,
:locale => 'en_US',
:verified => true,
:updated_time => '2011-11-11T06:21:03+0000'
}
}
}
I can do this to get gender and save it.
location:auth.extra.raw_info["gender"]
Obviously though I dont want to save gender to location. I want to get "Palo Alto" and save it. But this doesn't work.
location.auth.extra.raw_info["location"]["name"]
What am I doing wrong? When I try it in console, I'm able to get the value.
try this
location.auth.extra.raw_info.location.name
or this
location.auth.extra.raw_info[:location][:name]
Yeah, what you suggested was what I was trying...and it turns out we were right but FB had changed how that hash was set up so it wasn't working. Lesson learned: subscribe FB's notifications next time :)

Ruby collection out of order

I have the following:
BB_AREAS = {
:about => {:link => "quem somos", :slug => "quem-somos"},
:expositors => {:link => "expositores",:slug => "expositores"},
:map => {:link => "planta", :slug => "planta"},
:activities => {:link => "atividades",:slug => "atividades"},
:address => {:link => "como chegar",:slug => "como-chegar"},
:support => {:link => "apoio", :slug => "apoio"},
:optin => {:link => "cadastro",:slug => "cadastro"},
:how_expositors => {:link => "como expor",:slug => "como-expor"},
:press => {:link => "imprensa",:slug => "imprensa"},
:contact => {:link => "contato",:slug => "contato"},
}
BB_MENU_AREAS = BB_AREAS.each_with_object({}) { |(k, v), h| h[k] = v[:link]}
BB_MENU_AREAS_SLUG = BB_AREAS.each_with_object({}) { |(k, v), h| h[k] = v[:slug]}
And in the view I have the following:
=render :partial => '/shared/menu', :collection => BB_MENU_AREAS.map {|link, menu| {:link => link, :menu => menu}}, :spacer_template => '/shared/menu_separator'
I want the menu to render in the same order of BB_AREAS, but it is rendered in an arbitrary order.
Hashes are ordered by insertion order in Ruby 1.9+, otherwise they have an internal order.
IMO this data belongs in an array of actual objects, though; roughly:
class Area
attr_accessor :name, :link, :slug
def initialize(name, link, slug)
#name = name
#link = link
#slug = slig
end
end
BB_AREAS = [
Area.new("About", "quem somos", "quem-somos"),
Area.new("Expositors", "expositores", "expositores"),
# etc.
]
If you actually need to extract individual components in order you may.
Ruby Hashs are orderless in Ruby 1.8 and lower. However, in Ruby 1.9 and higher, Hashes are ordered. There is a backward compatible solution though:
BB_AREAS = [
[:about , {:link => "quem somos", :slug => "quem-somos"}],
[:expositors , {:link => "expositores",:slug => "expositores"}],
[:map , {:link => "planta", :slug => "planta"}],
[:activities , {:link => "atividades",:slug => "atividades"}],
[:address , {:link => "como chegar",:slug => "como-chegar"}],
[:support , {:link => "apoio", :slug => "apoio"}],
[:optin , {:link => "cadastro",:slug => "cadastro"}],
[:how_expositors , {:link => "como expor",:slug => "como-expor"}],
[:press , {:link => "imprensa",:slug => "imprensa"}],
[:contact , {:link => "contato",:slug => "contato"}],
]
BB_MENU_AREAS = BB_AREAS.each_with_object({}) { |(k, v), h| h[k] = v[:link]}
BB_MENU_AREAS_SLUG = BB_AREAS.each_with_object({}) { |(k, v), h| h[k] = v[:slug]}
Nothing do change in your view. Additionally, in this data structure, instead of [key], you need to use .assoc(key)[1].

How do I correctly call Magento SOAP API with Ruby Savon for Category Product Links?

I am trying to call the catalog_product_link.list API method using Savon. However, I keep receiving the error Error cannot find parameter.
Here is what I am using, though I have tried several variations of the call and still cannot get it to go through correctly:
client = Savon.client(wsdl: 'http://localhost/index.php/api/soap/?wsdl')
response = client.call(:login){message(username: 'user', apiKey: 'key')}
session = response.body[:login_response][:login_return]
#These all do not work
client.call(:call){message(:session => session, :method => 'catalog_product_link.list', :type => 'up_sell', :productId => '166')}
client.call(:call){message(:session => session, :method => 'catalog_product_link.list', :type => 'up_sell', :product => '166')}
client.call(:call){message(:sessionId => session, :resourcePath => 'catalog_product_link.list', :args => {:type => 'up_sell', :product => '166'})}
client.call(:call){message(:sessionId => session, :resourcePath => 'catalog_product_link.list', :args => {:type => 'up_sell', :productId => '166'})}
client.call(:call){message(:sessionId => session, :resourcePath => 'catalog_product_link.list', :arguments => {:type => 'up_sell', :product => '166'})}
Is there a different way to format to get this to work?
UPDATE: If I try removing the type parameter, it gives the error Given invalid link type, so it appears it does not like something about multiple parameters.
response = client.call(:call){message(:session => session, :method => 'catalog_product_link.list', :product => '166')}
I was able to get this to work using Builder:
class ServiceRequest
def initialize(session, type, product)
#session = session
#type = type
#product = product
end
def to_s
builder = Builder::XmlMarkup.new()
builder.instruct!(:xml, encoding: "UTF-8")
builder.tag!(
"env:Envelope",
"xmlns:env" => "http://schemas.xmlsoap.org/soap/envelope/",
"xmlns:ns1" => "urn:Magento",
"xmlns:ns2" => "http://xml.apache.org/xml-soap",
"xmlns:xsd" => "http://www.w3.org/2001/XMLSchema",
"xmlns:xsi" => "http://www.w3.org/2001/XMLSchema-instance"
) do |envelope|
envelope.tag!("env:Body") do |body|
body.tag!("ns1:call") do |call|
builder.sessionId(#session, "xsi:type" => "xsd:string")
builder.resourcePath("catalog_product_link.list", "xsi:type" => "xsd:string")
builder.args("xsi:type" => "ns2:Map") do |args|
args.item do |item|
item.key("type", "xsi:type" => "xsd:string")
item.value(#type, "xsi:type" => "xsd:string")
end
args.item do |item|
item.key("product", "xsi:type" => "xsd:string")
item.value(#product, "xsi:type" => "xsd:string")
end
end
end
end
end
builder.target!
end
end
client.call(:call, xml: ServiceRequest.new(session, 'up_sell', '166').to_s)
Thanks to #rubiii for the direction.

Resources