Axlsx Gem:Ruby - Creating A dropdown - ruby

wb.add_worksheet(name: 'Report') do |sheet|
sheet.add_data_validation("D25", {
:type => :list,
:formula1 => 'list!D11:D17',
:showDropDown => false,
:showInputMessage => true,
:promptTitle => 'blah blah',
:prompt => 'Please select a valid blah'
})
end
I have no idea how to populate the dropdown. The template shows a caret which tells me that it knows I want this to be a dropdown.

With your formula1 => 'list!D11:D17' you reference on another Worksheet named list.
If you reference only D11:D17 you get the values from the selected area:
require 'axlsx'
Axlsx::Package.new do |p|
wb = p.workbook
wb.add_worksheet(name: 'Report') do |sheet|
sheet.add_data_validation("A10", {
:type => :list,
:formula1 => 'A1:A9',
:showDropDown => false,
:showInputMessage => true,
:promptTitle => 'blah blah',
:prompt => 'Please select a valid blah'
})
end
p.serialize('simple.xlsx')
puts "Wrote simple.xlsx"
end
You can use your list!-reference, but then you must name your sheet list.
Example:
require 'axlsx'
Axlsx::Package.new do |p|
wb = p.workbook
wb.add_worksheet(name: 'list') do |sheet|
1.upto(10){|i| sheet.add_row([i])}
end
wb.add_worksheet(name: 'Report') do |sheet|
sheet.add_data_validation("A1", {
:type => :list,
:formula1 => 'list!A1:A9',
:showDropDown => false,
:showInputMessage => true,
:promptTitle => 'blah blah',
:prompt => 'Please select a valid blah'
})
end
p.serialize('simple.xlsx')
puts "Wrote simple.xlsx"
end

Related

Watir: Passing dynamic selector

Is there a way to pass a dynamic set of options to a textarea element in browser?
options = {
:type => 'textarea',
:selector => ':id',
:field => 'id_of_textarea_field',
:value => 'Joe Salesperson'
}
browser.textarea(options[:selector] => options[:field]).set ''
Error received:
invalid attribute: ":id"
A similar thread is listed here (selecting elements using variables in ruby /watir) but no answer.
options = {
:type => 'textarea',
:selector => :id,
:field => 'id_of_textarea_field',
:value => 'Joe Salesperson'
}
You can just pass the identifier, no need for quotes.
2017-01-03, Updating with a use case. Here is the declaration of the method I'm using and the call. The actual code is much more verbose and contains different validations than what I've pasted here. In the example, you'll notice a simple switch block which sets the appropriate information based on the element type passed (specifically text areas, text fields, and select elements).
def validateInput(options = {})
success = true
begin
case options[:type]
when 'textarea', 'text_field'
Watir::Wait.until{$browser.textarea(options[:selector] => options[:field]).present?}
$browser.textarea(options[:selector] => options[:field]).set options[:value]
when 'select'
$browser.select_list(options[:selector] => options[:field]).select_value options[:value]
else
puts "in else"
end
end
rescue => e
$message.push("Failed to validate '#{options[:field]}' field. #{e}")
success = false
end
return success
end
validateInput({
:type => 'textarea',
:selector => :id,
:field => 'order_approval_comment_name',
:value => 'Joe Salesperson'
})

How to insert video youtube api v3 through service account with ruby

My goal is to let users of my app upload to my youtube account through my server.
I have a developer acount, with youtube data api enabled and a service account client setup and for some reason I am not authorized. I dug through the net to try and figure out why and found many things.
I tried giving permissions in the admin security settings with the projects client id and scope.
Many people were saying that this error is caused because I don't have a youtube account associated with my account. but I have no idea how to associate these.
This is my upload_video.rb script:
require 'rubygems'
require 'google/api_client'
require 'google/api_client/client_secrets'
require 'google/api_client/auth/file_storage'
require 'google/api_client/auth/installed_app'
require 'certified'
DEVELOPER_KEY = "MY-DEVELOPER-KEY"
YOUTUBE_UPLOAD_SCOPE = 'https://www.googleapis.com/auth/youtube.upload'
YOUTUBE_API_SERVICE_NAME = 'youtube'
YOUTUBE_API_VERSION = 'v3'
def get_authenticated_service
puts #PROGRAM_NAME
client = Google::APIClient.new(
:application_name => $PROGRAM_NAME,
:application_version => '1.0.0'
)
key = Google::APIClient::KeyUtils.load_from_pkcs12('oauth2service.p12', 'notasecret')
auth_client = Signet::OAuth2::Client.new(
:token_credential_uri => 'https://accounts.google.com/o/oauth2/token',
:audience => 'https://accounts.google.com/o/oauth2/token',
:scope => YOUTUBE_UPLOAD_SCOPE,
:issuer => 'SERVICE ACCOUNT EMAIL ADDRESS',
:signing_key => key)
auth_client.fetch_access_token!
client.authorization = auth_client
youtube = client.discovered_api(YOUTUBE_API_SERVICE_NAME, YOUTUBE_API_VERSION)
return client, youtube
end
def upload2youtube file, title, description, category_id, keywords, privacy_status
client, youtube = get_authenticated_service
begin
body = {
:snippet => {
:title => title,
:description => description,
:tags => keywords.split(','),
:categoryId => category_id,
},
:status => {
:privacyStatus => privacy_status
}
}
videos_insert_response = client.execute!(
:api_method => youtube.videos.insert,
:body_object => body,
:media => Google::APIClient::UploadIO.new(file, 'video/*'),
:parameters => {
:uploadType => 'resumable',
:part => body.keys.join(',')
}
)
videos_insert_response.resumable_upload.send_all(client)
puts "Video id '#{videos_insert_response.data.id}' was successfully uploaded."
rescue Google::APIClient::TransmissionError => e
puts e.result.body
end
end
This is how I am running it from another script:
require 'google/api_client'
require_relative 'upload_video'
$PROGRAM_NAME = 'MY-PROJECT-NAME'
upload2youtube File.open("somevideo.avi"), "title", "description", 'categoryid', 'tag1,tag2,tag3', 'unlisted'
And this is the result:
{
"error": {
"errors": [
{
"domain": "youtube.header",
"reason": "youtubeSignupRequired",
"message": "Unauthorized",
"locationType": "header",
"location": "Authorization"
}
],
"code": 401,
"message": "Unauthorized"
}
}
What am I doing wrong
#!/usr/bin/ruby
require 'rubygems'
require 'google/api_client'
require 'google/api_client/client_secrets'
require 'google/api_client/auth/file_storage'
require 'google/api_client/auth/installed_app'
require 'certified'
class Youtube_Helper
##client_email = '' #email id from service account (that really long email address...)
##youtube_email = '' #email associated with youtube account
##p12_file_path = '' #path to the file downloaded from the service account (Generate new p12 key button)
##p12_password = '' # password to the file usually 'notasecret'
##api_key = nil # The API key for non authenticated things like lists
YOUTUBE_UPLOAD_SCOPE = 'https://www.googleapis.com/auth/youtube.upload'
YOUTUBE_API_SERVICE_NAME = 'youtube'
YOUTUBE_API_VERSION = 'v3'
##client = nil
##youtube = nil
FILE_POSTFIX = '-oauth2.json'
def initialize(client_email, youtube_email, p12_file_path, p12_password, api_key)
##client_email=client_email
##youtube_email=youtube_email
##p12_file_path=p12_file_path
##p12_password=p12_password
##api_key = api_key
end
def get_authenticated_service
credentialsFile = $0 + FILE_POSTFIX
needtoauthenticate = false
#api_client = Google::APIClient.new(
:application_name => $PROGRAM_NAME,
:application_version => '1.0.0'
)
key = Google::APIClient::KeyUtils.load_from_pkcs12(##p12_file_path, ##p12_password)
#auth_client = Signet::OAuth2::Client.new(
:token_credential_uri => 'https://accounts.google.com/o/oauth2/token',
:audience => 'https://accounts.google.com/o/oauth2/token',
:scope => YOUTUBE_UPLOAD_SCOPE,
:issuer => ##client_email,
:person => ##youtube_email,
:signing_key => key)
if File.exist? credentialsFile
puts 'credential file exists'
puts credentialsFile.to_s
File.open(credentialsFile, 'r') do |file|
credentials = JSON.load(file)
if !credentials.nil?
puts 'get credentials from file'
#auth_client.access_token = credentials['access_token']
#auth_client.client_id = credentials['client_id']
#auth_client.client_secret = credentials['client_secret']
#auth_client.refresh_token = credentials['refresh_token']
#auth_client.expires_in = (Time.parse(credentials['token_expiry']) - Time.now).ceil
#api_client.authorization = #auth_client
if #auth_client.expired?
puts 'authorization expired'
needtoauthenticate = true
end
else
needtoauthenticate = true
end
end
else
needtoauthenticate = true
end
if needtoauthenticate
#auth_client.fetch_access_token!
#api_client.authorization = #auth_client
save(credentialsFile)
end
youtube = #api_client.discovered_api(YOUTUBE_API_SERVICE_NAME, YOUTUBE_API_VERSION)
##client = #api_client
##youtube = youtube
return #api_client, youtube
end
def save(credentialsFile)
File.open(credentialsFile, 'w', 0600) do |file|
json = JSON.dump({
:access_token => #auth_client.access_token,
:client_id => #auth_client.client_id,
:client_secret => #auth_client.client_secret,
:refresh_token => #auth_client.refresh_token,
:token_expiry => #auth_client.expires_at
})
file.write(json)
end
end
def upload2youtube file, title, description, category_id, keywords, privacy_status
puts 'begin'
begin
body = {
:snippet => {
:title => title,
:description => description,
:tags => keywords.split(','),
:categoryId => category_id,
},
:status => {
:privacyStatus => privacy_status
}
}
puts body.keys.join(',')
# Call the API's videos.insert method to create and upload the video.
videos_insert_response = ##client.execute!(
:api_method => ##youtube.videos.insert,
:body_object => body,
:media => Google::APIClient::UploadIO.new(file, 'video/*'),
:parameters => {
'uploadType' => 'multipart',
:part => body.keys.join(',')
}
)
puts'inserted'
puts "'#{videos_insert_response.data.snippet.title}' (video id: #{videos_insert_response.data.id}) was successfully uploaded."
rescue Google::APIClient::TransmissionError => e
puts e.result.body
end
return videos_insert_response.data.id #video id
end
def upload_thumbnail video_id, thumbnail_file, thumbnail_size
puts 'uploading thumbnail'
begin
thumbnail_upload_response = ##client.execute({ :api_method => ##youtube.thumbnails.set,
:parameters => { :videoId => video_id,
'uploadType' => 'media',
:onBehalfOfContentOwner => ##youtube_email},
:media => thumbnail_file,
:headers => { 'Content-Length' => thumbnail_size.to_s,
'Content-Type' => 'image/jpg' }
})
rescue Google::APIClient::TransmissionError => e
puts e.result.body
end
end
def get_video_statistics video_id
client = Google::APIClient.new(:key => ##api_key,
:application_name => $PROGRAM_NAME,
:application_version => '1.0.0',
:authorization => nil)
youtube = client.discovered_api(YOUTUBE_API_SERVICE_NAME, YOUTUBE_API_VERSION)
stats_response = client.execute!( :api_method => youtube.videos.list,
:parameters => {:part => 'statistics', :id => video_id }
)
return stats_response
end
end

Create multi-dimensional array or hash in ruby from JSON

I am using Rhomobile and trying to dynamically build a hash for the id and title of the buttons has of the Alert.show_popup, but am not quite getting it. What I want the end result to be, in effect, is:
Alert.show_popup( {
:message => 'Please Select Appropriate Address:',
:title => 'Get Nearby...',
:icon => :info,
:buttons => [
{'id' => '1', 'title' => 'Address 1'},
{'id' => '2', 'title' => 'Address 2'},
{'id' => '3', 'title' => 'Address 3'},
{'id' => '4', 'title' => 'Address 4'}
],
:callback => url_for(:action => :on_addressidentified_popup)
}
)
I've tried a few methods, but none have worked (build a string that looks like a hash and try_convert, etc.). Here was the latest one I tried which seemed close, but yet still far away:
nearbyaddresses = Rho::JSON.parse(#params['body'])
h = {}
nearbyaddresses.each do |location|
h[intIndex] = {}
h[intIndex][:id] = intIndex.to_s
h[intIndex][:title] = location["Address"].to_s
intIndex = intIndex + 1
end
Alert.show_popup( {
:message => 'Please Select Appropriate Address:',
:title => 'Get Nearby...',
:icon => :info,
:buttons => h,
:callback => url_for(:action => :on_addressidentified_popup)
}
)
Any ruby wizards here that can help me out?
How about
nearby_addresses_list = Rho::JSON.parse(#params['body'])
buttons_list = nearby_addresses_list.collect.each_with_index {|address, i|
{'id' => i, 'title' => address} #not sure if you need to dig into this at all.
}
This should leave buttons_list with this value
[{'id' => 0, 'title' => nearby_addresses_list[0]},
{'id' => 1, 'title' => nearby_addresses_list[1]}
{'id' => 2, 'title' => nearby_addresses_list[2]}
{'id' => 3, 'title' => nearby_addresses_list[3]}]
If you want the id's to start with 1, change the body of the collect statement to {'id' => i+1, 'title' => address}
Then just add buttons_list in as the value for the key :buttons.
Alert.show_popup( {
:message => 'Please Select Appropriate Address:',
:title => 'Get Nearby...',
:icon => :info,
:buttons => buttons_list,
:callback => url_for(:action => :on_addressidentified_popup)
})
If you're seeing weirdness between the desired output you mentioned first and the code you said was close, is it perhaps that you used symbols for the keys in your code (:id), and strings in your desired output ("id") ?
Here's how I addressed the issue. Works like a charm...
intIndex = 0
nearbyaddresses = Rho::JSON.parse(#params['body'])
##nearbyAddresses = nearbyaddresses
button_array = []
nearbyaddresses.each do |location|
opt = {'id' => intIndex.to_s, 'title' => location["Address"] }
button_array << opt
intIndex = intIndex + 1
end
Alert.show_popup( {
:message => 'Please Select Appropriate Address:',
:title => 'Get Nearby...',
:icon => :info,
:buttons => button_array,
:callback => url_for(:action => :getselectedaddress)
}
)

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.

Ruby - multidimensional hash

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"}
]

Resources