Subscribe an email with MailChimp API 3.0 in Ruby - ruby-on-rails

I'm trying to subscribe a user to my MailChimp list from Ruby 1.9.3. I've got the following code:
require 'net/http'
require 'digest/md5'
class Email < ActiveRecord::Base
attr_accessible :email
validates :email, :confirmation => true
before_create :chimp_subscribe
def chimp_subscribe
api_key = "my api key"
list_id = "my list id"
dc = "my data center"
member_id = Digest::MD5.hexdigest(self.email)
uri = URI.parse("https://" + dc + ".api.mailchimp.com/3.0/lists/" + list_id + "/members/" + member_id)
req = Net::HTTP::Put.new(uri.path)
req.body = { "email" => self.email, "status" => 'subscribed' }.to_json
req.content_type = "application/json"
res = Net::HTTP.start(uri.hostname, uri.port) do |http|
http.request(req)
end
end
end
Before creating a new Email, it runs chimp_subscribe. Unfortunately, it breaks in the request block, with Errno::ECONNRESET, meaning that MailChimp is resetting my connection.
Am I missing some MailChimp API parameter in here? I'm struggling to find it.

The server you are requesting is HTTPS, so you should use SSL.
You should first require it:
require 'openssl'
Then make your request like this:
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
http.verify_mode = OpenSSL::SSL::VERIFY_NONE # You should use VERIFY_PEER in production
res = http.request(req)

Related

ruby code to download a file from url with basic authentication

I am new to ruby and I am learning it.
I am looking to download a file from one url(eg: https://myurl.com/123/1.zip), with basic authentication. I tried to execute the following ruby script, from windows command prompt..
require 'net/http'
uri = URI('https://myurl.com/123/1.zip')
Net::HTTP.start(uri.host, uri.port,
:use_ssl => uri.scheme == 'https',
:verify_mode => OpenSSL::SSL::VERIFY_NONE) do |http|
request = Net::HTTP::Get.new uri.request_uri
request.basic_auth 'john#test.com', 'John123'
response = http.request request # Net::HTTPResponse object
puts response
puts response.body
end
When I executed the script, I see no errors but the file isn't downloaded. Could you please kindly correct my code
You can try this:
require 'open-uri'
File.open('/path/your.file', "wb") do |file|
file.write open('https://myurl.com/123/1.zip', :http_basic_authentication => ['john#test.com', 'John123']).read
end
You were almost there. Just make use of ruby's send_data method
require 'net/http'
uri = URI('https://myurl.com/123/1.zip')
Net::HTTP.start(uri.host, uri.port,
:use_ssl => uri.scheme == 'https',
:verify_mode => OpenSSL::SSL::VERIFY_NONE) do |http|
request = Net::HTTP::Get.new uri.request_uri
request.basic_auth 'john#test.com', 'John123'
http.request(request) do |response|
send_data(response.body, filename: 'set_filename.pdf')
end
end

How to i get ruby to return json response to be used in rails controller

I'm working with an Api, so far so good i am able to send requests and receive response, but i want the ruby code to send the json response and message that can be accessible from my rails controller so that i can get simple_form to render the error or success messages and also handle redirection from the rails controller, i also want to save transaction details from the response in a model, here's my lib code
class SimplePay
require 'net/https'
require 'uri'
require 'json'
def self.pay(api_key, token, amount, amount_currency, status)
uri = URI.parse('https://checkout.simplepay.ng/v2/payments/card/charge/')
header = {'Content-Type': 'text/json'}
data = {
'token': token,
'amount': amount,
'amount_currency': amount_currency
}
http = Net::HTTP.new(uri.host, uri.port)
request = Net::HTTP::Post.new(uri.request_uri, header)
http.use_ssl = true
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
request = Net::HTTP::Post.new(uri.request_uri, header)
request.basic_auth(api_key, '')
request.set_form_data(data)
response = http.request(request)
res = JSON.parse(response.read_body)
response_code = res['response_code']
if response.kind_of? Net::HTTPSuccess
if response_code.eql? 20000
puts 'success'
else
puts 'Failed'
end
elsif status.eql? true
puts 'Success But Not Charged'
elsif status.eql? false
raise error 'Failed To Charge Card'
elsif response.kind_of? Net::HTTPBadRequest
raise error 'Failed 400'
elsif response.kind_of? Net::HTTPError
raise error 'Failed 404'
else
raise error 'Unknown Error'
end
end
end
How do i go about achieving this?
I would say send a Hash to the controller and then when you are sending it just doing a .to_json will make it into a json

HTTPBadRequest {"error_description": "Code has expired", "error": "invalid_grant"} for Oauth authentification, Ruby on Rails

I am having weird behavior of my omniauth app. Basically, I have admin panel to whom access it is required to authenticate with Yandex account.
Problem: I did everything as required in multiple guides and everything worked fine since yesterday I tried to authenticate with Yandex account and I received HTTPBadRequest error.
Note: I haven't changed a bit in my code. All my access data client_Id and password hasn't changed either.
Gemfile:
gem "omniauth-yandex"
Routes:
devise_for :users, :controllers => { :omniauth_callbacks => "callbacks" }
CallbacksController:
def yandex
require 'net/http'
require 'json' # => false
#user = User.from_omniauth(request.env["omniauth.auth"])
#client_id = Rails.application.secrets.client_id
#secret = Rails.application.secrets.password
#authorization_code = params[:code]
#user.update_attribute(:code, #authorization_code)
#user.update_attribute(:state, params[:state])
#post_body = "grant_type=authorization_code&code=#{#authorization_code}&client_id=#{#client_id}&client_secret=#{#secret}"
#url = "https://oauth.yandex.ru/token"
url = URI.parse(#url)
req = Net::HTTP::Post.new(url.request_uri)
req['host'] ="oauth.yandex.ru"
req['Content-Length'] = #post_body.length
req['Content-Type'] = 'application/x-www-form-urlencoded'
req.body = #post_body
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = (url.scheme == "https")
#response_mess = http.request(req)
refreshhash = JSON.parse(#response_mess.body)
access_token = refreshhash['access_token']
refresh_token = refreshhash['refresh_token']
access_token_expires_at = DateTime.now + refreshhash["expires_in"].to_i.seconds
if access_token.present? && refresh_token.present? && access_token_expires_at.present?
#user.update_attribute(:access_token, access_token)
#user.update_attribute(:refresh_token, refresh_token)
#user.update_attribute(:expires_in, access_token_expires_at)
sign_in(#user)
redirect_to admin_dashboard_index_path
end
end
User model:
require 'rest-client'
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable,
:omniauthable, :omniauth_providers => [:yandex]
def self.from_omniauth(auth)
where(provider: auth.provider, uid: auth.uid).first_or_create do |user|
user.provider = auth.provider
user.uid = auth.uid
user.email = auth.info.email
user.code = auth.info.code
user.state = auth.info.state
user.password = Devise.friendly_token[0,20]
end
end
def refresh_token_if_expired
if token_expired?
response = RestClient.post "https://oauth.yandex.com/token",
:grant_type => 'refresh_token',
:refresh_token => self.refresh_token
refreshhash = JSON.parse(response.body)
self.access_token = refreshhash['access_token']
self.expires_in = DateTime.now + refreshhash["expires_in"].to_i.seconds
self.save
puts 'Saved'
end
end
def token_expired?
expiry = Time.at(self.expires_in)
logger.debug "#{expiry}"
return true if expiry < Time.now
token_expires_at = expiry
save if changed?
false
end
end
Problem:
HTTPBadRequest error highlights the line in CallbacksController:
#response_mess = http.request(req)
What I have tried:
1) Restarted Rails app;
2) Deleted user from database and tried to sign in again;
3) Deleted registered app in Yandex Oauth section. Then added back again with new client_id and password.
From Yandex Oauth guide:
Exchanging an authorization code for a token
The application sends the code, along with its ID and password, in a POST request.
POST /token HTTP/1.1
Host: oauth.yandex.
Content-type: application/x-www-form-urlencoded
Content-Length: <length of request body>
[Authorization: Basic <encoded client_id:client_secret string>]
grant_type=authorization_code
& code=<authorization code>
[& client_id=<application ID>]
[& client_secret=<application password>]
[& device_id=<device ID>]
[& device_name=<device name>]
UPDATE: I am receiving this error:
{"error_description": "Code has expired", "error": "invalid_grant"}
UPDATE 2 : I tried to contact Yandex Support. I sent them brief description to my problem and link to question. But no response.
UPDATE 3:
I tried the same POST request in CHROME POSTMAN and received the same response as
{"error_description": "Code has expired", "error": "invalid_grant"}
Update 4:
I checked again all my credentials client_id and password for Yandex and they are 100% valid.
From the OAUTH 2.0 RFC:
invalid_grant
The provided authorization grant (e.g., authorization
code, resource owner credentials) or refresh token is
invalid, expired, revoked, does not match the redirection
URI used in the authorization request, or was issued to
another client.
This is further explained on the Yandex site:
The access_token could not be issued. Either the temporary authorization code was not issued by Yandex.Money, or it has expired, or an access_token has already been issued for this temporary authorization code (a duplicate request for an access token using the same temporary authorization code).
You are supplying invalid credentials to Yandex. Forget the code you've written for a moment because the only part that is failing is when it sends the data to Yandex. Yandex is telling you the data is invalid and you have confirmed this with Postman. That means this is sending invalid data:
#post_body = "grant_type=authorization_code&code=#{#authorization_code}&client_id=#{#client_id}&client_secret=#{#secret}"
So double check these things:
Is the grant_type supposed to be authorization_code?
Are you certain #authorization_code is set to a value (and not nil) and that the value is valid?
Same question for #client_id?
Same question #secret?
Are you missing a redirect_uri value?

Trying to access Basecamp API via Rails

I'm trying to access the Basecamp API through Rails, but it responds with a SocketError. My code is like this:
require 'rubygems'
require 'net/https'
http = Net::HTTP.new('https://webonise.basecamphq.com')
http.use_ssl = true
http.start do |http|
req = Net::HTTP::GET.new('/projects.xml')
req.basic_auth 'username' , 'password'
resp, data = http.request(req)
end
The response is:
SocketError: getaddrinfo: Name or service not known
Net::HTTP.new takes a hostname, not a URI, as its first argument. Try calling URI.parse to break up the URI into the parts you want first:
require 'rubygems'
require 'net/http'
uri = URI.parse("https://webonise.basecamphq.com/")
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
req = Net::HTTP::Get.new(uri.request_uri)
req.basic_auth 'username', 'password'
resp = http.request(req)
body = resp.body
You'll also have to get the body in the response from the body method.

Rails 3 getting gmail contacts using omniauth?

I am successfully login with google credentials using omniauth? omniauth is providing uid as following link
https://www.google.com/accounts/o8/id?id=xxxxxxxxxx
by using the above link is possible to get gmail contacts or their any other way to get gmail contact
No, Omniauth just provides authentication.
There is a gem that might be interesting for you: https://github.com/cardmagic/contacts
Quote: "Contacts is a universal interface to grab contact list information from various providers including Hotmail, AOL, Gmail, Plaxo and Yahoo."
Edit: Take a look at this blog post too: http://rtdptech.com/2010/12/importing-gmail-contacts-list-to-rails-application/
Get your client_id and client_secret from here. This is rough script, which works perfectly fine. Modified it as per your needs.
require 'net/http'
require 'net/https'
require 'uri'
require 'rexml/document'
class ImportController < ApplicationController
def authenticate
#title = "Google Authetication"
client_id = "xxxxxxxxxxxxxx.apps.googleusercontent.com"
google_root_url = "https://accounts.google.com/o/oauth2/auth?state=profile&redirect_uri="+googleauth_url+"&response_type=code&client_id="+client_id.to_s+"&approval_prompt=force&scope=https://www.google.com/m8/feeds/"
redirect_to google_root_url
end
def authorise
begin
#title = "Google Authetication"
token = params[:code]
client_id = "xxxxxxxxxxxxxx.apps.googleusercontent.com"
client_secret = "xxxxxxxxxxxxxx"
uri = URI('https://accounts.google.com/o/oauth2/token')
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
request = Net::HTTP::Post.new(uri.request_uri)
request.set_form_data('code' => token, 'client_id' => client_id, 'client_secret' => client_secret, 'redirect_uri' => googleauth_url, 'grant_type' => 'authorization_code')
request.content_type = 'application/x-www-form-urlencoded'
response = http.request(request)
response.code
access_keys = ActiveSupport::JSON.decode(response.body)
uri = URI.parse("https://www.google.com/m8/feeds/contacts/default/full?oauth_token="+access_keys['access_token'].to_s+"&max-results=50000&alt=json")
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
request = Net::HTTP::Get.new(uri.request_uri)
response = http.request(request)
contacts = ActiveSupport::JSON.decode(response.body)
contacts['feed']['entry'].each_with_index do |contact,index|
name = contact['title']['$t']
contact['gd$email'].to_a.each do |email|
email_address = email['address']
Invite.create(:full_name => name, :email => email_address, :invite_source => "Gmail", :user_id => current_user.id) # for testing i m pushing it into database..
end
end
rescue Exception => ex
ex.message
end
redirect_to root_path , :notice => "Invite or follow your Google contacts."
end
end
Screenshot for settings.

Resources