I'm currently trying to create a new thread using the Youtube API. Here is the example provided:
def comments_insert(service, properties, part, **params)
resource = create_resource(properties) # See full sample for function
params = params.delete_if { |p, v| v == ''}
response = service.insert_comment(part, resource, params)
end
comments_insert(service,
{'snippet.parent_id': 'pS16m0FttKk',
'snippet.text_original': ''},
'snippet')
I'm essentially using their exact sample code but I'm getting an error that reads: ArgumentError - unknown keyword: snippet:
resource = ChannelbackController.create_resource({'snippet.parentId': '123', 'snippet.textOriginal': message})
response = service.insert_comment('snippet', resource).inspect
I am trying to access Ivona Speech Cloud using Ruby.
I have ported one of the code examples I found to Ruby, but I probably did something wrong at authenticating the request, since I am getting an error.
This is my implementation:
require 'http' # the gem
require 'openssl'
require 'pp'
def sign key, date, region, service, text
k_date = OpenSSL::HMAC.digest('sha256', "AWS4" + key, date)
k_region = OpenSSL::HMAC.digest('sha256', k_date, region)
k_service = OpenSSL::HMAC.digest('sha256', k_region, service)
k_signing = OpenSSL::HMAC.digest('sha256', k_service, "aws4_request")
signature = OpenSSL::HMAC.digest('sha256', k_signing, text)
signature
end
def run
access_key = "GDxxxxxxxxxxxxxxxxRA"
secret_key = "QtxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxlE"
region = 'eu-west-1'
date = '20160808'
service = 'tts'
body = {"Input" => {"Data" => "Hello world"}}
endpoint = "https://#{service}.#{region}.ivonacloud.com/CreateSpeech"
signature = sign secret_key, date, region, service, 'Hello World'
headers = {
"Content-Type" =>"application/json",
"Authorization" => "AWS4-HMAC-SHA256",
"Credential" => "#{access_key}/#{date}/#{region}/#{service}/aws4_request",
"SignedHeaders" => "content-type;host;x-amz-content-sha256;x-amz-date",
"Signature" => "#{signature}",
}
res = HTTP.headers(headers).post(endpoint, json: body)
p res
end
run
This is the error I am getting (line broken for legibility):
#<HTTP::Response/1.1 403 Forbidden
{"X-Amzn-Requestid"=>"18a44dd8-6dc3-11e6-808f-975692d1ee55",
"X-Amzn-Errortype"=>"IncompleteSignatureException:http://internal.amazon.com/coral/com.amazon.coral.service/",
"Content-Type"=>"application/json",
"Content-Length"=>"293",
"Date"=>"Mon, 29 Aug 2016 08:32:18 GMT"}>
Any assistance is appreciated
I would suggest using the AWS4 gem to help with this. I've made similar calls using the following format:
signer = ::AWS4::Signer.new(
access_key: "YOUR_ACCESS_KEY",
secret_key: "YOUR_SECRET_KEY",
region: "us-east-1"
)
aws_headers = {
"Content-Type" => "application/json; charset=utf8",
"Date" => Time.now.iso8601.to_s,
"Host" => "tts.us-east-1.ivonacloud.com"
}
uri = URI(endpoint)
body_params = {"Input":{"Data":"Hello world"}}.to_json
headers = signer.sign("POST", uri, aws_headers, body_params)
res = HTTP.headers(headers).post(endpoint, body: body_params)
I recently moved all my app assets to CDN and everything is working fine. All images are loading in views. But my problem is my images are not loading in emails which I am sending from my application. I have specified my CDN Path in production.rb file also but still not working. When I inspect that image in email, I didn't even getting src for that image.
I am loading my images using image_tag.
Can anyone please help me on this:
Production.rb:
config.action_controller.asset_host = AssetsCdn.new
config.action_mailer.asset_host = AssetsCdn.new
config.action_mailer.default_url_options = { :host => 'localhost', :protocol => 'http' }
config.action_mailer.perform_deliveries = true config.action_mailer.raise_delivery_errors = false config.action_mailer.default :charset => "utf-8"
config.action_mailer.delivery_method = :smtp #:mailhopper
AssetsCdn Class:
require 'zlib'
class AssetsCdn
CSS_CDN = "cdn-css"
CSS_CDN_0 = "cdn-css0"
CSS_CDN_1 = "cdn-css1"
CSS_CDN_2 = "cdn-css2"
JS_CDN = "cdn-js"
JS_CDN_0 = "cdn-js0"
JS_CDN_1 = "cdn-js1"
JS_CDN_2 = "cdn-js2"
ASSETS_CDN = "cdn-assets"
ASSETS_CDN_0 = "cdn-assets0"
ASSETS_CDN_1 = "cdn-assets1"
ASSETS_CDN_2 = "cdn-assets2"
ALL = [CSS_CDN_0, CSS_CDN_1, CSS_CDN_2, JS_CDN_0, JS_CDN_1, JS_CDN_2, ASSETS_CDN_0, ASSETS_CDN_1, ASSETS_CDN_2]
def call(source, request = nil)
cdn_index = Zlib.crc32(source) % 3
if source.ends_with?('.css')
url("#{CSS_CDN}#{cdn_index}", request)
elsif source.ends_with?('.js')
url("#{JS_CDN}#{cdn_index}", request)
else
url("#{ASSETS_CDN}#{cdn_index}", request)
end
end
def url(cdn_subdomain, request = nil)
return "//#{cdn_subdomain}-#{localhost}:3000"
end
end
TIA.
action_mailer.assets_host doesn't accept protocol relative URLs. Instead URLs have to start with with a protocol like http:// or https://.
This makes kind of sense, because usually emails aren't opened in a browser and email clients are not able to inherit the protocol from a patent html document like browsers do.
I need to create Customer using SOAP API in ruby (we want to consume Acumatica api from Ruby on Rails project).
Currently my code using Savon gem looks like this:
client = Savon.client(wsdl: 'wsdl.wsdl') # sample wsdl path
response = client.call :login, message: { name: '', password: '' }
auth_cookies = response.http.cookies
class ServiceRequest
def to_s
builder = Builder::XmlMarkup.new
builder.instruct!(:xml, encoding: 'UTF-8')
# ... problem is here, I don't know how XML request should look like
builder
end
end
p client.call :submit, message: ServiceRequest.new, cookies: auth_cookies
Problem is that, I don't know how XML request should look like.
C# requests looks like this (just piece of sample from docs):
PO302000result = context.PO302000Submit(
new Command[]
{ new Value { Value = "PORE000079", LinkedCommand =
PO302000.DocumentSummary.ReceiptNbr},
new Value { Value = "OK", LinkedCommand =
PO302000.AddPurchaseOrderLine.ServiceCommands.DialogAnswer,
PO302000.Actions.AddPOOrderLine, new Key { Value = "='PORG000084'", FieldName = Commit = true },
PO302000.AddPurchaseOrderLine.OrderNbr.FieldName, ObjectName =
PO302000.AddPurchaseOrderLine.OrderNbr.ObjectName },
new Key { Value = "='CPU00004'", FieldName =
PO302000.AddPurchaseOrderLine.InventoryID.FieldName, ObjectName =
PO302000.AddPurchaseOrderLine.InventoryID.ObjectName },
new Value{ Value = "True", LinkedCommand =
PO302000.AddPurchaseOrderLine.Selected, Commit = true },
PO302000.Actions.AddPOOrderLine2
new Key{ Value = "='CPU00004'", FieldName =
PO302000.DocumentDetails_.InventoryID.FieldName, ObjectName =
PO302000.DocumentDetails_.InventoryID.ObjectName},
new Value{ Value = "1.00", LinkedCommand =
PO302000.DocumentDetails_.ReceiptQty, Commit = true},
// the next part of code is needed if you use Serial items
PO302000.BinLotSerialNumbers.ServiceCommands.NewRow,
new Value { Value = "R01", LinkedCommand =
PO302000.BinLotSerialNumbers.Location },
PO302000.Actions.Save
} );
But I don't know what kind of XML this code produce. It looks like we have Commands array with Values and then action name. But what XML does this kind of code renders? Maybe some C# or Java folks can copy me xml requests samples that are rendered by that kind of code?
Thank you a lot.
Basically it's a bad idea to generate XML SOAP package manually, you should have some wrapper on your side, which have to simplify your code.
Anyway, the C# code below + XML SOAP request
Content[] result = context.Submit(
new Command[]
{
new Value { Value = "PORE000079", LinkedCommand = PO302000.DocumentSummary.ReceiptNbr}
,new Value { Value = "OK", LinkedCommand = PO302000.AddPurchaseOrderLine.ServiceCommands.DialogAnswer, Commit = true }
,PO302000.Actions.AddPOOrderLine
,new Key { Value = "='PORG000077'", FieldName = PO302000.AddPurchaseOrderLine.OrderNbr.FieldName, ObjectName = PO302000.AddPurchaseOrderLine.OrderNbr.ObjectName }
,new Key { Value = "='CPU00004'", FieldName = PO302000.AddPurchaseOrderLine.InventoryID.FieldName, ObjectName = PO302000.AddPurchaseOrderLine.InventoryID.ObjectName }
,new Value{ Value = "True", LinkedCommand = PO302000.AddPurchaseOrderLine.Selected, Commit = true }
,PO302000.Actions.AddPOOrderLine2
,new Key{ Value = "='CPU00004'", FieldName = PO302000.DocumentDetails.InventoryID.FieldName, ObjectName = PO302000.DocumentDetails.InventoryID.ObjectName}
,new Value{ Value = "1.00", LinkedCommand = PO302000.DocumentDetails.ReceiptQty, Commit = true}
// the next part of code is needed if you use Serial items
,PO302000.BinLotSerialNumbers.ServiceCommands.NewRow
,new Value { Value = "R01", LinkedCommand = PO302000.BinLotSerialNumbers.Location }
,new Value { Value = "1.00", LinkedCommand = PO302000.BinLotSerialNumbers.Quantity, Commit = true }
,new Value { Value = "25.00", LinkedCommand = PO302000.DocumentDetails.UnitCost, Commit = true }
,new Key { Value = "='CPU00004'", FieldName = PO302000.DocumentDetails.InventoryID.FieldName, ObjectName = PO302000.DocumentDetails.InventoryID.ObjectName }
,new Value { Value = "0.00", LinkedCommand = PO302000.DocumentDetails.ReceiptQty, Commit = true }
,PO302000.Actions.Save
}
);
<?xml version="1.0" encoding="utf-8"?><soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"><soap:Body><Submit xmlns="http://www.acumatica.com/typed/"><commands><Command xsi:type="Value"><Value>PORE000079</Value><LinkedCommand xsi:type="Field"><FieldName>ReceiptNbr</FieldName><ObjectName>Document</ObjectName><Value>ReceiptNbr</Value><Commit>true</Commit><LinkedCommand xsi:type="Action"><FieldName>cancel</FieldName><ObjectName>Document</ObjectName><LinkedCommand xsi:type="Key"><FieldName>ReceiptNbr</FieldName><ObjectName>Document</ObjectName><Value>=[Document.ReceiptNbr]</Value><LinkedCommand xsi:type="Key"><FieldName>ReceiptType</FieldName><ObjectName>Document</ObjectName><Value>=[Document.ReceiptType]</Value></LinkedCommand></LinkedCommand></LinkedCommand></LinkedCommand></Command><Command xsi:type="Value"><Value>OK</Value><Commit>true</Commit><LinkedCommand xsi:type="Answer"><ObjectName>poLinesSelection</ObjectName><Value>='Yes'</Value></LinkedCommand></Command><Command xsi:type="Action"><FieldName>AddPOOrderLine</FieldName><ObjectName>Document</ObjectName><Commit>true</Commit></Command><Command xsi:type="Key"><FieldName>OrderNbr</FieldName><ObjectName>poLinesSelection</ObjectName><Value>='PORG000077'</Value></Command><Command xsi:type="Key"><FieldName>InventoryID</FieldName><ObjectName>poLinesSelection</ObjectName><Value>='CPU00004'</Value></Command><Command xsi:type="Value"><Value>True</Value><Commit>true</Commit><LinkedCommand xsi:type="Field"><FieldName>Selected</FieldName><ObjectName>poLinesSelection</ObjectName><Value>Selected</Value><Commit>true</Commit></LinkedCommand></Command><Command xsi:type="Action"><FieldName>AddPOOrderLine2</FieldName><ObjectName>Document</ObjectName><Commit>true</Commit></Command><Command xsi:type="Key"><FieldName>InventoryID</FieldName><ObjectName>transactions</ObjectName><Value>='CPU00004'</Value></Command><Command xsi:type="Value"><Value>1.00</Value><Commit>true</Commit><LinkedCommand xsi:type="Field"><FieldName>ReceiptQty</FieldName><ObjectName>transactions</ObjectName><Value>ReceiptQty</Value><Commit>true</Commit></LinkedCommand></Command><Command xsi:type="NewRow"><ObjectName>splits</ObjectName></Command><Command xsi:type="Value"><Value>R01</Value><LinkedCommand xsi:type="Field"><FieldName>LocationID</FieldName><ObjectName>splits</ObjectName><Value>Location</Value></LinkedCommand></Command><Command xsi:type="Value"><Value>1.00</Value><Commit>true</Commit><LinkedCommand xsi:type="Field"><FieldName>Qty</FieldName><ObjectName>splits</ObjectName><Value>Quantity</Value></LinkedCommand></Command><Command xsi:type="Value"><Value>25.00</Value><Commit>true</Commit><LinkedCommand xsi:type="Field"><FieldName>CuryUnitCost</FieldName><ObjectName>transactions</ObjectName><Value>UnitCost</Value></LinkedCommand></Command><Command xsi:type="Key"><FieldName>InventoryID</FieldName><ObjectName>transactions</ObjectName><Value>='CPU00004'</Value></Command><Command xsi:type="Value"><Value>0.00</Value><Commit>true</Commit><LinkedCommand xsi:type="Field"><FieldName>ReceiptQty</FieldName><ObjectName>transactions</ObjectName><Value>ReceiptQty</Value><Commit>true</Commit></LinkedCommand></Command><Command xsi:type="Action"><FieldName>Save</FieldName><ObjectName>Document</ObjectName></Command></commands></Submit></soap:Body></soap:Envelope>
So in the end what I did:
gem install 'mumboe-soap4r' # not soap4r,
# because soap4r is old and bugged with newer rubies
Then I ran
wsdl2ruby.rb --wsdl customer.wsdl --type client
Where wsdl2ruby.rb is installed together with mumboe-soap4r gem. Replace customer.wsdl with path to your wsdl, could be URL or file system path.
After running this command next files were created:
default.rb
defaultMappingRegistry.rb
defaultDriver.rb
ScreenClient.rb
Using those files you can write code similar to C# code or php code to interact with acumatica API:
require_relative 'defaultDriver'
require 'soap/wsdlDriver'
# this is my helper method to make life easier
def prepare_value(value, command, need_commit = false, ignore = false)
value_command = Value.new
value_command.value = value
value_command.linkedCommand = command
value_command.ignoreError = ignore unless ignore.nil?
value_command.commit = need_commit unless need_commit.nil?
value_command
end
soap_client = SOAP::WSDLDriverFactory.new('customer.wsdl').create_rpc_driver
soap_client.login(name: '', password: '').loginResult
screen = soap_client.getSchema(nil)
soap_client.clear(nil)
content = screen.getSchemaResult
# p schema
p customer = content.customerSummary.customerID
p customer_name = content.customerSummary.customerName
country = content.generalInfoMainAddress.country
customer_class = content.generalInfoFinancialSettings.customerClass
commands = ArrayOfCommand.new
commands << prepare_value('ABBA', customer_name)
commands << prepare_value('US', country)
commands << prepare_value('MERCHANT', customer_class)
commands << content.actions.insert
commands << customer.clone # to return
p commands
p soap_client.submit(commands)
Hope it will help someone.
Actually 'mumboe-soap4r' or 'soap2r' or 'soap4r' doesn't work with Acumatica soap API. They are too old and buggy.
In the end I am using Savon gem (version 2). I am creating message using XmlMarkup class. But how I know what XML should I create? In order to know this I am creating soap request in .net , then I see what right XML request looks like and only then I am creating soap request using Savon gem. Too much work, but I don't know better way for now. It works.
In order for Savon to work with Acumatica API I set next options:
client = Savon.client do
wsdl 'http://path/Soap/AR303000.asmx?wsdl'
log true
namespaces 'xmlns:soap' => 'http://schemas.xmlsoap.org/soap/envelope/'
env_namespace 'soap'
namespace_identifier nil
element_form_default ''
end
Don't forget to pass auth cookies
response = client.call(:login, message: { name: '', password: '' })
auth_cookies = response.http.cookies
Build your customer creating xml, then do submit
m = build_create_submit(customer_name)
response = client.call(:submit, message: m, cookies: auth_cookies)
# get customer id of newly created customer
customer_id = response.try(:hash).try(:[], :envelope).
try(:[], :body).
try(:[], :submit_response).
try(:[], :submit_result).
try(:[], :content).
try(:[], :customer_summary).
try(:[], :customer_id).
try(:[], :value)
I want to start working with Magento's REST API, but I can't seem to get it working.
To start with I need to get access tokens, here's what I'm trying:
require 'oauth'
#consumer = OAuth::Consumer.new("4200100753b2c8b03bde1f5b062c5a80", "c06abdcb734c85dfd7bb115c6a67ae4d", {:site=>"http://178.62.173.99/"})
#request_token = #consumer.get_request_token
# => oauth-0.4.7/lib/oauth/consumer.rb:216:in `token_request': 404 Not Found (OAuth::Unauthorized)
But I keep getting a 404 error.
What should I try next?
Here's a Ruby module I've written to create an access token for the Magento REST API:
module Token
def create_consumer
OAuth::Consumer.new(
CONSUMER_KEY,
CONSUMER_SECRET,
:request_token_path => '/oauth/initiate',
:authorize_path=>'/admin/oauth_authorize',
:access_token_path=>'/oauth/token',
:site => URL
)
end
def request_token(args = {})
args[:consumer].get_request_token(:oauth_callback => URL)
end
def get_authorize_url(args = {})
args[:request_token].authorize_url(:oauth_callback => URL)
end
def authorize_application(args = {})
m = Mechanize.new
m.get(args[:authorize_url]) do |login_page|
auth_page = login_page.form_with(:action => "#{URL}/index.php/admin/oauth_authorize/index/") do |form|
form.elements[1].value = ADMIN_USERNAME
form.elements[2].value = ADMIN_PASSWORD
end.submit
authorize_form = auth_page.forms[0]
#callback_page = authorize_form.submit
end
#callback_page.uri.to_s
end
def extract_oauth_verifier(args = {})
callback_page = "#{args[:callback_page]}".gsub!("#{URL}/?", '')
callback_page_query_string = CGI::parse(callback_page)
callback_page_query_string['oauth_verifier'][0]
end
def get_access_token(args = {})
args[:request_token].get_access_token(:oauth_verifier => args[:oauth_verifier])
end
def save_tokens_to_json(args = {})
auth = {}
auth[:time] = Time.now
auth[:token] = args[:access_token].token
auth[:secret] = args[:access_token].secret
File.open("#{args[:path]}#{args[:filename]}.json", 'w') {|f| f.write(auth.to_json)}
auth
end
def get_new_access_tokens
new_consumer = self.create_consumer
new_request_token = self.request_token(consumer: new_consumer)
new_authorize_url = self.get_authorize_url(request_token: new_request_token)
authorize_new_application = self.authorize_application(authorize_url: new_authorize_url)
extract_new_oauth_verifier = self.extract_oauth_verifier(callback_page: authorize_new_application)
new_access_token = self.get_access_token(request_token: new_request_token, oauth_verifier: extract_new_oauth_verifier)
save_tokens_to_json(filename: 'magento_oauth_access_tokens', path: '/', access_token: new_access_token)
return 'Successfully obtained new access tokens.'
end
end
Run #get_new_access_tokens to get an access token.
Don't forget to define the following variable:
CONSUMER_KEY
CONSUMER_SECRET
URL
ADMIN_USERNAME
ADMIN_PASSWORD
Check out mage on rails. It should work right out of the box. Check out this page for annotated ruby code showcasing the oauth flow