Change non ascii character in an HTTP request - ruby-on-rails

i have to make an http get call to an external service. By sending an address, the latitude and longitude coordinates are returned. The problem is that if the address is Russian or French I have errors like:
URI must be ascii only "http://nominatim.openstreetmap.org/?format=json&addressdetails=1&q={Barrage de G\u00E9nissiat, Rue Marcel Paul, Injoux, Franclens, Nantua, Ain, Auvergne-Rh\u00F4ne-Alpes, Francia metropolitana, 74910, Francia}&format=json"
My code is:
url = "http://nominatim.openstreetmap.org/?format=json&addressdetails=1&q={"+ address_search +"}&format=json";
response = Faraday.get url
the variable address_search is:
Barrage de Génissiat, Rue Marcel Paul, Injoux, Franclens, Nantua, Ain, Auvergne-Rhône-Alpes, Francia metropolitana, 74910, Francia
Faraday is just a grm in rails to make an HTTP request, nothing strange. I have to manipulate the URL. Do you have any suggestion?
EDIT:
print Rails.logger.info "body " + response.body
print Rails.logger.info response.status
print Rails.logger.info response.env.url
This is the output
body []
200
https://nominatim.openstreetmap.org/?addressdetails=1&format=json&q=Barrage+de+G%C3%A9nissiat%2C+Rue+Marcel+Paul%2C+Injoux%2C+Franclens%2C+Nantua%2C+Ain%2C+Auvergne-Rh%C3%B4ne-Alpes%2C+Francia+metropolitana%2C+74910%2C+Francia
Rendering homes/index.html.erb within layouts/application

The query should be encoded, you can do it manually:
query = 'Barrage de Génissiat, Rue Marcel Paul, Injoux, Franclens, Nantua, Ain, Auvergne-Rhône-Alpes, Francia metropolitana, 74910, Francia'
address_search = URI.escape(query)
url = "https://nominatim.openstreetmap.org/?format=json&addressdetails=1&q=#{address_search}&format=json"
response = Faraday.get(url)
Or leave the job for Faraday:
query = 'Barrage de Génissiat, Rue Marcel Paul, Injoux, Franclens, Nantua, Ain, Auvergne-Rhône-Alpes, Francia metropolitana, 74910, Francia'
connection = Faraday.new('https://nominatim.openstreetmap.org')
response = connection.get do |request|
request.params = { format: 'json', addressdetails: 1, q: query }
end
Here is the response:
=> #<Faraday::Response:0x0000556afc452060
#env=
#<struct Faraday::Env
method=:get,
body=
"[{\"place_id\":104161692,\"licence\":\"Data \xC2\xA9 OpenStreetMap contributors, ODbL 1.0. https://osm.org/copyright\",\"osm_type\":\"way\",\"osm_id\":80667335,\"boundingbox\":[\"46.0516289\",\"46.0531641\",\"5.8112371\",\"5.81
4139\"],\"lat\":\"46.0523765\",\"lon\":\"5.812744291298651\",\"display_name\":\"Barrage de G\xC3\xA9nissiat, Rue Marcel Paul, Injoux, Franclens, Nantua, Ain, Auvergne-Rh\xC3\xB4ne-Alpes, France m\xC3\xA9tropolitaine, 74910, France\"
,\"class\":\"tourism\",\"type\":\"attraction\",\"importance\":1.7983764706069638,\"icon\":\"https://nominatim.openstreetmap.org/images/mapicons/poi_point_of_interest.p.20.png\",\"address\":{\"tourism\":\"Barrage de G\xC3\xA9nissiat\
",\"road\":\"Rue Marcel Paul\",\"suburb\":\"Injoux\",\"village\":\"Franclens\",\"municipality\":\"Nantua\",\"county\":\"Ain\",\"state\":\"Auvergne-Rh\xC3\xB4ne-Alpes\",\"country\":\"France\",\"postcode\":\"74910\",\"country_code\":\
"fr\"}}]",
url=
#<URI::HTTPS https://nominatim.openstreetmap.org/?addressdetails=1&format=json&q=Barrage+de+G%C3%A9nissiat%2C+Rue+Marcel+Paul%2C+Injoux%2C+Franclens%2C+Nantua%2C+Ain%2C+Auvergne-Rh%C3%B4ne-Alpes%2C+Francia+metropolitana%2C+74910%2C+Francia>,
request=#<struct Faraday::RequestOptions params_encoder=nil, proxy=nil, bind=nil, timeout=nil, open_timeout=nil, write_timeout=nil, boundary=nil, oauth=nil, context=nil>,
request_headers={"User-Agent"=>"Faraday v0.17.3"},
ssl=
#<struct Faraday::SSLOptions
verify=true,
ca_file=nil,
ca_path=nil,
verify_mode=nil,
cert_store=nil,
client_cert=nil,
client_key=nil,
certificate=nil,
private_key=nil,
verify_depth=nil,
version=nil,
min_version=nil,
max_version=nil>,
parallel_manager=nil,
params=nil,
response=#<Faraday::Response:0x0000556afc452060 ...>,
response_headers=
{"server"=>"nginx",
"date"=>"Thu, 15 Oct 2020 19:42:53 GMT",
"content-type"=>"application/json; charset=UTF-8",
"transfer-encoding"=>"chunked",
"connection"=>"close",
"access-control-allow-origin"=>"*",
"access-control-allow-methods"=>"OPTIONS,GET"},
status=200,
reason_phrase="OK">,
#on_complete_callbacks=[]>
Make sure that you use https schema, otherwise, you'll get a response with a redirect.

I use this code:
query = "Barrage de Génissiat, Rue Marcel Paul, Injoux, Franclens, Nantua, Ain, Auvergne-Rhône-Alpes, Francia metropolitana, 74910, Francia"
connection = Faraday.new('https://nominatim.openstreetmap.org')
response = connection.get do |request|
request.params = { format: 'json', addressdetails: 1, q: query }
end
print Rails.logger.info response.body
And I receive []..

Related

Generate UPC Barcode with Number with rails

I'm able to generate barcode by using "Barby" gem with "EAN13 & UPCA" But I need to show numbers with the barcode and I have no idea, what I'm missing in code.
Current Generated Barcode
Read out the barby gem documentation but no luck.
#barcode_value = "123456789123"
full_path = "public/Barcodes/"+#barcode_value+".png"
barcode = Barby::EAN13.new(#barcode_value)
File.open(full_path, 'wb') { |f| f.write barcode.to_png(:margin => 3, :xdim => 2, :height => 50) }
Generate Barcode with Number.
Required Barcode
The code you generated is a Code 39. The barcode you marked as required is a Code EAN 13, not UPC (those are not identical). One way to create such a code with Ruby would be using an API, e.g. https://mcapi.io/barcode/barcode-api-ruby.php
The API is hosted on RapidAPI; sample call to create your barcode:
# Ruby
require 'uri'
require 'net/http'
require 'openssl'
url = URI("https://mcapi-barcode.p.rapidapi.com/")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
request = Net::HTTP::Post.new(url)
request["content-type"] = 'application/json'
request["x-rapidapi-key"] = 'YOUR_API_KEY'
request["x-rapidapi-host"] = 'mcapi-barcode.p.rapidapi.com'
request.body = "{
\"data\": \"9501101530003\",
\"type\": 1,
\"size\": 2,
\"format\": \"pdf\"
}"
response = http.request(request)
The returned code will be in response.read_body as a base64 encoded PDF (posted as a screenshot since SO doesn't display PDFs):
EAN13 created with Ruby
(Disclaimer: We are the developers.)

Rake task to update records

I am doing a rake task that is scrapping a website in order to find concerts:
lib/tasks/my_task.rake
task :find_concerts => :environment do
doc = Nokogiri::HTML(open(url))
data = doc.search('#dateconcert table')
data = data.css('.jaunec' ).map { |tr| tr.css('td').map(&:text) } + doc.css('.jaunef' ).map { |tr| tr.css('td').map(&:text) }
data.each do |concert|
c = Concert.new
c.date = concert[0]
c.city = concert[1]
c.save
end
end
What I want
I want to get an alert when a new concert is added ( on the website I am scrapping), so the tasks will be run everyday.
My problem
I want my Concerts list to be updated if there is a new record...
With the task I wrote it finds again the records that are already stored and duplicated them...
I only want the new records that could be found...
In the end I would like to compare what is new between the two last tasks in order to send an alert if something new was found.
EDIT
This is what data returns
[
["03 Décembre 2017", "PONT L\u0092ABBE (29) | Centre Culturel Le Triskell "],
["26 Janvier 2018", "MONTPELLIER (34) | Le Jam "],
["17 Février 2018", "BLOIS (41) | All That Jazz / Les Lobis "],
["22 Mars 2018", "MOISSAC (82) | Hall de Paris "],
["24 Mars 2018", "LAX (Baraqueville) (12) | Festival Lax'N Blues LAX\u0092N "],
["08 Décembre 2017", "ECHANGE CULTUREL CAMEROUN (0) | au 18 décembre 2017 - Organisation tournée MFR "],
["27 Janvier 2018", "LE THOR (84) | Le Sonograf "],
["16 Mars 2018", "CHAUMONT (52) | Le Nouveau Relax "],
["23 Mars 2018", "AUCH (32) | Le Cri'Art "]
]
I found a solution that may need some refactoring, though.
So I created two tasks,
find_concerts that will be run manually for the first scrap
update_concerts that will be run every day
task
require "nokogiri"
require "open-uri"
require "date"
require "time"
namespace :scrap do
desc "This get MM concerts"
url = "http://mountain-men.fr/concerts/"
doc = Nokogiri::HTML(open(url))
data = doc.search('#dateconcert table')
data = data.css('.jaunec' ).map { |tr| tr.css('td').map(&:text) } + doc.css('.jaunef' ).map { |tr| tr.css('td').map(&:text) }
task :find_concerts => :environment do
data.each do |concert|
c = Concert.create
c.date = concert[0]
c.city = concert[1]
c.save
end
end
task :update_concerts => :environment do
existing_date = Concert.all.map { |c| [c.date, c.city] }
data.each do |concert|
c = Concert.create
c.date = concert[0]
c.city = concert[1]
c.save unless existing_date.include?([concert[0], concert[1]])
end
Concert.where(city: nil, date: nil).destroy_all
end
end
I am not sure if I understand you correctly, but what you need to do is to check if it exists and other wise create.
I would do some thing like this.
task :find_concerts => :environment do
doc = Nokogiri::HTML(open(url))
data = doc.search('#dateconcert table')
data = data.css('.jaunec' ).map { |tr| tr.css('td').map(&:text) } + doc.css('.jaunef' ).map { |tr| tr.css('td').map(&:text) }
data.each do |concert|
Concert.where(data: concert[0], city: concert[1]).first_or_create
end
end
Now you only create if it doesn't exist. Then when you create one you can set a hook.
class Concern
after_create :send_notification
def send_notification
# send email here
end
end

Integrating Payfort Payment with Ruby On Rails App

I am trying to implement the Payfort payment gateway with rails app.
But i am getting following response message:
"response_message":"Signature mismatch"
Following is my try:
params = {command: "AUTHORIZATION",
currency: "USD",
access_code: "z7TfXF2xxxxxxxxxxxx",
merchant_identifier: "xoNbjDoq",
merchant_reference: "405",
language: "en",
amount: 250,
token_name: "token_is_here",
expiry_date: "07/2023",
card_number: "5200421234563432",
card_security_code: "417",
card_holder_name: "Abc Xyz",
remember_me: "YES",
return_url: "http://lvh.me:3000/payments/test"}
params = params.except(:card_security_code, :card_number, :expiry_date, :card_holder_name, :remember_me)
params = params.sort.to_h
string = params.to_query(nil)
string = string.gsub! '&', ''
string = ##sha_request + string + ##sha_request
string = Digest::SHA256.hexdigest string
uri = URI.parse("https://sbpaymentservices.payfort.com/FortAPI/paymentApi")
header = {'Content-Type': 'application/json'}
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
request = Net::HTTP::Post.new(uri.request_uri, header)
request.body = params.to_json
response = http.request(request)
Check sequence of parameters while generating signature. and check for algorithm which u have setup in account and use same algorithm while generating signature
Or else try using their gem
https://github.com/payfort/start-ruby
there may be many reasons for such issue one of them is rails form params and also hashing algorithm, here's my implementation for it
def sign_with_key(params, key)
string_to_digest = params.sort { |a, b| a[0].upcase <=> b[0].upcase }.map { |k, v| "#{k}=#{v}" }.join()
string_to_digest.prepend(key)
string_to_digest << key
"Digest::#{#options[:sha].upcase}".constantize.hexdigest(string_to_digest)
end
Rest of the code seems good but the issue I faced and I see here is that you are using string = params.to_query(nil) which will used escaped characters %20 instead of space in card_holder_name
So I used CGI.unescape and fixed the issue -
def signature(string)
Digest::SHA256.hexdigest(CGI.unescape("#{SHA_REQUEST_PHRASE}#{string.gsub(/&/, "")}#{SHA_REQUEST_PHRASE}"))
end
Hope it helps :)

rails no bitesize error to 3rd party API response

I have a rails app and I'm trying to get calendar freebusy events from google. When I run the following code I get undefined method "bytesize" for #<Hash.. error for the result = client.execute(.... method. I checked out some other stackoverflow answers, but I can't see what I'm doing wrong. Anyone can tell me how I should deal with this problem?
controller
include GoogleCalendarApi
......
#user = current_user
#google = #user.socials.where(provider: "google_oauth2").first
unless #google.blank?
# #client = get_busy_events(#google)
# #result = open_gcal_connection(get_busy_events, #client, #google)
#result = get_busy_events(#google)
end
.....
lib/google_calendar_api.rb
def init_google_api_calendar_client(google_account)
#method only called if google_oauth2 social exists
client = Google::APIClient.new
client.authorization.access_token = google_account.token
client.authorization.client_id = ENV['GOOGLE_API_KEY']
client.authorization.client_secret = ENV['GOOGLE_API_SECRET']
client.authorization.refresh_token = google_account.refresh_token
return client
end
def get_busy_events(social_object)
client = init_google_api_calendar_client(social_object)
old_token = client.authorization.access_token
service = client.discovered_api('calendar', 'v3')
result = client.execute(
api_method: service.freebusy.query,
body: { timeMin: '2015-12-24T17:06:02.000Z',
timeMax: '2016-01-30T17:06:02.000Z',
items: [{ id: social_object.email }]},
headers: {'Content-Type' => 'application/json'})
new_token = client.authorization.access_token
if old_token != new_token
social_object.update_attribute(token: new_token)
end
return result
end
full error:
Google::APIClient - Initializing client with options {}
21:33:15 puma.1 | Google::APIClient - Please provide :application_name and :application_version when initializing the client
21:33:15 puma.1 | Google::APIClient::Request Sending API request get https://www.googleapis.com/discovery/v1/apis/calendar/v3/rest {"User-Agent"=>"google-api-ruby-client/0.8.6 Mac OS X/10.10.4\n (gzip)", "Accept-Encoding"=>"gzip", "Content-Type"=>""}
21:33:15 puma.1 | Decompressing gzip encoded response (12528 bytes)
21:33:15 puma.1 | Decompressed (103479 bytes)
21:33:15 puma.1 | Google::APIClient::Request Result: 200 {"expires"=>"Thu, 31 Dec 2015 05:36:09 GMT", "date"=>"Thu, 31 Dec 2015 05:31:09 GMT", "etag"=>"\"ye6orv2F-1npMW3u9suM3a7C5Bo/U5WRLEvUgzkUohB7qwzTs2ir15o\"", "vary"=>"Origin, X-Origin", "content-type"=>"application/json; charset=UTF-8", "x-content-type-options"=>"nosniff", "x-frame-options"=>"SAMEORIGIN", "x-xss-protection"=>"1; mode=block", "content-length"=>"12528", "server"=>"GSE", "age"=>"126", "cache-control"=>"public, max-age=300, must-revalidate, no-transform", "alternate-protocol"=>"443:quic,p=1", "alt-svc"=>"quic=\":443\"; ma=604800; v=\"30,29,28,27,26,25\"", "connection"=>"close"}
21:33:15 puma.1 | Google::APIClient::Request Sending API request post https://www.googleapis.com/calendar/v3/freeBusy {"User-Agent"=>"google-api-ruby-client/0.8.6 Mac OS X/10.10.4\n (gzip)", "Content-Type"=>"application/json", "Accept-Encoding"=>"gzip", "Authorization"=>"Bearer ya29.WQKv43gUEb0Jt3jTBevBs0_Z9VurfGxmbH8Knv8E9Sqbw4zxeCHjydwUeyo3MSAotYj0", "Cache-Control"=>"no-store"}
21:33:15 puma.1 | Completed 500 Internal Server Error in 382ms (ActiveRecord: 0.8ms)
21:33:15 puma.1 |
21:33:15 puma.1 | NoMethodError - undefined method `bytesize' for #<Hash:0x007fb6d25b9330>:
21:33:15 puma.1 | /Users/Silo/.rvm/rubies/ruby-2.2.3/lib/ruby/2.2.0/net/http/generic_request.rb:182:in `send_request_with_body'
21:33:15 puma.1 | /Users/Silo/.rvm/rubies/ruby-2.2.3/lib/ruby/2.2.0/net/http/generic_request.rb:120:in `exec'
From Pardeep's link, try
result = client.execute(
api_method: service.freebusy.query,
body: URI.encode_www_form({ timeMin: '2015-12-24T17:06:02.000Z',
timeMax: '2016-01-30T17:06:02.000Z',
items: [{ id: social_object.email }]}),
headers: {'Content-Type' => 'application/json'})
The problem is that the body could not be sent as a hash. You should encode as an string.

How send email with BCC header via GMAIL API?

How can I send email with BCC via GMAIL API? I send emails to TO or CC but BCC doesn't work. I use Base64.urlsafe_encode64(email.to_s)and this code create string without BCC. My working code example:
email = Mail.new
email.date = Time.now
email.subject = subject
email.to = email_array_to_email_to(to)
email.cc = email_array_to_email_to(cc)
email.bcc = email_array_to_email_to(bcc)
email.reply_to = email_array_to_email_to(reply_to)
email.html_part do
body message
end
request = {
api_method: #google_api.users.messages.to_h['gmail.users.messages.send'],
parameters: { userId: 'me' },
body_object: {
raw: Base64.urlsafe_encode64(email.to_s)
},
}
Do I have to call again GMAIL API and send this email with thread id and BCC as TO?
I use google-api-client 0.7.1
EDIT:
Mail object:
#<Mail::Message:70336725981360,
Multipart: true,
Headers: <Date: Tue,
01 Dec 2015 14:09:08 +0100>,
<Reply-To: >,
<To: ["quatermain32 <my_email#gmail.com>"]>,
<Cc: ["quatermain32 <my_email#gmail.com>"]>,
<Bcc: ["my_email#gmail.com"]>,
<Subject: Test subject>,
<Content-Type: multipart/mixed>>
Mail object with to_s:
"Date: Tue, 01 Dec 2015 14:09:08 +0100\r\n
To: my_email <my_email#gmail.com>\r\n
Cc: my_email <my_email#gmail.com>\r\n
Message-ID: <565d9c6e3cf0b_058b7#Olivers-MacBook-Pro.local.mail>\r\n
Subject: Test subject\r\n
Mime-Version: 1.0\r\n
Content-Type: multipart/mixed;\r\n
boundary=\"--==_mimepart_565d9bf468e77_cb0d35e200577a\";\r\n
charset=UTF-8\r\n
Content-Transfer-Encoding: 7bit\r\n
\r\n
\r\n
----==_mimepart_565d9bf468e77_cb0d3ff88645e200577a\r\n
Content-Type: text/html;\r\n
charset=UTF-8\r\n
Content-Transfer-Encoding: 7bit\r\n
\r\n
<p>Test content</p>\r\n
----==_mimepart_565d9bf468e77_cb0d3ff88645e200577a--\r\n
"
You have to manually add the bcc header to the email, it will not be sent to the recipients. Same as gmail-ruby-api does it https://github.com/jhk753/gmail-ruby-api/blob/e0d62a751bc31397926c5800532f26e185e00b16/lib/gmail/message.rb
encoded = mail.encoded
if bcc = mail.bcc.join(",").presence
encoded.prepend "Bcc: #{bcc}\n"
end
... send email ...

Resources