I need some help with Google integration.
I need to create google contacts through the Google Contacts API but all the gems I can find only gets the contents and it also seems like the Google Contacts API doesn't support JSON posts, only xml/atom.
This is what I have
Gemfile
gem 'google-api-client'
google_contacts_controller.rb
require 'google/apis/people_v1'
require 'google/api_client/client_secrets'
class GoogleContactsController < ApplicationController
def auth
client_secrets = Google::APIClient::ClientSecrets.load('app/controllers/google_contacts/client_secret.json')
auth_client = client_secrets.to_authorization
auth_client.update!(
:scope => 'https://www.google.com/m8/feeds/',
:redirect_uri => 'http://localhost:3000/google_contacts/auth')[]
if request['code'] == nil
auth_uri = auth_client.authorization_uri.to_s
redirect_to auth_uri
else
auth_client.code = request['code']
auth_client.fetch_access_token!
auth_client.client_secret = nil
_auth_client(auth_client)
redirect_to action: 'sync_contacts'
end
end
def sync_contacts
unless session.has_key?(:credentials)
_auth_client
unless session.has_key?(:credentials)
redirect action: 'auth'
end
end
client_opts = JSON.parse(session[:credentials])
auth_client = Signet::OAuth2::Client.new(client_opts)
people_service = Google::Apis::PeopleV1::PeopleServiceService.new
people_service.authorization = auth_client
response = people_service.list_person_connections('people/me', request_mask_include_field: %w'person.names', page_size: 10,)
remote_name_arry = response.connections.map{|person| person.names[0].display_name}
redirect_to action: 'done', message: 'Synced Contacts'
end
def done
#message = params[:message]
end
private
def _auth_client(auth_client=nil)
if auth_client
credentials = GoogleContactCredential.new
credentials.authorization_uri = auth_client.authorization_uri
credentials.token_credential_uri = auth_client.token_credential_uri
credentials.client_id = auth_client.client_id
credentials.scope = "[#{auth_client.scope.join(', ')}]"
credentials.redirect_uri = auth_client.redirect_uri
credentials.expiry = auth_client.expiry
credentials.expires_at = auth_client.expires_at
credentials.access_token = auth_client.access_token
if credentials.save
session[:credentials] = credentials.to_json
end
else
credentials = GoogleContactCredential.first
if credentials.present?
session[:credentials] = credentials.to_json
end
end
credentials
end
end
This all works fine and I am able to get all of my contacts but I can not find a way with this gem or another gem or JSON to create contacts.
Is there anybody that has had this issue and can please point me in the right direction.
UPDATE
I have also tried using the google_contacts_api gem to no success.
Here is what I have
Gemfile
gem 'google_contacts_api'
google_contacts_controller.rb
def sync_contacts
unless session.has_key?(:credentials)
_auth_client
unless session.has_key?(:credentials)
redirect action: 'auth'
end
end
client_opts = JSON.parse(session[:credentials])
auth = OAuth2::Client.new(client_opts['client_id'], client_opts['client_secret'], client_opts)
token = OAuth2::AccessToken.new(auth, client_opts['access_token'])
google_contacts_user = GoogleContactsApi::User.new(token)
contacts = google_contacts_user.contacts
contact = contacts.first
logger.info contact.title
new_group = google_contacts_user.create_group('New group')
redirect_to action: 'done', message: 'Synced Contacts'
end
Everything works fine until this line (which I got out of the example supplied for the gem):
new_group = google_contacts_user.create_group('New group')
Then I get this line exception:
undefined method `create_group' for #<GoogleContactsApi::User:0x007ff2da2291b8>
Can someone spot my mistake I made?
Also, how would I proceed to create contacts as I can not seem to find documentation or posts on actually creating and updating contacts, I thought maybe I would have to create a group and then I can add contacts to the group but as I can not manage to create a group I can not test that theory.
Please point me in the right direction
The Google People API is read-only and can't be used to update or add new contacts. For that, you need to use the Google Contacts API which is, unfortunately, not supported by the google-api-client gem.
To access the Google Client API, you can try using this gem:
google_contacts_api
If you run into trouble setting it up, check out this stackoverflow question:
access google contacts api
It has a helpful answer written by the same person who wrote the gem.
EDIT
It looks like development on the google_contacts_api gem stopped before functionality for creating contacts was added. I'm looking through the various gems on Github and they're all in states of disrepair / death.
As much as it pains me to say it, your best bet might be to access Google Contacts directly via their web API.
Best of luck and sorry for the disheartening answer.
Related
I am working on a project to do CRUD Operations to firebase. I made use of this to help facilitate and link my ruby project to firebase.
Functions:
def delete_firebase(event_params,rootpath="Events/")
query = init_firebase.delete(rootpath,event_params)
end
def new_firebase(event_params,rootpath="Events")
query = init_firebase.push(rootpath,event_params)
end
def init_firebase # Inits firebase project with URL and secret
firebaseURL = "myfirebaseprojecturl"
firebaseSecret = "myfirebasesecret"
firebase = Firebase::Client.new(firebaseURL, firebaseSecret)
end
Event params consist of my event parameters as shown below
def event_params
params.require(:event).permit(:eventID, :eventName, :attachment, :eventNoOfPpl, :eventAdminEmail, {eventpics: []})
end
I encountered an issue. When I push with push() into firebase, there is a random key like -LSFOklvcdmfPOWrxgBo. In such case, the structure of the document would look like this:
But I cannot delete anything from -LSFOklvcdmfPOWrxgBo as I do not have the value. I used delete() from Oscar's firebase-ruby gem. I would appreciate any help with this issue.
I re-read the gem docs, and got some help from my friends and came up with two solutions
The body's response has response.body # => { 'name' => "-INOQPH-aV_psbk3ZXEX" } and thus, you're able to find out the name if you'd like
Change the index, and don't use .push, instead I made use of .set and did a random number for every event
Final solution
def load_firebase(root_path = "Events")
firebase_json = init_firebase.get(root_path)
if valid_json?(firebase_json.raw_body)
#json_object = JSON.parse(firebase_json.raw_body)
end
end
def update_firebase(event_params, root_path = "Events/")
init_firebase.update("#{root_path}#{event_params["eventID"]}", event_params)
end
def delete_firebase(event_params, root_path = "Events/")
init_firebase.delete("#{root_path}#{event_params["eventID"]}")
end
def save_firebase(event_params, root_path = "Events/")
init_firebase.set("#{root_path}#{event_params["eventID"]}", event_params)
end
Just as I thought that I "hacked" this ... I realize that I don't understand it anyway.
Important note:
I want to use "server-to-server approved" access so I can avoid Google's crazy approval nightmare for all operations on google drive. My users hate having to approve the script actions on every new copy of my master spreadsheet that we create.
I am trying to use DriveV3 - gem 'google-api-client', '0.9.11'
And I am trying to get authentication working.
I have managed all the initial setup of both console.xxx.xx and admin.google.xxx
So now I have a .p12 file with a Server-to-server approved credentials.
The following code has been used to get a service:
def self.service_client
keypath = Rails.root.join('config','xxxxxxxx.p12').to_s
#client = Google::Apis::DriveV3::DriveService.new
#client.client_options.application_name = "Rails2"
#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/drive",
:issuer => "rails2#autoa-automations.iam.gserviceaccount.com",
:signing_key => Google::APIClient::KeyUtils.load_from_pkcs12(keypath, "yyyy"))
#client.authorization.fetch_access_token!
end
I did this in my before_filter:
session[:google_token] = GoogleDrive::GoogleDocs.service_client
And then use it something like ...
def list_google_docs
gtoken = session[:google_token]
google_session = Google::Apis::DriveV3::DriveService.new
google_session.authorization = gtoken
#google_docs = []
page_token = nil
begin
(myfiles, page_token) = google_session.list_files(page_size: 10, q: "'MYROOTFOLDERID' in parents", fields: 'files(id, mimeType, name), nextPageToken')
#for file in google_session.drive.list_files(page_size: 10, fields: 'nextPageToken, files(id, mime name)')
myfiles.files.each do |file|
filename = file.name
if filename.include?('body')
#google_docs << filename
end
end
end while page_token
end
But I keep getting
dailyLimitExceededUnreg: Daily Limit for Unauthenticated Use Exceeded. Continued use requires signup.
It worked initially ...
Anyone who can help?
I simply don't get the hole Google authentication approach ... I have tried a lot but this is too complicated for me ...
Hi I am wondering how to get user posts insights from Facebook API Koala Gem.
I only found solutions that works for facebook page posts but not user posts.
I used the code below for user posts but it just returns empty array.
#graph.get_connections('me', 'insights', metric: 'page_impressions', period: 'now')
UPDATE
user = Authentication.where(user_id: current_user.id, provider: "facebook").first
oauth_access_token = user.token
#graph = Koala::Facebook::API.new(oauth_access_token)
#posts = #graph.get_connection('me', 'posts',{ fields: ['id', 'message', 'link', 'name', 'description', "likes.summary(true)", "shares", "comments.summary(true)"]})
The code above works fine, but when I try to get post insights, it returns empty array.
If your using omniauth-facebook gem you just have to make sure you have the right permissions in your scope and you can use the original query.
config/initializers/omniauth.rb
OmniAuth.config.logger = Rails.logger
Rails.application.config.middleware.use OmniAuth::Builder do
provider :facebook, {id}, {secret},
:scope => 'email,manage_pages,read_stream,read_insights'
end
Also, you can get post insights for a page via koala. This worked for me.
m = Koala::Facebook::API.new(User.find(5).oauth_token)
m = m.get_connections('me', 'accounts')
m = m.first['access_token']
#post_graph = Koala::Facebook::API.new(m)
#feed = #post_graph.get_connection('me', 'feed')
#postid = #feed.first['id']
#post_data = #post_graph.get_connections(#postid, 'likes', since: "2015-05-17", until: "2015-07-17")
https://github.com/arsduo/koala/wiki/Acting-as-a-Page
https://developers.facebook.com/docs/graph-api/reference/v2.3/post
If you check here at 'Edges' you can see that /insights are available only for Pages.
'/insights Insights for this post (only for Pages).'
I hope I am right and helped you.
Here you can see it is only for pages post
/{post-id}/insights (where this is a Page post)
I am using pengwynn linkedIn gem in my rails project. How do I follow a company given the company id.
I have written the following code, but it is not working.
client = LinkedIn::Client.new('consumer_key', 'consumer_secret')
rtoken = client.request_token.token
rsecret = client.request_token.secret
client.request_token.authorize_url
=> "https://api.linkedin.com/uas/oauth/authorize?oauth_token=<generated_token>"
client.authorize_from_request(rtoken, rsecret, pin)
client.company(:id => <company_id>).follow
Any idea why it is not working or any other solution?
If you're using linkedin gem 0.3.x, it doesn't have a method to follow a company.
It could be added in 2-0-stable branch.
Then I've same task, I just fork gem and add follow_company method to /lib/linked_in/api/update_methods.rb
def follow_company(company_id)
path = "/people/~/following/companies"
post(path, {id: company_id}.to_json ,"Content-Type" => "application/json")
end
I am working on integrating Omniauth with my new Facebook application, and I am looking through the rather sparse documentation to understand if it gives simple ways to access the graph API... I am moving from Koala which was pretty simple.
Has anyone out there used Omniauth for this yet? I want to get photos from the users' albums, and sort and get the unique URLs for them.
I finally found out:
1) include this gem
2) use the gem:
user = FbGraph::User.new('me', :access_token => session[:omniauth]["credentials"]["token"])
user.fetch
3) retrieve your information
user.name
Remember you can get anything from here ttp://developers.facebook.com/docs/reference/api/user
Another good option is Koala: https://github.com/arsduo/koala
If you're just using Facebook, Koala has its own OAuth support. It also works fine with OmniAuth. To use them together, set up OmniAuth per this Railscast:
http://railscasts.com/episodes/235-omniauth-part-1
Then add a 'token' column to 'authentications' table, and any supporting methods for retrieving tokens. When the app needs to interact with Facebook, let Koala grab the token and do its thing. In a controller:
if #token = current_user.facebook_token
#graph = Koala::Facebook::GraphAPI.new(#token)
#friends = #graph.get_connections("me", "friends")
end
First, I would go for fb_graph, just compare:
with koala:
graph = Koala::Facebook::GraphAPI.new OAUTH_ACCESS_TOKEN
friends = graph.get_connections("me", "friends")
graph.put_object("me", "feed", :message => "I am writing on my wall!")
with fb_graph:
me = FbGraph::User.me OAUTH_ACCESS_TOKEN
my_friends = me.friends
me.feed! :message => "I am writing on my wall!"
When using omniauth, every user has many authorizations (facebook, twitter, ...)
For each user authorization, you should store the oauth token that is returned in your oauth callback hash.
auth = Authorization.create!(:user => user,
:uid => hash['uid'],
:provider => hash['provider'],
:token => hash['credentials']['token'])
Then wherever you want to access albums and photos, do something like this:
class User
...
has_many :authorizations
...
def grap_facebook_albums
facebook = authorizations.where(:provider => :facebook).first
fb_user = ::FbGraph::User.fetch facebook.uid, :access_token => facebook.token
fb_albums = fb_user.albums
end
...
end
So I wasn't able to get fb_graph to work properly - I am still a noob having been a Ruby On Rails developer for a total of about 8-10 weeks, and therefore don't have an instinct for what must be obvious problems to other folks.
However I found this great little blog post which outlines a simple facebook client and shows clearly how it all plugs together. I found an issue with it picking up the me/picture object as Facebook returns an http302 not http200 but that was easily worked around with the help of the author. Check it out: http://bnerd.de/misc/ruby-write-basic-client-for-facebook-graph-api/
I am now using Omniauth for the simplicity of the login/signup interaction based on this walkthrough here: blog.railsrumble.com/blog/2010/10/08/intridea-omniauth and with the token I get from that I am using this simple FBClient from the bnerd reference above to access the Graph API. Hope what I found helps others.
...here's my version of bnerd's code and it worked for me:
class FBClient
def initialize(app, access_token = nil)
#app = app
#access_token = access_token
end
# request permission(s) from user
def request(perms)
#create a random verifier to identify user on fb callback
verifier = (0...10).map{65.+(rand(25)).chr}.join
uri = "https://graph.facebook.com/oauth/authorize?client_id=#{#app.app_id}&redirect_uri=#{#app.connect_url}?verifier=#{verifier}&scope=#{perms}"
request = { :verifier => verifier, :uri => uri }
return request
end
def connect(code, verifier)
uri = URI.parse("https://graph.facebook.com/oauth/access_token?client_id=#{#app.app_id}&redirect_uri=#{#app.connect_url}?verifier=#{verifier}&client_secret=#{#app.secret}&code=#{CGI::escape(code)}")
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
request = Net::HTTP::Get.new(uri.path + "?" + uri.query)
response = http.request(request)
data = response.body
return data.split("=")[1]
end
# get, post
def get(path, params = nil)
uri = URI.parse("https://graph.facebook.com/" + path)
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
if params.nil?
params = Hash.new
end
if params["access_token"].nil?
params["access_token"] = #access_token unless #access_token.nil?
end
request = Net::HTTP::Get.new(uri.path)
request.set_form_data( params )
request = Net::HTTP::Get.new(uri.path + "?" + request.body)
return response = http.request(request)
end
def post(path, params = nil)
uri = URI.parse("https://graph.facebook.com/" + path)
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
if params.nil?
params = Hash.new
end
if params[:access_token].nil?
params[:access_token] = #access_token unless #access_token.nil?
end
request = Net::HTTP::Post.new(uri.path)
request.set_form_data( params )
request = Net::HTTP::Post.new(uri.path + "?" + request.body)
response = http.request(request)
response.code == "200" ? feed = JSON.parse(response.body) : raise("Sorry, an error occured. #{response.body}")
return feed
end
end
I am sure someone more experienced than I could improve this - I was about 10 weeks into learning Ruby (and my first programming since Fortran and Pascal at university in the early 90s!).
I also had problems getting the devise+Omniauth solution to work. I had to problems:
The session cookie did not store the facebook authentication token that is necessary to initialize fb_graph and koala.
I was unable to initialize fb_graph after getting the facebook authentication token in place (but got Koala to work after some work).
I solved #1 by inserting 'session[:omniauth] = omniauth' into the create method of the authentications_controller.rb.
I solved #2 by using Koala. Seem like fb_graph requires oauth2, and the devise omniauth integration use oauth. Koala works with perfectly with the facebook authentication token stored by session[:omniauth]["credentials"]["token"].
You initialize koala like this:
- #fbprofile =
Koala::Facebook::GraphAPI.new(
session[:omniauth]["credentials"]["token"]
)
I made sure oauth and oauth2 were uninstalled, and then I installed oauth2. It appears that now omniauth and fb_graph are working ... but probably need to test it more.