Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit 1306bb4
Showing
9 changed files
with
237 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
*.pyc |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,97 @@ | ||
google_contacts | ||
=============== | ||
|
||
Allows you to retrieve the contacts from the Gmail account of a user of your | ||
site, via Google's APIs. | ||
|
||
Dependencies: | ||
|
||
- gdata-python-client | ||
http://code.google.com/p/gdata-python-client/ | ||
|
||
- json_response | ||
http://www.djangosnippets.org/snippets/154/ | ||
(save this snippet in a file on your PYTHONPATH called json_response.py) | ||
|
||
- django-picklefield | ||
http://github.com/shrubberysoft/django-picklefield | ||
(save the fields.py file on your PYTHONPATH and rename it picklefield.py) | ||
|
||
Installation instructions: | ||
|
||
1. Place the google_contacts directory somewhere in your PYTHONPATH. | ||
|
||
2. Ensure that all the dependencies (listed above) are installed. | ||
|
||
3. Define the following variables in your project's settings.py file: | ||
|
||
----------------------------------------------------------------------------- | ||
|
||
GOOGLE_COOKIE_CONSENT = 'google_token_consent' | ||
|
||
(the value can be whatever you want, as long as it's a unique cookie name | ||
within your project) | ||
|
||
GOOGLE_REDIRECT_SESSION_VAR = 'google_contacts_redirect' | ||
|
||
(the value can be whatever you want, as long as it's a unique session var | ||
within your project) | ||
|
||
GOOGLE_REDIRECT_BASE_URL = 'http://localhost:8000' | ||
(should be whatever the base URL of your site is) | ||
|
||
----------------------------------------------------------------------------- | ||
|
||
4. Use code similar to the following, in the view for which you want to | ||
display the contact import functionality: | ||
|
||
----------------------------------------------------------------------------- | ||
|
||
import gdata.contacts.service | ||
|
||
from django.conf import settings | ||
from django.shortcuts import render_to_response | ||
from django.template import RequestContext | ||
|
||
from google_contacts.utils import google_get_state, google_import | ||
|
||
def test_page(request): | ||
request.session[settings.GOOGLE_REDIRECT_SESSION_VAR] = request.path | ||
|
||
google_state = google_get_state(request) | ||
gcs = gdata.contacts.service.ContactsService() | ||
google_contacts = google_import(request, gcs, cache=True) | ||
|
||
return render_to_response('test_page.html', { | ||
'google_state': google_state, | ||
'google_contacts': google_contacts | ||
}, context_instance=RequestContext(request)) | ||
|
||
----------------------------------------------------------------------------- | ||
|
||
5. Use code similar to the following, in the template for which you want to | ||
display the contact import functionality: | ||
|
||
----------------------------------------------------------------------------- | ||
|
||
{% load google_contacts %} | ||
|
||
<p> | ||
{% if google_state %} | ||
Using imported contacts from Gmail [<a | ||
href="{% google_auth_url request %}">stop using</a>] | ||
{% else %} | ||
Import contacts from <a | ||
href="{% google_auth_url request %}">Gmail</a> | ||
{% endif %} | ||
</p> | ||
|
||
{% if google_contacts %} | ||
<ul> | ||
{% for contact in google_contacts %} | ||
<li>{{ contact }}</li> | ||
{% endfor %} | ||
</ul> | ||
{% endif %} | ||
|
||
----------------------------------------------------------------------------- |
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
from uuid import uuid4 | ||
|
||
from django.contrib.contenttypes import generic | ||
from django.contrib.contenttypes.models import ContentType | ||
from django.db import models | ||
|
||
from picklefield import PickledObjectField | ||
|
||
class ActionState(models.Model): | ||
""" | ||
A temporary store for the state of a user form entry. | ||
The typical usage of this would be for an action where the user needs | ||
to leave and return to the page, for instance in an iframe-busting | ||
auth process. | ||
""" | ||
uuid = models.CharField(max_length=32, default=lambda: uuid4().hex, primary_key=True) | ||
action_type = models.ForeignKey(ContentType, null=True) | ||
action_id = models.PositiveIntegerField(null=True) | ||
action = generic.GenericForeignKey('action_type', 'action_id') | ||
data = PickledObjectField() | ||
created = models.DateTimeField(auto_now_add=True) | ||
modified = models.DateTimeField(auto_now=True) |
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
from gdata.auth import GenerateAuthSubUrl | ||
|
||
from django import template | ||
from django.conf import settings | ||
from django.core.urlresolvers import reverse | ||
|
||
from ..utils import google_get_state | ||
|
||
register = template.Library() | ||
|
||
@register.simple_tag | ||
def google_auth_url(request): | ||
state = google_get_state(request) | ||
if not state: | ||
next = '%s%s' % (settings.GOOGLE_REDIRECT_BASE_URL, reverse('google_contacts_login')) | ||
scope = 'http://www.google.com/m8/feeds/' | ||
return GenerateAuthSubUrl(next, scope, secure=False, session=True) | ||
else: | ||
return reverse('google_contacts_logout') |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
from django.conf.urls.defaults import * | ||
|
||
from views import google_get_state_token, google_login, google_logout | ||
|
||
urlpatterns = patterns('', | ||
|
||
url(r'^get-state-token/(?P<action_type_id>\d+)/(?P<action_id>\d+)/$', google_get_state_token, name='google_contacts_get_state_token'), | ||
url(r'^login/$', google_login, name='google_contacts_login'), | ||
url(r'^logout/$', google_logout, name='google_contacts_logout'), | ||
|
||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
from django.conf import settings | ||
|
||
def google_import(request, gcs, cache=False): | ||
""" | ||
Uses the given contacts service object to retrieve Google Contacts and | ||
import the entries with an email address into the contacts of the | ||
given user. | ||
Returns a list of 'contact name <contact@email>' strings. | ||
""" | ||
state = google_get_state(request) | ||
contacts = [] | ||
|
||
if state == 'authorized': | ||
if cache and request.session.get('google_contacts_cached'): | ||
return request.session.get('google_contacts_cached') | ||
|
||
gcs.SetAuthSubToken(request.session.get(settings.GOOGLE_COOKIE_CONSENT)) | ||
|
||
entries = [] | ||
feed = gcs.GetContactsFeed() | ||
entries.extend(feed.entry) | ||
next_link = feed.GetNextLink() | ||
while next_link: | ||
feed = gcs.GetContactsFeed(uri=next_link.href) | ||
entries.extend(feed.entry) | ||
next_link = feed.GetNextLink() | ||
|
||
for entry in entries: | ||
for email in entry.email: | ||
if email.primary: | ||
contact = '%s <%s>' % (entry.title.text, email.address) | ||
contacts.append(contact) | ||
|
||
if cache: | ||
request.session['google_contacts_cached'] = contacts | ||
|
||
return contacts | ||
|
||
|
||
def google_get_state(request): | ||
""" | ||
Get the current login state for the Google Contacts API. | ||
Possible states are: | ||
None - logged out | ||
authorized - logged in and consent granted | ||
""" | ||
state = None | ||
if request.session.get(settings.GOOGLE_COOKIE_CONSENT): | ||
state = 'authorized' | ||
|
||
return state |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
import gdata.contacts.service | ||
|
||
from django.conf import settings | ||
from django.shortcuts import redirect | ||
|
||
from json_response import JsonResponse | ||
from models import ActionState | ||
|
||
def google_get_state_token(request, action_type_id, action_id): | ||
action_state = ActionState.objects.create(**{ | ||
'action_type_id': action_type_id, | ||
'action_id': action_id, | ||
'data': request.GET | ||
}) | ||
return JsonResponse({'stat': 'ok', 'token': action_state.uuid}) | ||
|
||
def google_login(request): | ||
token_login = request.GET.get('token') | ||
|
||
if token_login: | ||
gcs = gdata.contacts.service.ContactsService() | ||
gcs.SetAuthSubToken(token_login) | ||
gcs.UpgradeToSessionToken() | ||
request.session[settings.GOOGLE_COOKIE_CONSENT] = gcs.GetAuthSubToken() | ||
|
||
return redirect(request.session.get(settings.GOOGLE_REDIRECT_SESSION_VAR)) | ||
|
||
|
||
def google_logout(request): | ||
if request.session.get(settings.GOOGLE_COOKIE_CONSENT): | ||
del request.session[settings.GOOGLE_COOKIE_CONSENT] | ||
if request.session.get('google_contacts_cached'): | ||
del request.session['google_contacts_cached'] | ||
return redirect(request.session.get(settings.GOOGLE_REDIRECT_SESSION_VAR)) |