Access google analytics data with Django - django

I'm trying to build a super simple dashboard to show to users their Google Analytics data well formatted.
I'm using oAuth2Client and Django 1.10.4 and Python 3.5.
I've followed the example within the documentation and now I have a very simple app, the landing page will ask you to login, you click on a link to authorise, the Google page loads and asks you if you want to share your GA data and if you accept you are redirect to a page you can see only if you are logged in. All good so far.
However I can't manage to actually get users data, what's the best way to get for example the list of properties in a user's account or even better the number of page views a property had in the last week?
This is my code so far:
/pools/models.py
from django import http
from oauth2client.contrib.django_util import decorators
from django.views.generic import ListView
# from polls.models import GoogleAnalytic
from django.http import HttpResponse
# Google Analytics
from apiclient.discovery import build
# def index(request):
# return http.HttpResponse("Hello and Welcome! </br> </br> Click <a href='/profile_enabled'> here</a> to login")
#decorators.oauth_required
def get_profile_required(request):
resp, content = request.oauth.http.request(
'https://www.googleapis.com/plus/v1/people/me')
return http.HttpResponse(content)
#decorators.oauth_enabled
def get_profile_optional(request):
if request.oauth.has_credentials():
# this could be passed into a view
# request.oauth.http is also initialized
return http.HttpResponse('You are signed in.</br> </br>'+'User email: {}'.format(
request.oauth.credentials.id_token['email']) + "</br></br>Click <a href='/ga'> here </a> to view your metrics")
else:
return http.HttpResponse(
'Hello And Welcome!</br></br>'
'You need to sign in to view your data. </br></br>' +
'Here is an OAuth Authorize link:Authorize'
.format(request.oauth.get_authorize_redirect()))
########## MY CODE! ###############
#decorators.oauth_required
def google_analytics(object):
return HttpResponse('These are your results for last week:')
urls.py
from django.conf import urls
from polls import views
import oauth2client.contrib.django_util.site as django_util_site
urlpatterns = [
urls.url(r'^$', views.get_profile_optional),
urls.url(r'^profile_required$', views.get_profile_required),
# urls.url(r'^profile_enabled$', views.get_profile_optional),
urls.url(r'^oauth2/', urls.include(django_util_site.urls)),
urls.url(r'^ga/$', views.google_analytics)
]
settings.py
[...]
GOOGLE_OAUTH2_CLIENT_ID = 'XXX.apps.googleusercontent.com'
GOOGLE_OAUTH2_CLIENT_SECRET = 'XXX'
GOOGLE_OAUTH2_SCOPES = ('email','https://www.googleapis.com/auth/analytics')
So my problem is I don't really understand where Django saves the token to access the data of that particular user, I know it works because it prints out the email address correctly etc, but I can't figure out what I should add to def google_analytics(object): to actually get specific Google API methods.
If anyone has experience on these kind of things I would really appreciate some help! Thanks!

If you want to fetch Google Analytics configuration details e.g. Accounts, Web properties, Profiles, Filters, Goals, etc you can do that using Google Analytics Management API V3
If you want to fetch data of certain dimension and metrics from a Google Analytics view (aka profile), you can do that using either Core Reporting API V3 or Analytics Reporting API V4.
I think you will find the python api examples in their respective Guides.

Related

Flask Admin custom permissions for items in the nav

I'm having trouble figuring out how to add custom permissions to nav items, such that certain items will show up when the user is logged in / logged out, or other parameters are met (such as the user is part of a certain organization).
Any help or examples would be greatly appreciated.
With flask_security package you are able to set roles to users and check them in flask_admin views as follows:
from http import HTTPStatus
from flask_admin.contrib.sqla import ModelView
from flask_security import current_user, url_for_security
from flask import abort, redirect, request
class AdminSecurityMixin:
allowed_roles = []
def is_accessible(self):
return current_user.is_active and current_user.is_authenticated and \
(current_user.has_role('admin') or any(current_user.has_role(r) for r in self.allowed_roles))
def _handle_view(self, name, **kwargs):
if not self.is_accessible():
# if user is logged in, but can't view the admin, reject access
if current_user.is_authenticated:
abort(HTTPStatus.FORBIDDEN)
# otherwise redirect to the admin login view
# the next parameter is so we can redirect them after they'ved
# logged in to where they wanted to go originally
return redirect(url_for_security('login', next=request.url))
return None
class SecuredModelView(AdminSecurityMixin, ModelView):
allowed_roles = ['custom_role']
Now model registered with SecuredModelView will be accessible in admin panel only to users who are logged in and have assigned custom_role or admin role.
Roles can be created and added to existing users with following commands:
$ flask roles create custom_role
$ flask roles add <your user email> custom_role
I guess you already have a database with at least a user table.
I think you just want to design templates.
I invite you to follow this Flask tutorial about templates. It will introduce you Jinja, a templating language.

Django: Stripe & POST request

I am currently trying to implement Stripe Connect in my Django project. Stripe documentations states for Standard accounts:
Assuming no error occurred, the last step is to use the provided code
to make a POST request to our access_token_url endpoint to fetch the
user’s Stripe credentials:
curl https://connect.stripe.com/oauth/token \
-d client_secret=sk_test_Dur3X2cOCwyjlf9Nr7OCf3qO \
-d code="{AUTHORIZATION_CODE}" \
-d grant_type=authorization_code
I now wonder how to send a POST request with Django without form & user action (clicking the submit button)?
Since Standard Connect relies on OAuth for its connection flow:
https://stripe.com/docs/connect/standard-accounts#oauth-flow
so you can use an OAuth python library like Rauth, as you mentioned, to handle the flow.
Also please note that Stripe Python library provides an implementation of the OAuth flow here:
https://github.com/stripe/stripe-python/blob/a938c352c4c11c1e6fee064d5ac6e49c590d9ca4/stripe/oauth.py
You can see an example of its usage here:
https://github.com/stripe/stripe-python/blob/f948b8b95b6df5b57c7444a05d6c83c8c5e6a0ac/examples/oauth.py
The example uses Flask not Django but should give you a good idea in terms of its use.
With regards to the advantages of using an existing OAuth implementation as opposed to implementing the calls directly yourself: one advantage I see is that your code would reuse a library that generally covers all different uses cases (e.g better error handling) and is also well tested.
Thanks to #psmvac I could implement it the 'proper' way now using the oAuth of Stripe. Here some reference/example Django code if anyone is trying the same. Obviously, urls.py has to be configured. This is in my views.py:
def stripe_authorize(request):
import stripe
stripe.api_key = ''
stripe.client_id = 'XYZ'
url = stripe.OAuth.authorize_url(scope='read_only')
return redirect(url)
def stripe_callback(request):
import stripe
from django.http import HttpResponse
# import requests
stripe.api_key = 'XYZ'
## import json # ?
code = request.GET.get('code', '')
try:
resp = stripe.OAuth.token(grant_type='authorization_code', code=code)
except stripe.oauth_error.OAuthError as e:
full_response = 'Error: ' + str(e)
return HttpResponse(full_response)
full_response = '''
<p>Success! Account <code>{stripe_user_id}</code> is connected.</p>
<p>Click here to
disconnect the account.</p>
'''.format(stripe_user_id=resp['stripe_user_id'])
return HttpResponse(full_response)
def stripe_deauthorize(request):
from django.http import HttpResponse
import stripe
stripe_user_id = request.GET.get('stripe_user_id', '')
try:
stripe.OAuth.deauthorize(stripe_user_id=stripe_user_id)
except stripe.oauth_error.OAuthError as e:
return 'Error: ' + str(e)
full_response = '''
<p>Success! Account <code>{stripe_user_id}</code> is disconnected.</p>
<p>Click here to restart the OAuth flow.</p>
'''.format(stripe_user_id=stripe_user_id)
return HttpResponse(full_response)

Django Allauth very specific redirection after Facebook Social Signup

I know there are a few questions on the topic already but I have tried to implement those solutions and could not really solve my problem.
I am talking about social signup with allauth here, and facebook in particular.
DESIRED BEHAVIOR: after facebook signup I want user to go to my url "accounts:welcome", but when they simply login I want them to go to my LOGIN_REDIRECT_URL (which is the site's home page).
After looking here and there this is the code I came up with (writing my custom adapter)
settings.py:
LOGIN_REDIRECT_URL = ("gamestream:home")
SOCIALACCOUNT_ADAPTER = "myproject.users.adapter.MySocialAccountAdapter"
adapter.py:
from django.conf import settings
from allauth.socialaccount.adapter import DefaultSocialAccountAdapter
from django.core.urlresolvers import reverse
from django.shortcuts import redirect
class MySocialAccountAdapter(DefaultSocialAccountAdapter):
def save_user(self, request, sociallogin, form=None):
print('OK11OK')
super().save_user(request, sociallogin, form=form)
return redirect(reverse('accounts:welcome'))
def get_connect_redirect_url(self, request, socialaccount):
print('OK22OK')
assert is_authenticated(request.user)
url = reverse('accounts:welcome')
return url
Please assume that all links/settings are good as for example the console prints out 'OK11OK' when I create myself as a user via the facebook app. The fact is that the method get_connect_redirect_url never gets triggered as I never read 'OK22OK' on the console.
The user is created and I end up on the home page, which is not what I want.
So I thought that after the save_user method something else gets called as I can tell that I pass through accounts:welcome, but then end up on the home page.
I can tell this because if I return an incorrect url in the save_user method I get an error that is specific to that url on that line.
So, what is wrong here?
I think I might be overriding the wrong method but I have read all the code of the base SocialAccountAdapter and I can't see anything else that would be the right choice.
Just wanted to mention that as I have more control on the normal account signup (not social) I have achieved what I wanted.
Any ideas?
Thanks very much!
I had the same problem too, I found two methods:
METHOD 1
Django doesn't use redirection function of the DefaultSocialAccountAdapter, you'll have to override the get_signup_redirect_url function of DefaultAccountAdapter to achieve the result.
First you need to change the default adapter in settings.py:
ACCOUNT_ADAPTER = 'users.adapter.MyAccountAdapter'
Then, just override the get_signup_redirect_url with your url:
# project/users/adapter.py
from allauth.account.adapter import DefaultAccountAdapter
class MyAccountAdapter(DefaultAccountAdapter):
def get_signup_redirect_url(self, request):
return resolve_url('/your/url/')
METHOD 2
This is the easier one
If you take a look at the source code at DefaultAccountAdapter it says:
Returns the default URL to redirect to after logging in. Note
that URLs passed explicitly (e.g. by passing along a next
GET parameter) take precedence over the value returned here.
So, you can pass along a next parameter in your login template to force the redirection. Here is an example using Google social login:
{% load socialaccount %}
{% providers_media_js %}
{# your html tags #}
<body>
SOCIAL LOGIN
</body>
Of course you can personalize the next url (I'm refering to /success/url/) as you wish. You can pass a context variable with your desired url and put it there instead of that hardcoded url.

Django URL and making a portion of it optional, but using the same class API View

So I have this API URL on the back-end and I am wondering how to make a portion of it optional.
url(r'^api/documents/(?P<id>[0-9]+)$', GetDocumentsAPIView.as_view(), name='documents'),
So two things can happen coming from the front-end.
1) When the user logs in, it brings them to the /home which lists all of their projects. Clicking on the project brings them /documents/85 where the number is the number of the project and it lists all the documents for that project. This is sent to the API URL /api/documents/85. This much is working fine.
2) The other option is the user will just click on a Documents link in the navbar, which will just bring them to /documents. This should just go to the API URL /api/documents/ and eventually onto the serializer.py where their most recent project is determined and the documents for that are returned and rendered in the front-end
This I can't get working. Not sure if I can do it with just one url(), or if I need two. Was hoping the one I posted would look at the (?P<id>[0-9]+)$ as optional and if nothing was there would return the same GetDocumentsAPIView, but this is not the case.
EDIT: Including the view I am using for testing at this point. Just print() to see if anything is being routed to the view.
from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response
from rest_framework.views import APIView
class GetDocumentsAPIView(APIView):
permission_classes = [IsAuthenticated]
def get(self, request, *args, **kwargs):
print(kwargs.get('id'))
return Response('Test')
No you need to add a URL pattern for r'^api/documents/$', which can launch the same view by the way. Only inside the view you'll have to assume id is optional:
if kwargs.get('id'):
# return specific document
else:
# return list of documents
I would rename your first URL pattern to 'view_document' so you can use the name 'documents' on the other, more generic view.
Note: I think your URL structure is wrong. Reading your URL, according to REST, I would expect to see the document with id 85 when fetching documents/85. If you actually are listing the docs of a project, the URL should be projects/85/documents/ or if unspecified projects/documents.

Which Django library to use for Facebook Graph API?

I'm currently developing an application in Django and trying to implement Facebook authentication and requests to the Graph API. I've seen a few different libraries out there, but what is the best way to do the following:
Have a user login via Facebook.
Django creates a new user for them and adds their uid and oauth token.
I can then make calls to the Graph API using Facebook's Python SDK.
I did see this example. Is it that simple on normal Django?
My company has built a library that makes integrating Facebook into your Django application dead simple (we've probably built 10-20 apps with the library, including some with huge amounts of traffic, so it's been battle-tested).
pip install ecl-facebook==1.2.7
In your settings, add values for your FACEBOOK_KEY, FACEBOOK_SECRET, FACEBOOK_SCOPE, FACEBOOK_REDIRECT_URL, and PRIMARY_USER_MODEL. You'll also need to add ecl_facebook.backends.FacebookAuthBackend to your AUTHENTICATION_BACKENDS. For example, in settings.py:
# These aren't actual keys, you'll have to replace them with your own :)
FACEBOOK_KEY = "256064624431781"
FACEBOOK_SECRET = "4925935cb93e3446eff851ddaf5fad07"
FACEBOOK_REDIRECT_URL = "http://example.com/oauth/complete"
FACEBOOK_SCOPE = "email"
# The user model where the Facebook credentials will be stored
PRIMARY_USER_MODEL = "app.User"
AUTHENTICATION_BACKENDS = (
# ...
'ecl_facebook.backends.FacebookAuthBackend',
)
Add some views in your views.py to handle pre- and post-authentication logic.
from django.contrib.auth import authenticate, login
from django.http import HttpResponseRedirect
from ecl_facebook.django_decorators import facebook_begin, facebook_callback
from ecl_facebook import Facebook
from .models import User
# ...
#facebook_begin
def oauth_facebook_begin(request):
# Anything you want to do before sending the user off to Facebook
# for authorization can be done here.
pass
#facebook_callback
def oauth_facebook_complete(request, access_token, error):
if error is None:
facebook = Facebook(token)
fbuser = facebook.me()
user, _ = User.objects.get_or_create(facebook_id=fbuser.id, defaults={
'access_token': access_token})
user = authenticate(id=user.id)
login(request, user)
return HttpResponseRedirect("/")
else:
# Error is of type ecl_facebook.facebook.FacebookError. We pass
# the error back to the callback so that you can handle it
# however you want.
pass
Now just hook up these URLs in your urls.py file and you're done.
# ...
urlpatterns = patterns('app.views',
# ...
url(r'^oauth/facebook/begin$', 'oauth_facebook_begin'),
url(r'^oauth/facebook/complete$', 'oauth_facebook_complete'),
)
Hope this helps!
P.S. You can read the rest of the docs here.
We do a lot of Facebook Application development where I work, and so we've developed an open-source library that makes everything about it really easy.
from django.http import HttpResponse
from fandjango.decorators import facebook_authorization_required
#facebook_authorization_required
def foo(request, *args, **kwargs):
return HttpResponse("Your name is %s" % request.facebook_user.first_name)
I recommend https://github.com/egnity/fb.py. Got my Django-based Facebook app up and running in no time. It includes a middleware that allows you to run code like this in your view:
for the user id:
user_id = request.facebook.graph().get_object("me")['id']
for the oauth token:
user_token = request.facebook.auth_token
You can then add the above to your User model as you please. To make Graph API calls, you can still use fb.py's middleware -- no need for using the primitive python-sdk. The user_id code above is a perfect example of a Graph API call. There's much more you can do with fb.py. The download includes a sample django project to get you going.