how to use facebook api on a group - facebook

i created an application to test facebook api using Python, then, in the application, i created its Group, but, the problem that this Group dont know who i'm; it shows me that am the Admin, but when i try to publish something using Tornado, i get the error
GraphAPIError: (#210) User not visible
and this is because it seems that it deletes the cookie, because when am using the group's profile, then i cant see the GraphAPI since it dont know who is authentificated!
here is the code:
class MainHandler(BaseHandler, tornado.auth.FacebookGraphMixin):
#tornado.web.authenticated
#tornado.web.asynchronous
def get(self):
self.facebook_request("/me/home", self.print_callback,access_token=self.current_user["access_token"])
a = self.current_user["access_token"]
self.graph = GraphAPI(a)
def print_callback(self, data):
self.graph.post_wall(self, "heloooooooo")
an sorry, because i dont get well the logic behind users Token, and Groups tokens? here i got a user Token? and because am the admin, i cant post!
EDIT: here are some snapshots i took from the application:
picture 1
picture 2
Update: i tried this:
def print_callback(self, me):
self.graph.post_wall(self, "helooooo", profile_id="267914489995838")
and got the error:
self.graph.post_wall(self, "helooooo", profile_id="267914489995838")
TypeError: post_wall() got multiple values for keyword argument 'profile_id'
and i used what is in the Tornado-Facebook-API
def post_wall(self, message, profile_id='me', body=None, **kwargs):
#XXX move to separate User class?
body = body or {}
body['message'] = message
self._make_request("{0}/feed".format(profile_id), method='POST',
body=body, **kwargs)
update2: here is the full code
class BaseHandler(tornado.web.RequestHandler):
def get_current_user(self):
user_json = self.get_secure_cookie("user")
if not user_json: return None
return tornado.escape.json_decode(user_json)
class MainHandler(BaseHandler, tornado.auth.FacebookGraphMixin):
#tornado.web.authenticated
#tornado.web.asynchronous
def get(self):
self.facebook_request("/me/accounts", self._on_accounts,
access_token=self.current_user["access_token"])
self.a = self.current_user["access_token"]
self.graph = GraphAPI(self.a)
def _on_accounts(self, account):
if account is None:
# Session may have expired
print "on accounts failed"
return
for acc in account["data"]:
if acc["id"] == "267914489995838":
print acc["access_token"]
self.facebook_request("/PAGE_ID/feed",
post_args={"message": "Test"},
access_token=acc["access_token"],
callback=self.async_callback(self._on_page_post))
def _on_page_post(self, post):
if not post:
# Post failed
return
class AuthLoginHandler(BaseHandler, tornado.auth.FacebookGraphMixin):
#tornado.web.asynchronous
def get(self):
my_url = (self.request.protocol + "://" + self.request.host +
"/auth/login?next=" +
tornado.escape.url_escape(self.get_argument("next", "/")))
if self.get_argument("code", False):
self.get_authenticated_user(
redirect_uri=my_url,
client_id=self.settings["facebook_api_key"],
client_secret=self.settings["facebook_secret"],
code=self.get_argument("code"),
callback=self._on_auth)
return
self.authorize_redirect(redirect_uri=my_url,
client_id=self.settings["facebook_api_key"],
extra_params={"scope": "read_stream, publish_stream"})
def _on_auth(self, user):
if not user:
raise tornado.web.HTTPError(500, "Facebook auth failed")
self.set_secure_cookie("user", tornado.escape.json_encode(user))
self.redirect(self.get_argument("next", "/"))
class AuthLogoutHandler(BaseHandler, tornado.auth.FacebookGraphMixin):
def get(self):
self.clear_cookie("user")
self.redirect(self.get_argument("next", "/"))
class PostModule(tornado.web.UIModule):
def render(self, post):
return self.render_string("modules/post.html", post=post)

Some clarifications:
A #200 error is a permission error. In this case, you don't have permissions to post somewhere.
There are two main types of tokens: user tokens and page tokens
You can add a group to an application's roles http://developers.facebook.com/blog/post/531/
As far as I know, there is no way to add an application to a group
So I think based on the Facebook id given you either want to do two things
Post to an application's timeline
Post to a group via an application
Posting to an application's timeline
This requires the application page access token, which you get from /me/accounts using the manage_pages and publish_stream permissions
self.facebook_request("/me/accounts", self._on_accounts,
access_token=self.current_user["access_token"])
def _on_accounts(self, account):
if account is None:
# Session may have expired
print "on accounts failed"
return
for acc in account["data"]:
if acc["id"] == "PAGE_ID":
print acc["access_token"]
self.facebook_request("/PAGE_ID/feed",
post_args={"message": "Test"},
access_token=acc["access_token"],
callback=self.async_callback(self._on_page_post))
def _on_page_post(self, post):
if not post:
# Post failed
return
See http://developers.facebook.com/docs/reference/api/application/ for more info
A full example can be seen at https://gist.github.com/3867203 (Which doesn't handle duplicate posting)

Related

Graphene JWT authentication

I'm using graphene-jwt to authenticate user but my user has to multiple object return
here
def mutate(cls, root, info, **kwargs):
result = super().mutate(root, info, **kwargs)
...
How can I add additional query to 'filter' more like User.object.filter(user_type=3)? cause currently my code is like this
except (MultipleObjectsReturned, JSONWebTokenError) as e:
users = models.User.objects.get(email=kwargs.get("email"), user_type_id=3)
result = cls(
user=users,
errors=[Error()],
account_errors=[],
token=get_token(users))
user = result.user
I do get token even my password is wrong, it should be failed when the password is wrong.
Thanks

Tornado facebook_request() to get email

I'm using tornado and trying to get a facebook user's email address from the Graph API. I have the following code (most of which is from the Tornado website)
class FacebookAuth2Handler(BaseHandler,tornado.auth.FacebookGraphMixin):
#tornado.gen.coroutine
def get(self):
if self.get_argument("code", False):
user = yield self.get_authenticated_user(redirect_uri=self.settings["facebook_redirect_uri"],
client_id=self.settings["facebook_app_id"],
client_secret=self.settings["facebook_secret"],
code=self.get_argument("code"))
ob = yield self.facebook_request("/me/email",access_token=user["access_token"])
print(ob)
else:
yield self.authorize_redirect(redirect_uri=self.settings["facebook_redirect_uri"],
client_id=self.settings["facebook_app_id"],
extra_params={"scope": ["email","public_profile"]})
The problem seems to be fetching the /me/email with the facebook_request() this crashes with the following:
tornado.auth.AuthError: Error response HTTP 400: Bad Request fetching https://graph.facebook.com/me/email?access_token=xxxxxxx
Setting the path to "/me/email" is not valid, and setting it to "/me?fields=email" causes it to send your url as "/me?fields=email?access_token=xxxxxxx", which is no good either.
use the fields parameter:
ob = yield self.facebook_request(
path="/me",
access_token=user["access_token"],
fields="email,gender"
)
or you can really simplify things by adding the extra_fields parameter to get_authenticated_user. Note it is a python list, not a comma-separated string like above:
user = yield self.get_authenticated_user(redirect_uri=self.settings["facebook_redirect_uri"],
client_id=self.settings["facebook_app_id"],
client_secret=self.settings["facebook_secret"],
code=self.get_argument("code"),
extra_fields=['email','gender']
)
Any missing or unpermitted fields will show as None in the returned user mapping object.

Pipeline workflow and variables

I have Facebook authentication working on my site, but I need the user to fill a profile form during his authentication. I have used an authentication pipeline to do so but whithout success. The pipeline is being called like it should, but the result is an error.
Let's say I need his mobile number - consider it does not come from Facebook.
Please consider:
models.py
from django.db import models
from django.contrib.auth.models import User
class Profile(models.Model):
user = models.OneToOneField(User)
mobile = models.IntegerField()
settings.py
SOCIAL_AUTH_PIPELINE = (
'social.pipeline.social_auth.social_details',
'social.pipeline.social_auth.social_uid',
'social.pipeline.social_auth.auth_allowed',
'social.pipeline.social_auth.social_user',
'social.pipeline.user.get_username',
'social.pipeline.mail.mail_validation',
'social.pipeline.user.create_user',
'social.pipeline.social_auth.associate_user',
'social.pipeline.social_auth.load_extra_data',
'social.pipeline.user.user_details',
'myapp.pipeline.fill_profile',
)
pipeline.py
from myapp.models import Profile
from social.pipeline.partial import partial
#partial
def fill_profile(strategy, details, user=None, is_new=False, *args, **kwargs):
try:
if user and user.profile:
return
except:
return redirect('myapp.views.profile')
myapp/views.py
from django.shortcuts import render, redirect
from myapp.models import Perfil
def profile(request):
if request.method == 'POST':
profile = Perfil(user=request.user,mobile=request.POST.get('mobile'))
profile.save()
backend = request.session['partial_pipeline']['backend']
redirect('social:complete', backend=)
return render(request,'profile.html')
The profile.html is just a form with an input text box named 'mobile' and a submit button.
Then I get this error:
Cannot assign "<SimpleLazyObject: <django.contrib.auth.models.AnonymousUser object at 0x03C2FB10>>": "Profile.user" must be a "User" instance.
Why can't I access the User instance since the user in auth_user table is already there (I suppose)?
Please, what's wrong with this?
You can't access the user in request.user because it's not logged in yet, the user will be logged in social complete view after the pipeline executed. Usually partial pipeline views will save the form data into the session and then the pipeline will pick it and save it. Also you can set the user id in the session in your pipeline and then pick that value in your view. For example:
#partial
def fill_profile(strategy, user, *args, **kwargs):
...
strategy.session_set('user_id', user.id)
return redirect(...)

Scala-Lift redirect user after login

I want to redirect to a certain page after a user logs in to my Scala Lift web application. I found this answer which doesn't seem to work:
In my User object (which is a MetaMegaProtoUser) I override the following method like so:
object User extends User with MetaMegaProtoUser[User] {
override def loginFirst = If(
loggedIn_? _,
() => {
import net.liftweb.http.{RedirectWithState, RedirectState}
val uri = Full("/myPicks")
println("login sucessful .. redirecting!..")
RedirectWithState(
loginPageURL,
RedirectState( ()=>{loginRedirect.set(uri)})
)
}
)
}
This doesn’t work. Any ideas?
loginFirst defines a LocParam which can be used for specifying where to send the user if they are not logged in. It is used in conjunction with SiteMap.
For the page you want to protect, you can modify that entry like:
Menu("Protected Page") / "protected" >> User.loginFirst
That should test whether the user is logged in when you access /protected and, if they are not, set the loginRedirect SessionVar and display the login form. On a successful login, you should be redirected to the page specified in loginRedirect.
I believe you can also just use: override def homePage = "/myPicks" if you want to set a default page to redirect to.

using flask-login with postgresql

I'm working on a flask app that needs authentication. I've hooked up flask-login but it doesn't seem very graceful.
First flask-login needs to make sure the user exists:
#login_manager.user_loader
def load_user(id):
return User.query.get(id)
But you also need to use 'login_user' to create the user object
# Some code above
user = User.query.filter_by(email = form.email.data, password = form.password.data).first()
user.login_status = 1
db.session.commit()
login_user(objects.SignedInUser(user.id, user.email, user.login_status == LoginStatus.Active))
# Some code below
In the code above 'User' is a model for postgres and SignedInUser is just an object to be used for flask-login.
Does anyone have an example of flask-login used with postgres?
It looks like you might be misunderstanding what Flask-Login handles. It's there to keep track of everything about the user's session after you tell it authentication was successful (by calling login_user.) The user_loader callback only tells it how to reload the object for a user that has already been authenticated, such as when someone reconnects to a "remember me" session. The docs are not especially clear on that.
There should be no need to keep a flag in the database for the user's login status. Also, the code you included will raise an AttributeError if the credentials are incorrect (user = None).
Here's an example from a Flask-SQLAlchemy application. It uses an external authentication source and a wrapper for the SQLAlchemy User object, but the process is basically the same.
user_loader callback:
#login_manager.user_loader
def load_user(user_id):
user = User.query.get(user_id)
if user:
return DbUser(user)
else:
return None
User class (wrapper for SQLAlchemy object):
# User class
class DbUser(object):
"""Wraps User object for Flask-Login"""
def __init__(self, user):
self._user = user
def get_id(self):
return unicode(self._user.id)
def is_active(self):
return self._user.enabled
def is_anonymous(self):
return False
def is_authenticated(self):
return True
Login handler:
#app.route('/login', methods=['GET', 'POST'])
def login():
error = None
next = request.args.get('next')
if request.method == 'POST':
username = request.form['username']
password = request.form['password']
if authenticate(app.config['AUTH_SERVER'], username, password):
user = User.query.filter_by(username=username).first()
if user:
if login_user(DbUser(user)):
# do stuff
flash("You have logged in")
return redirect(next or url_for('index', error=error))
error = "Login failed"
return render_template('login.html', login=True, next=next, error=error)
Note that login fails if:
external auth fails
user query returns None (user does not exist)
login_user returns False (user.is_active() == False)
Logout
#app.route('/logout')
#login_required
def logout():
logout_user()
flash('You have logged out')
return(redirect(url_for('login')))