Why is current_user None? - google-app-engine

I have a horrible bug that I put a bounty on and now I'm reducing to the simplest case of reproduction. At least a can reproduce it :D Some info: The entity FUser does not populate an entity, the javascript button switches between login / logout apprioriately and from the log you might be able to tell me what's wrong with the flow.
2011-10-04 17:34:14.398 /example 200 10ms 0cpu_ms 0kb Mozilla/5.0 (X11; Linux x86_64; rv:2.0) Gecko/20100101 Firefox/4.0
213.89.134.0 - - [04/Oct/2011:13:34:14 -0700] "GET /example HTTP/1.1" 200 694 - "Mozilla/5.0 (X11; Linux x86_64; rv:2.0) Gecko/20100101 Firefox/4.0" "www.koolbusiness.com" ms=11 cpu_ms=0 api_cpu_ms=0 cpm_usd=0.000157 instance=00c61b117c837db085d58acd70ffae167a06
D 2011-10-04 17:34:14.395
logging current_userNone
.py
"""A barebones AppEngine application that uses Facebook for login."""
FACEBOOK_APP_ID = "164355773607006"
FACEBOOK_APP_SECRET = "642f15e4324b45661e1049d5b139cb0"
import facebook
import os.path
import wsgiref.handlers
import logging
from google.appengine.ext import db
from google.appengine.ext import webapp
from google.appengine.ext.webapp import util
from google.appengine.ext.webapp import template
class FUser(db.Model):
id = db.StringProperty(required=True)
created = db.DateTimeProperty(auto_now_add=True)
updated = db.DateTimeProperty(auto_now=True)
name = db.StringProperty(required=True)
profile_url = db.StringProperty(required=True)
access_token = db.StringProperty(required=True)
class BaseHandler(webapp.RequestHandler):
"""Provides access to the active Facebook user in self.current_user
The property is lazy-loaded on first access, using the cookie saved
by the Facebook JavaScript SDK to determine the user ID of the active
user. See http://developers.facebook.com/docs/authentication/ for
more information.
"""
#property
def current_user(self):
if not hasattr(self, "_current_user"):
self._current_user = None
cookie = facebook.get_user_from_cookie(
self.request.cookies, FACEBOOK_APP_ID, FACEBOOK_APP_SECRET)
logging.debug("logging cookie"+str(cookie))
if cookie:
# Store a local instance of the user data so we don't need
# a round-trip to Facebook on every request
user = FUser.get_by_key_name(cookie["uid"])
logging.debug("user "+str(user))
if not user:
graph = facebook.GraphAPI(cookie["access_token"])
profile = graph.get_object("me")
user = FUser(key_name=str(profile["id"]),
id=str(profile["id"]),
name=profile["name"],
profile_url=profile["link"],
access_token=cookie["access_token"])
user.put()
elif user.access_token != cookie["access_token"]:
user.access_token = cookie["access_token"]
user.put()
self._current_user = user
return self._current_user
class HomeHandler(BaseHandler):
def get(self):
path = os.path.join(os.path.dirname(__file__), "example.html")
logging.debug("logging current_user"+str(self.current_user))
args = dict(current_user=self.current_user,
facebook_app_id=FACEBOOK_APP_ID)
self.response.out.write(template.render(path, args))
def main():
util.run_wsgi_app(webapp.WSGIApplication([(r"/example", HomeHandler)]))
if __name__ == "__main__":
main()
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<title>Facebook Example</title>
</head>
<body>
<fb:login-button autologoutlink="true"></fb:login-button>
{% if current_user %}
<p><img src="http://graph.facebook.com/{{ current_user.id }}/picture?type=square"/></p>
<p>Hello, {{ current_user.name|escape }}</p>
{% endif %}
<div id="fb-root"></div>
<script>
window.fbAsyncInit = function() {
FB.init({appId: '{{ facebook_app_id }}', status: true, cookie: true,
xfbml: true});
FB.Event.subscribe('{% if current_user %}auth.logout{% else %}auth.login{% endif %}', function(response) {
window.location.reload();
});
};
(function() {
var e = document.createElement('script');
e.type = 'text/javascript';
e.src = document.location.protocol + '//connect.facebook.net/en_US/all.js';
e.async = true;
document.getElementById('fb-root').appendChild(e);
}());
</script>
</body>
</html>
Update
I still don't get the user object and changed the HomeHandler to this
class HomeHandler(BaseHandler):
def get(self):
path = os.path.join(os.path.dirname(__file__), "example.html")
logging.debug("logging current_user"+str(self.current_user))
args = dict(current_user=self.current_user,
facebook_app_id=FACEBOOK_APP_ID)
user = facebook.get_user_from_cookie(self.request.cookies, FACEBOOK_APP_ID, FACEBOOK_APP_SECRET)
if not user:
logging.debug("no user")
if user:
graph = facebook.GraphAPI(user["access_token"])
profile = graph.get_object("me")
friends = graph.get_connections("me", "friends")
logging.debug("logging profile"+str(profile))
self.response.out.write(template.render(path, args))

Relating to #Shay Erlichmen's observation, the above code shouldn't work due to facebook's changes of a few days ago. As I pointed out on your original question, there is a version of the facebook python SDK which has been modified to support the new authentication mechanism - see
https://gist.github.com/1190267
The specific place where this differs from the old version is in the get_user_from_cookie() method. If you're still using the old version of the facebook python SDK, this should look for an fbs_APPID cookie, not find it and return None - hence cookie is never assigned a value _current_user retains the None state assigned at the start of the method.
One check you can do is to have a look at the cookies in your browser - you should see the new fbsr_APPID cookies which are not handled by the old library.

Facebook switched to OAuth2.0 on October 1,2011, this code is old and should work anymore.

Related

wagtail 4.0/ How return urls (templates) for preview in admin board from #path

class ProductIndexPage(RoutablePageMixin, Page):
subpage_types = ['ProductPage']
parent_page_types = ['home.HomePage']
def live_categories(self):
all_products_live_id = ProductPage.objects.live().values_list('categories_id', flat=True)
list_live_id_uniqe = list(set(all_products_live_id))
live_cat = ProductCategory.objects.filter(id__in=list_live_id_uniqe).order_by('-id')
return live_cat
#path('')
#path('all-categories/')
def all_category_page(self, request):
productpages = self.get_children().live().order_by('-first_published_at')
return self.render(request, context_overrides={
'title': self.title,
'productpages': productpages,
'live_categories': self.live_categories,
})
#path('<str:cat_name>/', name='cat_url')
def current_category_page(self, request, cat_name=None):
productpages = ProductPage.objects.live().filter(categories__slug__iexact=cat_name).order_by \
('-first_published_at')
current_cat = self.live_categories().get(slug=cat_name).name
return self.render(request, context_overrides={
'title': "%s" % current_cat,
'productpages': productpages,
'live_categories': self.live_categories,
})
#path('<str:cat_name>/<str:prod_name>/')
def product_page(self, request, cat_name=None, prod_name=None):
product = ProductPage.objects.get(categories__slug__iexact=cat_name, slug=prod_name)
return self.render(request, context_overrides={
'product': product},
template="products/product_page.html",)
I can't edit page in wagtail admin menu from path:
#path('<str:cat_name>/<str:prod_name>/')
My page tree in admin:
root/products/<prod_name>
How to change route in Admin for editing pages from wagtal button or for preview in Admin?
I am newbie, plz show me example.
sorry for English)
With RoutablePageMixin there is only one page - and it displays differently depending on the parameter sent on the url. Unfortunately, this means you can't preview the category version of your page, current_category_page.
But it looks like the product page you are routing too as #path('str:cat_name/str:prod_name/') should be displaying the same page as you serve from the ProductPage's own url. So the ProductPage you see in the preview ProductIndexPage + 'str:cat_name/str:prod_name/'

React fine-uploader upload the file

I have a simple react app. I've added react-fine-uploader to it. I have a Flask server that accepts files and puts them into MongoDB database. The code for server looks like this:
from flask import Flask, render_template, request
from pymongo import MongoClient
import os
import time
from json import dumps, loads
app = Flask(__name__)
global index
map_dir = 'maps'
client = MongoClient(
'<connection_string>')
db = client.business
#app.route('/maps', methods=['GET'])
def process():
cursor = db.maps.find({}, {'_id': False})
maps = {'maps': []}
for doc in cursor:
try:
maps['maps'].append(doc['filename'])
except Exception:
pass
return dumps(maps)
#app.route('/map/<map_name>', methods=['GET'])
def get_map(map_name):
doc = db.maps.find_one({'filename': map_name}, {'_id': False})
return dumps(doc)
#app.route('/uploader', methods=['GET', 'POST'])
def upload_file():
if request.method == 'POST':
f = request.files['file']
parsed = loads(f.read())
filename = ''.join(f.filename.split('.')[:-1]) + str(index) + '.json'
parsed['filename'] = filename
try:
result = db.maps.insert_one(parsed)
return 'File uploaded successfully'
except Exception:
return 'Error while uploading a file'
if __name__ == '__main__':
global index
index = len(os.listdir('maps')) + 1
app.run(debug=True)
It works with standard HTML input form with specifying target as localhost:5000/uploader. Now I want my fine-uploader form to do the same. In code it looks like this:
const uploader1 = new FineUploader({
options: {
request: {
endpoint: "localhost:5000/uploader"
},
resume: {
enabled: true
},
retry: {
enableAuto: true,
showButton: true
}
}
});
And somewhere in the render() method I got: <Gallery uploader={uploader1} />
Now I can select file, but when it is selected the form tries to upload it and it fails. Server is running and I can see no request on him in the terminal. Is there something I am doing wrong?
#Edit I've enabled debug mode and it throws something like this into dev console:
Cross origin requests are only supported for protocol schemes: http, data, chrome, chrome-extension, https

Check chrome web store user license from google app engine

Is it possible to use client-side generated access token in a server-side call to chromewebstore/v1.1/userlicenses/ to check user license? Both extension and app engine project registered on the same gmail account. I want to be able to tell if the user of my webapp has purchased my extension.
gapi.auth.authorize({
scope: [
"https://www.googleapis.com/auth/plus.me",
"https://www.googleapis.com/auth/plus.login",
"https://www.googleapis.com/auth/userinfo.email",
"https://www.googleapis.com/auth/chromewebstore.readonly"].join(" "),
client_id: "xxxxx"
}, () => gapi.client.myapi.check_payment().execute())
App engine code
import os
import urllib
import endpoints
import httplib2
from oauth2client import client
from protorpc import remote
from protorpc.message_types import VoidMessage
EXTENSION_ID = "xxxxx" # my extension id from Chrome Web Store Developer Dashboard
API_KEY = "xxxxx" # api key from Google APIs Console
CLIENT_ID = "xxxxx" # OAuth 2.0 client ID from Google APIs Console
SCOPES = [endpoints.EMAIL_SCOPE]
#endpoints.api(name="myapi", version="v1", allowed_client_ids=[CLIENT_ID], scopes=SCOPES)
class MyApi(remote.Service):
#endpoints.method(VoidMessage, VoidMessage)
def check_payment(self, msg):
user = endpoints.get_current_user()
assert user is not None
if "HTTP_AUTHORIZATION" in os.environ:
(tokentype, token) = os.environ["HTTP_AUTHORIZATION"].split(" ")
credentials = client.AccessTokenCredentials(token, 'my-user-agent/1.0')
http = credentials.authorize(httplib2.Http())
params = urllib.urlencode({"key": API_KEY})
url = "https://www.googleapis.com/chromewebstore/v1.1/userlicenses/%s?%s" % (EXTENSION_ID, params)
response = http.request(url)
Responds with 403 status: {"domain":"global","reason":"forbidden","message":"You don\'t have access to licensing data for App ID: xxxxx"}
So yeah, there is no way for that to work, this kind of a request can only by authorized with a token minted by identity.getAuthToken.

AngularJS + django REST api

I'm attempting to build an api with DRF.
Client is a cordova app backed with AngularJS.
When I try to post some user object using $resource I'm getting a 403 forbidden response from django.
Below is some code which I think is relevant for the issue:
The API Call:
$rootScope.user =
User.get({id: response.id}).$promise.then(angular.noop, function (e) {
if (e.status == 404) { //If not found, register the user.
$rootScope.user = new User();
Object.keys(response).forEach(function (key) {
$rootScope.user[key] = response[key];
});
$rootScope.user.$save(); //Fails here! 403.
}
else
console.log(JSON.stringify(e.msg));
});
The User factory:
.factory('User', function ($resource, serverConstants) {
return $resource(serverConstants.serverUrl + '/users/:id');
})
django view:
# Users
class UserSerializer(serializers.HyperlinkedModelSerializer):
id = serializers.CharField(max_length=100,required=True)
email = serializers.EmailField(required=False,allow_blank=True)
joined = serializers.DateField(required=False,default=datetime.date.today)
class Meta:
model = models.User
fields = ('joined', 'id', 'email')
def get_validation_exclusions(self):
exclusions = super(UserSerializer, self).get_validation_exclusions()
return exclusions + ['owner']
class UserViewSet(viewsets.ModelViewSet):
queryset = models.User.objects.all()
serializer_class = UserSerializer
PS: I've configured angular to use CSRF cookie and django to allow CORS
Thanks in advance!
Your /user/:id endpoint requires authenticated requests.
You need to authenticate your client's requests using one of the methods specified on the previous link.
Given your app runs in a WebView and then has a builtin cookies handling, SessionAuthentication is the more straightforward to implement.
If you want the endpoint to not require authentication, you can set its permission_classes attribute like so:
from rest_framework.permissions import AllowAny
class UserViewSet(viewsets.ModelViewSet):
queryset = models.User.objects.all()
serializer_class = UserSerializer
permission_classes = (AllowAny, )
I guess with DRF you mean the django-rest-framework.
If yes, have a look here:
http://www.django-rest-framework.org/api-guide/authentication/
You can make the view public but using AllowAny.
from rest_framework.permissions import AllowAny
from rest_framework import generics
restapi_permission_classes = (AllowAny,)
class MyListView(generics.ListCreateAPIView):
serializer_class = MyObjectSerializer
permission_classes = restapi_permission_classes
queryset = MyObject.objects.all()
However I'd recommend you to use proper authentication once you are done with testing. I've been using the token authentication.
Have a look at this post for more details:
Django Rest Framework Token Authentication

AngularJS & Flask : Passing data to html

I am trying to send the data from Flask to AngularJS.
Server
#app.route("/data")
def getDataFromDB():
cur.execute("select * from employee")
rows = cur.fetchall()
columns = [desc[0] for desc in cur.description]
result = []
for row in rows:
row = dict(zip(columns, row))
json_row=json.dumps(row)
result.append(json_row)
json_response=json.dumps(result)
response=Response(json_response,content_type='application/json; charset=utf-8')
response.headers.add('content-length',len(json_response))
response.status_code=200
return response
Client
maincontroller.js
var app=angular.module('myApp',[]);
app.controller("MainController", function($scope,$http){
var done=function(resp){
$scope.lists=resp.data;
};
var fail=function(err){
};
$http.get('http://10.62.XX.XX:8083/data')
.then(done,fail);
});
index.html
<!DOCTYPE html>
<head>
<title>Learning AngularJS</title>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.0/angular.min.js"
type="text/javascript"></script>
<script src="app.js" type="text/javascript"></script>
<script src="maincontroller.js" type="text/javascript"></script>
</head>
<body ng-app="myApp">
<div id='content' ng-controller='MainController'>
<div>
<ul>
<li ng-repeat='ele in list'>{{ele}}</li>
</ul>
</div>
</div>
</body>
</html>
Now, when I access the above code using jsbin.com, I can see my api getting called but nothing is visible on the output screen in jsbin. It is blank.
But when I put the same code in eclipse, I see no api call happening. Do I need to do something more to make angularJS work? I just open the index.html with web browser.
If the IP is not your local machine you need to setup CORS on the server. I am not familiar with Flask but it looks like there is a package that handles this. I also found a function that sets up CORS for Flask.
from datetime import timedelta
from flask import Flask, make_response, request, current_app
from functools import update_wrapper
def crossdomain(origin=None, methods=None, headers=None, max_age=21600, attach_to_all=True, automatic_options=True):
if methods is not None:
methods = ', '.join(sorted(x.upper() for x in methods))
if headers is not None and not isinstance(headers, basestring):
headers = ', '.join(x.upper() for x in headers)
if not isinstance(origin, basestring):
origin = ', '.join(origin)
if isinstance(max_age, timedelta):
max_age = max_age.total_seconds()
def get_methods():
if methods is not None:
return methods
options_resp = current_app.make_default_options_response()
return options_resp.headers['allow']
def decorator(f):
def wrapped_function(*args, **kwargs):
if automatic_options and request.method == 'OPTIONS':
resp = current_app.make_default_options_response()
else:
resp = make_response(f(*args, **kwargs))
if not attach_to_all and request.method != 'OPTIONS':
return resp
h = resp.headers
h['Access-Control-Allow-Origin'] = origin
h['Access-Control-Allow-Methods'] = get_methods()
h['Access-Control-Max-Age'] = str(max_age)
if headers is not None:
h['Access-Control-Allow-Headers'] = headers
return resp
f.provide_automatic_options = False
return update_wrapper(wrapped_function, f)
return decorator
#app.route('/')
#crossdomain(origin='*')
def landing():
return jsonify(i_am_a='cross domain resource!')
if __name__ == '__main__':
app.run(host='0.0.0.0', port=8080)

Resources