Few days ago I released the first version of OmniContacts.
As it says in the README:
Inspired by the popular OmniAuth, OmniContacts is a library that enables users of an application to import contacts from their email accounts. The current version allows to import contacts from the three most popular web email providers: Gmail, Yahoo and Hotmail. OmniContacts is a Rack middleware, therefore you can use it with Rails, Sinatra and with any other Rack-based framework.
While working on CueCup I faced a problem shared by many web projects: I did not have much users.
I said to myself: What is the best way the find new users? Let the current users do the job for you!
With OmniContacts, users can invite their e-mail contacts to join the website.
Unfortunately, after few months of running OmniContacts in production I still do not have that many users :(
My consolation is that I produced something I could share with the Ruby Community! Considering I could not find many alternatives, if not paid services, I think the gem have some value and I hope it can help others in achieving what I could not.
I will not go into the details of how the gem works since there is a README for that!
If you encounter any problem using them gem or you have any idea about how to improve it, just comment on this post or create an issue for it.
Personally I loath this feature, but all my clients seem to think it is the holy grail for getting new users.
ReplyDeleteKeep up the good work. The more chatter in more places about your app, the more success you will eventually have.
Thanks
Hi Bill,
DeleteThanks for your feedback and thanks for the pull request!
Diego
I've been seriously frustrated with the contacts gem and the turing-contacts gem. I'm rooting for your solution to help me end this nightmare! last chance before i go at it alone :D
ReplyDeleteAnto
Hi diego,
ReplyDeleteI'm trying to figuring out how it works your gem, which is cool btw, can you explain me a little bit how can I integrate this with my application, I already install the gem, create the initializers, also i registered the app with the providers, but how can I test this features from my console.
Thanks in advance!
Hi Jonathan,
ReplyDeleteHave you used OmniAuth before? I ask you this because OmniContacts works in a very similar way.
I suggest you to watch this screencast about OmniAuth, which will surely clarify your ideas: http://railscasts.com/episodes/241-simple-omniauth
Let me know if this helps.
Diego
Hi diego,
ReplyDeleteWell, when I redirect a user to /contacts/:importer (yahoo/hotmail) doesn't redirect to an authorization page instead I got an error, with yahoo I got an internal error and with hotmail I got 'The provided value for the input parameter 'redirect_uri' is not valid.'
I'm testing from my local machine, could this be the problem?.
I would appreciate if you could help me with that.
The fact you are testing from your local machine is the reason Hotmail does not work. I know it is ridiculous, but unfortunately this is Microsoft :)
ReplyDeleteRegarding Yahoo, when you register your app you have to configure the relative permissions. Did you select the read permissions for the user's contact list?
Hi diego,
DeleteFinally, I have tested on a staging-server, it looks good, now the app redirects me to hotmail and ask me for my permissions, but once I allow the app to acces my info, how can I retrieve the contacts?, I meant, how can I acces that info. can't understand how do you do that in your explanation ;).
Thanks a lot man, nice job!
Hi Jonathan,
DeleteIn routes.rb you need to register the callback action to be invoked. Something like this:
match "/contacts/:importer/callback" => "invitations#contacts_callback"
Once the user authorizes your app he will be redirected to the callback's path. You can then access the list of contacts through the request object:
def contacts_callback
@contacts = request.env['omnicontacts.contacts']
puts "List of contacts obtained from #{params[:importer]}:"
@contacts.each do |contact|
puts "Contact found: name => #{contact[:name]}, email => #{contact[:email]}"
end
end
Let me know if this works,
Diego
Diego,
DeleteI already did that, the thing is that this line:
@contacts = request.env['omnicontacts.contacts']
does not retrieve me anything. ;(
it retrieves nil.
and for some reason i got a "not_authorized" error.
it still missing another configuration?
Sorry for all these questions, thanks for your help ;)
Hi Diego, thanks for your Gem, it's really helpfull to my app.
Deletebut I'm having the same issue that Jonathan has with hotmail, I tested with 3 hotmail accounts and i'm getting the same error message "not_authorized", I follow all the setup steps on Github and test in this url: http://alkiller.heroku.com/contacts/hotmail , it looks like in the callback action the request.env["omnicontacts.contacts"] always return nil.
maybe there is any missing configuration
Att:
Lumir Olivares
Hi Jonathan,
DeleteIs it only Hotmail not working? Does Gmail or Yahoo works?
Are you running on Windows? Does your log provides additional info?
The strange thing is that if you get get not_authorized than you should be redirected to /contacts/failure. The callback action should not be called, so it is not possible that request.env["omnicontacts.contacts"] since that code should not execute at all.
Diego
Hi Diego, I'm using this gem only to get the contacts from Hotmail and it's running on Mac.
Deletewhen i go to the path /contacts/hotmail then it show me the windows live login page, then it redirect me to the contacts/failure?error_message=not_authorized path, also the log show this error:
undefined method `each' for nil:NilClass in the next line in the callback action:
@contacts.each do |contact|
thanks for your help, :)
Att:
Lumir Olivares
Hi Lumir,
DeleteCan you paste the log starting from the request to /contacts/hotmail?
Diego
sure,
Delete2012-04-13T19:52:11+00:00 app[web.1]: Started GET "/contacts/hotmail" for 190.242.128.66 at 2012-04-13 12:52:11 -0700
2012-04-13T19:52:11+00:00 heroku[router]: GET alkiller.heroku.com/contacts/hotmail dyno=web.1 queue=0 wait=0ms service=412ms status=302 bytes=0
2012-04-13T19:52:11+00:00 heroku[nginx]: 190.242.128.66 - - [13/Apr/2012:19:52:11 +0000] "GET /contacts/hotmail HTTP/1.1" 302 0 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_8) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.151 Safari/535.19" alkiller.heroku.com
2012-04-13T19:53:30+00:00 heroku[router]: GET alkiller.heroku.com/contacts/failure?error_message=not_authorized dyno=web.1 queue=0 wait=0ms service=27ms status=500 bytes=728
2012-04-13T19:53:30+00:00 app[web.1]:
2012-04-13T19:53:30+00:00 app[web.1]:
2012-04-13T19:53:30+00:00 app[web.1]: app/controllers/alkilers_controller.rb:14:in `new'
2012-04-13T19:53:30+00:00 app[web.1]: NoMethodError (undefined method `each' for nil:NilClass):
2012-04-13T19:53:30+00:00 heroku[nginx]: 190.242.128.66 - - [13/Apr/2012:19:53:30 +0000] "GET /contacts/failure?error_message=not_authorized HTTP/1.1" 500 728 "http://alkiller.heroku.com/users/sign_in" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_8) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.151 Safari/535.19" alkiller.heroku.com
Lumir
Looks really strange. It is like there is some sort of redirection within your server itself.
DeleteI see two lines of log for each request. Once points to 190.242.128.66 and the second to alkiller.heroku.com/
Is there anything worth mentioning about your network configuration?
Could you access /contacts/hotmail?q=anything and show the log only for the request? I want to see if the parameters get lost during the redirection.
still the same error message on the callback action, but now also show that the user did not grant access to contact lists
Delete2012-04-13T21:07:33+00:00 app[web.1]: Started GET "/alkilers/new?code=40782e26-6ffd-38d6-1316-d7b6a17aa5c3" for 190.242.128.66 at 2012-04-13 14:07:33 -0700
2012-04-13T21:07:33+00:00 heroku[router]: GET alkiller.heroku.com/alkilers/new?code=40782e26-6ffd-38d6-1316-d7b6a17aa5c3 dyno=web.1 queue=0 wait=0ms service=2ms status=302 bytes=0
2012-04-13T21:07:33+00:00 heroku[nginx]: 190.242.128.66 - - [13/Apr/2012:21:07:33 +0000] "GET /alkilers/new?code=40782e26-6ffd-38d6-1316-d7b6a17aa5c3 HTTP/1.1" 302 0 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_8) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.151 Safari/535.19" alkiller.heroku.com
2012-04-13T21:07:34+00:00 app[web.1]: Error not_authorized while processing /alkilers/new: User did not grant access to contacts list
2012-04-13T21:07:34+00:00 app[web.1]: "List of contacts obtained from failure:"
2012-04-13T21:07:34+00:00 app[web.1]:
2012-04-13T21:07:34+00:00 app[web.1]: NoMethodError (undefined method `each' for nil:NilClass):
2012-04-13T21:07:34+00:00 app[web.1]: app/controllers/alkilers_controller.rb:14:in `new'
2012-04-13T21:07:34+00:00 app[web.1]:
2012-04-13T21:07:34+00:00 app[web.1]:
2012-04-13T21:07:34+00:00 heroku[nginx]: 190.242.128.66 - - [13/Apr/2012:21:07:34 +0000] "GET /contacts/failure?error_message=not_authorized HTTP/1.1" 500 728 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_8) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.151 Safari/535.19" alkiller.heroku.com
2012-04-13T21:07:34+00:00 heroku[router]: GET alkiller.heroku.com/contacts/failure?error_message=not_authorized dyno=web.1 queue=0 wait=0ms service=39ms status=500 bytes=728
Lumir Olivares
Hi Lumir,
DeleteBefore the callback was /contacts/hotmail/callback but now I see /alkilers/new. What have you changed in the configuration?
Can you show the initializer file? Can you also include the snippet of routes.rb relative to your callback?
Diego
Hi diego, it seems that Lumir has the same Problem.. I've do the same things, this is mi initializer file, check it out:
Deleteimporter :yahoo, "dj0yJmk9aXdiNHJHbTFZU1hKJmQ9WVdrOU5reFBkVlJoTkhVbWNHbzlNakEwTmpZeU5URTJNZy0tJnM9Y29uc3VtZXJzZWNyZXQmeD1jNw--", "828411bd3a77eec72715ad53e297aabe8ddf5a1a", {:callback_path => '/users/:id/contacts'}
importer :hotmail, "00000000480A726F", "xKS53APtkLLZ-xOdHdQezAcr-tBRHzrJ", {:redirect_path => '/callback'}
end
those ids are from my apps on each provider.
and these are my routes:
match "/contacts/:importer" => "invitations#new"
match "/contacts/:importer/callback" => "users#contacts"
it shows me that the user did not grant access to contact lists.
and retrieves me nil.
Thanks for your help!
Hi Jonathan,
DeleteI see something strange in your config. The callback for Hotmail is /callback but I do not see any controller registered for that path.
Can you try leaving the default setting? You can do this by only configuring client_id and callback_id:
:hotmail, "00000000480A726F", "xKS53APtkLLZ-xOdHdQezAcr-tBRHzrJ"
Then in your routes.rb try add this line:
match "/contacts/:importer/callback" => "invitations#new"
This should work :)
Diego
This looks great. I will try it out and see how it does! thanks alot.
ReplyDeleteThanks, I used your gem for Sandglaz.com. It works nicely, a few things that I ran across though:
ReplyDelete- For hotmail, I noticed that the contacts that do get imported are the ones that don't have any names. I saw your comment in the README "Their API returns a Contact object, which does not contain an e-mail field! However, if the contact has either name, family name or both set to null, than there is a field called name which does contain the e-mail address. To summarize, a Hotmail contact will only be returned if the name field contains a valid e-mail address, otherwise it will be skipped. "
I didn't dig in to debug it, but it's hard to believe that this is the behaviour of their api. I thought I read somewhere that it returns a hash of multiple e-mails addresses per contact. Maybe when I have time, I'll dig in.
- For testing it would be nice if it had some mock helpers like omniauth.
Thanks again for sharing the gem! It sure helped.
Hi Nada,
Deletethanks for your feedback.
Being the multiple e-mails addresses represented as a hash, they cannot be decoded to their original value. It sounds absurd but I really think Hotmail API works like this :(
To be honest I would not be too surprised, the fact you cannot test on localhost represents another weird limitation.
Regarding testing, thanks for the suggestion! I will have probably add mocks in the following version.
Diego
Hi Nada,
DeleteI created an issue for this: https://github.com/Diego81/omnicontacts/issues/8
Will soon start working in it.
Btw, thanks for your pull request!
Diego
Hi Diego, i'm having problems with your GEM...
ReplyDeleteMy code is like this...
initializer...
require "omnicontacts"
Rails.application.middleware.use OmniContacts::Builder do
#importer :gmail, "client_id", "client_secret", {:redirect_path => "/oauth2callback", :ssl_ca_file => "/etc/ssl/certs/curl-ca-bundle.crt"}
importer :yahoo, "dj0yJmk9TUtDckMzRFJqaURWJmQ9WVdrOVJtUTBka1JrTm5FbWNHbzlPRFUyTURRM09EWXkmcz1jb25zdW1lcnNlY3JldCZ4PWVj", "9fb4a1d3de38d6fcbeecbf8edd5755136724b348", {:callback_path => '/oc_callbacks/callback'}
importer :hotmail, "00000000440BD228", "0mV1JfA4VERiDJxz4emcf8ZxPsXPC0aD"
end
routes...
# omnicontacts controller
match 'oc_callbacks/callback', :to => 'oc_callbacks#callback'
match 'contacts/:provider', :to => 'invitations#new'
match 'contacts/:provider/callback', :to => 'oc_callbacks#callback'
callbacks controller...
# oc_callbacks_controller
class OcCallbacksController < AdminController
def callback
@contacts = request.env['omnicontacts.contacts']
puts "List of contacts obtained from #{params[:importer]}:"
@contacts.each do |contact|
puts "Contact found: name => #{contact[:name]}, email => #{contact[:email]}"
end
render :text => request
end
end
it returns correctly with yahoo and hotmail, but it's allways empty the contacts array...
What am i doing wrong??
Thanks!!
Sorry, but also, when i try with gmail, it always return failed and not_authorized :S
ReplyDeleteJavi, your code looks fine.
ReplyDeleteHowever, you can remove match 'contacts/:provider', :to => 'invitations#new' from your routes.rb. This is because OmniContacts will serve the request by itself and redirect the user to the email provider's website.
For Yahoo, have you configured the contacts permission for your application on the Yahoo website?
For Hotmail, it is possible all your contacts have both name and family name. In that case you would get no result. To know if this is true you could debug line 31 of lib/omnicontacts/importer/hotmail.rb
For Google, could you provide some additional info? Maybe some of your logs?
Diego
I have the same problem. My code is excatly as in the readme file or as the example Javi provided, and every thime I try to use google I get "not_authorized" error.
ReplyDeleteSome of the logs:
Started GET "/gmail_contacts/import?token=1%HtvN8WpdRwhghghfgsdfgrewt4cxvbmmn8" for 127.0.0.1 at 2012-06-11 10:33:30 +0200
Started GET "/contacts/failure?error_message=not_authorized" for 127.0.0.1 at 2012-06-11 10:33:31 +0200
Processing by GmailContactsController#failure as HTML
Parameters: {"error_message"=>"not_authorized"}
User Load (0.5ms) SELECT "users".* FROM "users" WHERE "users"."id" = 173746 LIMIT 1
Candidate Load (0.6ms) SELECT "candidates".* FROM "candidates" WHERE "candidates"."id" = 170251 LIMIT 1
Redirected to http://devmyhost.com/
Completed 302 Found in 101ms (ActiveRecord: 9.6ms)
Your log looks very strange. How come you have a token parameter in the GET request in place of the code parameter? Are you being redirected to the Google site? How does your routes.rb looks like?
DeleteThis comment has been removed by the author.
ReplyDeleteThis is good gem. It's easy to use. I have create a sample on github: https://github.com/khanhnguyen/omnicontacts_example. Thanks Diego. Great work!
ReplyDeleteHi Khanh, thanks a lot!
DeleteThanks Diego for putting up such a gem, and Khanh for putting a example to illustrate the usage.
DeleteHey Diego,
ReplyDeleteThank you for this excellent gem. You just ended 8 hours of digging with a quick 30 minute implemenation.
Here's a question: we already have a refresh_token from Google, with the scope for contacts (we're using OmniAuth). Do you think it's possible we can use our token to get contacts via omnicontacts without asking the user to re-authorize?
Best,
Galen
Hi Galen,
ReplyDeleteWith current implementation of OmniContacts I don't think that's possible but I have not tried that yet. You can try and modify the code yourself. If you need any help, just let me know.
Regards,
Diego
Thanks Diego. Will let you know how we proceed.
ReplyDeleteHi diego. I also have a problem with hotmail on my local machine. I read somewhere that I had to configure my hosts file and so I added this line:
ReplyDelete127.0.0.1 testserver.com
and I checked that it worked when I typed it on my server. However, I was still getting "redirect_uri invalid" error page from hotmail. I added http://testserver.com/contacts/hotmail/callback as redirect url in my microsoft app settings and in omnicontacts.rb I had
importer :hotmail, "0000000000000000", "xxxxxxxxxxxxxxxxxxx", {:redirect_path => '/contacts/hotmail/callback'}
Did I do something wrong? Do you have any ideas?
Very useful gem Diego, thanks a lot. I forked the project because I needed specifically the given name and family name. Not sure if that is something any other people would consider useful.
ReplyDeleteCheers,
Fede
Hello Diego, I have one issue about the callback of omnicontacts. I have a view /shares/new?share_type=yahoo and I use this route like a callback for yahoo "/shares/new?share_type=yahoo" but when I realice the authentication process omnicontacts return a callback with the authentication token params and here is where I have trouble cause the callback_path have a params and omnicontacts concat the rest of url like :
ReplyDelete/shares/new?share_type=yahoo/callback?oauth_token=b9uhe3t&oauth_verifier=atujsv
and this doesn't will match anything.
Shall you help me with that ?
by Luis Gutierrez
Hello Diego, I have some problem with yahoo in production,but it is working fine in development(local) this is not working in production. but when I realice the authentication process omnicontacts return a callback with the authentication token params and here is where I have trouble cause the callback_path have a params and omnicontacts concat the rest of url like :
ReplyDelete/contacts/yahoo/callback?oauth_token=bptttar&oauth_verifier=n5bmax
then this is redirecting this url /contacts/failure?error_message=internal_error
but at development it is working fine.
Please guide me what i can do?
HI Luis David Gutierrez Molina,
ReplyDeleteDid you get solution for yahoo contacts, i have also same issue having. please let me know if you get this.