Can't upload a file on Messenger bot with Ruby - ruby

I can't upload an image with Messenger bot on Ruby.
Here is a code that works in Bash:
curl \
-F recipient='{"id":"USER_ID"}' \
-F message='{"attachment":{"type":"image", "payload":{}}}' \
-F filedata="#out.jpg" \
"https://graph.facebook.com/v2.6/me/messages?access_token=PAGE_ACCESS"
Here is a translation with RestClient:
require 'rest-client'
require 'json'
file = "out.jpg"
tkn = "PAGE_ACCESS"
params = {
"recipient" => {"id" => "USER_ID"},
"message" => {
"attachment":{"type":"image", "payload":{}}
},
"filedata" => 'out.jpg'
}
puts params.to_json
begin
r = RestClient.post "https://graph.facebook.com/v2.6/me/messages?access_token=#{tkn}", params.to_json, :content_type => :json
rescue => e
puts e.response
end
Here is the answer I get:
{"recipient":{"id":"USER_ID"},"message":{"attachment":{"type":"image","payload":{}}},"filedata":"#out.jpg"}
{"error":{"message":"(#100) Incorrect number of files uploaded. Must upload exactly one file.","type":"OAuthException","code":100,"fbtrace_id":"xxxxx"}}

Related

unable to make api request with http ruby gem

I am trying to translate a curl request that works in the terminal for me into ruby code using the http gem.
This is the curl request that gives me back the valid json I want:
curl -X GET --header 'Accept: application/json' --header 'api_key: somekey' --header 'authtoken: sometoken' 'https://cdn.domain.io/v3/content_types/shirts/entries?environment=dev'
With the http gem I try to do this in my ruby script:
HTTP.headers(:Accept => "application/json", :api_key => 'somekey', :authtoken => 'sometoken').get("https://cdn.domain.io/v3/content_types/shirts/entries", :params => { :environment => 'dev'}).body.readpartial
And this gives my back "api_key":["is not valid."]} error from the server
What am I doing wrong? How do I get this to work?
Typhoeus seems to be working out well:
require "typhoeus"
require 'multi_json'
require "awesome_print"
response = Typhoeus::Request.new(
"https://api.domain.io/v3/content_types/shirts/entries?environment=dev",
headers: { api_key: "somekey", access_token: "sometoken",
accept_encoding: "gzip" }
).run
# puts response.body
begin
ap MultiJson.load(response.body, :symbolize_keys => true)
rescue MultiJson::ParseError => exception
p exception.data # => "{invalid json}"
p exception.cause # => JSON::ParserError: 795: unexpected token at '{invalid json}'
end

Google Apps Groups Settings API :: 500 Backend Error

Whenever I attempt to access the groups from our Google Apps instance, I get the following response:
{
"error": {
"errors": [
{
"domain": "global",
"reason": "backendError",
"message": "Backend Error"
}
],
"code": 500,
"message": "Backend Error"
}
}
The code I am using is below:
begin
require 'google/api_client'
rescue LoadError
puts "You need the google-api-ruby-client gem..."
puts "$ gem install google-api-client"
exit 1
end
client = Google::APIClient.new(application_name: "Group Modifier")
## Use key to authenticate and generate token
key = Google::APIClient::PKCS12.load_key("#{File.dirname(__FILE__)}/mykey.p12", 'notasecret')
service_account = Google::APIClient::JWTAsserter.new(
'mydeveloperid#developer.gserviceaccount.com',
'https://www.googleapis.com/auth/apps.groups.settings',
key)
client.authorization = service_account.authorize
groupssettings = client.discovered_api('groupssettings', 'v1')
result = client.execute(
:api_method => groupssettings.groups.get,
:parameters => { 'groupUniqueId' => 'mygroup#mydomain.com', 'alt' => 'json' }
)
puts result.body
I've added the correct permissions and all of that in both the "Manage API client access" within the Google Apps Admin Console and within the https://cloud.google.com/console.
I even noticed that when I use the "https://developers.google.com/admin-sdk/groups-settings/v1/reference/groups/get#try-it" it doesn't return anything.
Please help me out
I finally resolved my problem with using some example code from the git repo homepage. This is what I came up with:
begin
require 'google/api_client'
rescue LoadError
puts "You need the google-api-ruby-client gem..."
puts "$ gem install google-api-client"
exit 1
end
client = Google::APIClient.new
key = Google::APIClient::KeyUtils.load_from_pkcs12("#{File.dirname(__FILE__)}/mykey.p12", 'notasecret')
client.authorization = Signet::OAuth2::Client.new(
:token_credential_uri => 'https://accounts.google.com/o/oauth2/token',
:audience => 'https://accounts.google.com/o/oauth2/token',
:scope => 'https://www.googleapis.com/auth/apps.groups.settings',
:issuer => 'mydeveloperid#developer.gserviceaccount.com',
:person => 'myemail#mydomain.com',
:signing_key => key)
client.authorization.fetch_access_token!
groupssettings = client.discovered_api('groupssettings', 'v1')
result = client.execute(
:api_method => groupssettings.groups.get,
:parameters => { :groupUniqueId => 'mygroup#mydomain.com', :alt => 'json' }
)
puts result.body

Validate In-App-Purchase Android/Google on Server side

I would like to use the purchase token from the in app purchases in an android app to validate it to the google server on my own server.
With the following code I can validate a token, but I have to authenticate myself with my OAuth credentials every time:
class GooglePlayVerification
require 'google/api_client'
# Refer:
# https://code.google.com/p/google-api-ruby-client/issues/detail?id=72
# and
# http://jonathanotto.com/blog/google_oauth2_api_quick_tutorial.html
# and
# http://milancermak.wordpress.com/2012/08/24/server-side-verification-of-google-play-subsc/
GOOGLE_KEY = 'xxx.apps.googleusercontent.com'
GOOGLE_SECRET = 'xxxx'
APP_NAME = 'xx.xx.xx'
SCOPE = "https://www.googleapis.com/auth/androidpublisher"
def self.token
##token ||= begin
require 'oauth2'
raise "Missing client_id variable" if GOOGLE_KEY.to_s.empty?
raise "Missing client_secret variable" if GOOGLE_SECRET.to_s.empty?
raise "Missing scope variable" if SCOPE.to_s.empty?
redirect_uri = 'https://localhost/oauth2callback'
auth_client_obj = OAuth2::Client.new(GOOGLE_KEY, GOOGLE_SECRET, {:site => 'https://accounts.google.com', :authorize_url => "/o/oauth2/auth", :token_url => "/o/oauth2/token"})
puts "1) Paste this URL into your browser where you are logged in to the relevant Google account\n\n"
puts auth_client_obj.auth_code.authorize_url(:scope => SCOPE, :access_type => "offline", :redirect_uri => redirect_uri, :approval_prompt => 'force')
puts "\n\n\n2) Accept the authorization request from Google in your browser:"
puts "\n\n\n3) Google will redirect you to localhost, but just copy the code parameter out of the URL they redirect you to, paste it here and hit enter:\n"
code = gets.chomp.strip
access_token_obj = auth_client_obj.auth_code.get_token(code, {:redirect_uri => redirect_uri, :token_method => :post})
puts "Result: #{access_token_obj.inspect}\n\n"
puts "Token is: #{access_token_obj.token}"
puts "Refresh token is: #{access_token_obj.refresh_token}"
{
:access_token => access_token_obj.token,
:refresh_token => access_token_obj.refresh_token,
:expires_in => access_token_obj.expires_in,
:expires_at => access_token_obj.expires_at
}
end
end
def self.refresh_token
refresh_client_obj = OAuth2::Client.new(GOOGLE_KEY, GOOGLE_SECRET, {:site => 'https://accounts.google.com', :authorize_url => '/o/oauth2/auth', :token_url => '/o/oauth2/token'})
refresh_access_token_obj = OAuth2::AccessToken.new(refresh_client_obj, token[:access_token], {refresh_token: token[:refresh_token]})
refresh_access_token_obj.refresh!
puts "refresh token: #{refresh_access_token_obj.inspect}"
##token = {
:access_token => refresh_access_token_obj.token,
:refresh_token => refresh_access_token_obj.refresh_token,
:expires_in => refresh_access_token_obj.expires_in,
:expires_at => refresh_access_token_obj.expires_at
}
end
# ie. https://developers.google.com/android-publisher/v1/
# eg.
# #subscription_id com.stocklight.stocklight.standardsubscription
# #purchase_token xxx
def self.verify_subscription(subscription_id, purchase_token)
response = RestClient.get "https://www.googleapis.com/androidpublisher/v1.1/applications/#{APP_NAME}/inapp/#{subscription_id}/purchases/#{purchase_token}?access_token=#{token[:access_token]}"
puts "Respnse \n #{response.inspect}"
puts response.code == 200
puts JSON.parse(response)
return response.code == 200 && JSON.parse(response)['kind'] =='androidpublisher#inappPurchase'
rescue
return false
end
end
Has anyone an idea how to authenticate a server without such things like OAuth on the server? Is there another authentification possibility?
Thanks!
Here is my ruby code:
def self.verify_subscription(subscription_id, transaction_id)
json = JSON.parse(transaction_id)
order = ["orderId", "packageName", "productId", "purchaseTime", "purchaseState", "purchaseToken"]
signature = json["signature"]
data = {}
order.each do |o|
data[o] = json[o]
end
key = OpenSSL::PKey::RSA.new(Base64.decode64(GOOGLE_PUBLIC_KEY))
verified = key.verify(OpenSSL::Digest::SHA1.new, Base64.decode64(signature), data.to_json)
verified
end

Standardizing api responses in a modular Sinatra application

I'm developing an api as a modular Sinatra web application and would like to standardize the responses that are returned without having to do so explicitly. I thought this could be achieved by using middleware but it fails in most scenarios. The below sample application is what I have so far.
config.ru
require 'sinatra/base'
require 'active_support'
require 'rack'
class Person
attr_reader :name, :surname
def initialize(name, surname)
#name, #surname = name, surname
end
end
class MyApp < Sinatra::Base
enable :dump_errors, :raise_errors
disable :show_exceptions
get('/string') do
"Hello World"
end
get('/hash') do
{"person" => { "name" => "john", "surname" => "smith" }}
end
get('/array') do
[1,2,3,4,5,6,7, "232323", '3245235']
end
get('/object') do
Person.new('simon', 'hernandez')
end
get('/error') do
raise 'Failure of some sort'
end
end
class ResponseMiddleware
def initialize(app)
#app = app
end
def call(env)
begin
status, headers, body = #app.call(env)
response = {'status' => 'success', 'data' => body}
format(status, headers, response)
rescue ::Exception => e
response = {'status' => 'error', 'message' => e.message}
format(500, {'Content-Type' => 'application/json'}, response)
end
end
def format(status, headers, response)
result = ActiveSupport::JSON.encode(response)
headers["Content-Length"] = result.length.to_s
[status, headers, result]
end
end
use ResponseMiddleware
run MyApp
Examples (in JSON):
/string
Expected: {"status":"success","data":"Hello World"}
Actual: {"status":"success","data":["Hello World"]}
/hash (works)
Expected: {"status":"success","data":{"person":{"name":"john","surname":"smith"}}}
Actual: {"status":"success","data":{"person":{"name":"john","surname":"smith"}}}
/array
Expected: {"status":"success","data": [1,2,3,4,5,6,7,"232323","3245235"]}
Actual: {"status":"error","message":"wrong number of arguments (7 for 1)"}
/object
Expected: {"status":"success","data":{"name":"simon","surname":"hernandez"}}
Actual: {"status":"success","data":[]}
/error (works)
Expected: {"status":"error","message":"Failure of some sort"}
Actual: {"status":"error","message":"Failure of some sort"}
If you execute the code, you will see that /hash and /error give back the required responses, but the rest do not. Ideally, I would not like to change anything in the MyApp class. It's currently being built on top of Sinatra 1.3.3, ActiveSupport 3.2.9 and Rack 1.4.1.
With some help from #sinatra on irc.freenode.org, I managed to get it down to what I want. I added the following to MyApp:
def route_eval
result = catch(:halt) { super }
throw :halt, {"result" => result}
end
I then changed the following line in ResponseMiddleware:
response = {'status' => 'success', 'data' => body}
to
response = {'status' => 'success', 'data' => body["result"]}
and all my test cases passed.

Connect Rails 3 to Salesforce/Any other App via OAuth

Has anybody connected to Salesforce through Rails 3 App via oauth? Could you please post code for doing same. I am trying to same but I get some error below is my code
def oauth_client
consumer_key = '....'
consumer_secret = '....'
oauth_options = {
:site => 'https://login.salesforce.com',
:scheme => :body,
:request_token_path => '/_nc_external/system/security/oauth/RequestTokenHandler',
:authorize_path => '/setup/secur/RemoteAccessAuthorizationPage.apexp',
:access_token_path => '/_nc_external/system/security/oauth/AccessTokenHandler',
}
OAuth::Consumer.new consumer_key, consumer_secret, oauth_options
end
def oauth_redirect_uri
uri = URI.parse(request.url)
uri.path = '/sfdc/oauth_callback'
uri.query = nil
# uri = "http://localhost:3000/sfdc/oauth_callback"
uri.to_s
end
def oauth_connect
consumer_key = '...' # from SalesForce
consumer = oauth_client
request_t = consumer.get_request_token
redirect_to request_t.authorize_url(
:redirect_uri => oauth_redirect_uri,
:oauth_consumer_key => consumer_key
)
end
def oauth_callback
access = request_t.get_access_token :oauth_verifier => params[:oauth_verifier]
p access
render :text => access.token
end
Error undefined method get_access_token for #<ActionDispatch::Request:0x12b79f370>. the request variable is nil here. How do I get it back?
The rforce gem has quite a bit of an example that I pasted below. However you might just want to use rforce instead of rolling your own.
def init_server(url)
#url = URI.parse(url)
if (#oauth)
consumer = OAuth::Consumer.new \
#oauth[:consumer_key],
#oauth[:consumer_secret],
{
:site => url,
:proxy => #proxy
}
consumer.http.set_debug_output $stderr if show_debug
#server = OAuth::AccessToken.new \
consumer,
#oauth[:access_token],
#oauth[:access_secret]
class << #server
alias_method :post2, :post
end
else
#server = Net::HTTP.Proxy(#proxy).new(#url.host, #url.port)
#server.use_ssl = #url.scheme == 'https'
#server.verify_mode = OpenSSL::SSL::VERIFY_NONE
# run ruby with -d or env variable SHOWSOAP=true to see SOAP wiredumps.
#server.set_debug_output $stderr if show_debug
end
end

Resources