I use sqlalchemy and sometimes i have this error:
sqlalchemy.exc.ResourceClosedError: This Connection is closed
I think this is a problem with session but I do not know how to fix it
Code:
engine = create_engine(config['engine'])
connection = engine.connect()
Session = sessionmaker(bind=engine)
session = None
bot = telebot.TeleBot(config['telegram_token'])
app = flask.Flask(__name__)
#app.route('/tg', methods=['POST'])
def webhook():
if flask.request.headers.get('content-type') == 'application/json':
global session
session = Session()
json_string = flask.request.get_data().decode('utf-8')
update = telebot.types.Update.de_json(json_string)
bot.process_new_updates([update])
return ''
else:
flask.abort(403)
#bot.message_handler(func=lambda message: message.chat.id == config['chat_id'], content_types=['text'])
def chat_handler(message):
tg_id = message.from_user.id
in_db = session.query(ChatMessage).filter(
ChatMessage.message_id == message.message_id).count()
if in_db == 0:
die_time = datetime.now().replace(second=0, microsecond=0) + \
timedelta(seconds=config['chat_message_lifetime'])
if message.pinned_message != None:
die_time = None
chat_mess = ChatMessage(
user_id=None, advorder_id=None, message_id=message.message_id, dietime=die_time)
session.add(chat_mess)
session.commit()
bot.remove_webhook()
bot.set_webhook(url=config['webhook_url_base'],
certificate=open(config['webhook_ssl_cert'], 'r'))
app.run()
Related
I'm trying to test a endpoint that depends a jwt authentication but don't know how make this, especially send the authentication or skip, please an advice will be very useful.
My code give me that error :
AssertionError: {"detail":"Not authenticated"}
router:
#router.post(
path="/api/users",
response_model=UsersRespose,
status_code=status.HTTP_201_CREATED,
summary="Create a new Users Survey",
tags = ["Users"]
)
async def create_user_survey(
user:Users,
db: Session = Depends(get_db),
admin: Admins= Depends(get_curret_admin)
):
db_user = await get_users_by_email(db,email=user.users_email)
if db_user:
raise HTTPException(status_code=400, detail="El correo electronico ya existe")
return await create_users_survey(db=db, user=user)
dependency:
async def create_token(admin:Admin):
admin_obj = Admins.from_orm(admin)
token = encode(admin_obj.dict(), JWT_SECRET)
return dict(access_token=token, token_type="bearer")
async def get_curret_admin(db: Session=Depends(get_db), token: str = Depends(oauth2schema)):
try:
payload=decode(token, JWT_SECRET, algorithms=["HS256"])
admin= db.query(Admin).get(payload["id"])
except:
raise HTTPException(
status_code=401,
detail="Correo o password invalido"
)
return Admins.from_orm(admin)
and test
SQLALCHEMY_DATABASE_URL = "sqlite:///./test.db"
engine = create_engine(
SQLALCHEMY_DATABASE_URL, connect_args={"check_same_thread": False}
)
TestingSessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
Base.metadata.create_all(bind=engine)
def override_get_db():
try:
db = TestingSessionLocal()
yield db
finally:
db.close()
app.dependency_overrides[get_db] = override_get_db
client = TestClient(app)
def test_create_user():
mail=random_email_user()
name =random_name_user()
password = random_pasword_user()
id=random_int_user()
response=client.post("/api/users", json={"users_email":mail ,"id":id, "users_name": name},)
assert response.status_code == 201, response.text
data = response.json()
assert data["users_email"] == mail
Thanks to #MatsLindh the solution was quite simple
def override_get_currrent_admin():
return {"email":"dummy#dummy.com", "name_admin":"dummy", "id":"5"}
app.dependency_overrides[get_curret_admin]= override_get_currrent_admin
Background:
I built an app in which, as soon as a user browse a file and clicks on the "upload" button, a behind-the-scenes calculation takes place, which can take long minutes, and at the end the output is uploaded to GCP. I want the calculation (after clicking) not to stuck the app and that in the meantime the user will be moved to another page. At the end of the process he will receive a success/failure email.
To achieve this goal I try to use multiprocessing.
I'm having much trouble trying to turn it to multi-processed app - I keep gettin the following error message when I'm trying to start a process:
_pickle.PicklingError: Can't pickle <class 'wtforms.form.Meta'>: attribute lookup Meta on wtforms.form failed
app.py -
The main function is `upload_file:
#app.route('/')
def home():
return redirect(url_for('upload_file', page_num=1))
#app.route('/<int:page_num>', methods=['GET', 'POST'])
def upload_file(page_num=1):
form = CreateXslxForm()
traffic_data = get_page_of_traffic_data(page_num)
queue = Queue()
p = Process(target=main_func, args=(queue, form))
p.start()
proc_ret = queue.get()
if proc_ret:
upload_success(*proc_ret)
else:
return render_template(constants.GeneralConstants.LANDING_PAGE, title='URL Comparison', form=form,
traffic_data=traffic_data)
def get_page_of_traffic_data(page_num):
traffic_data = urls_comparison_users_traffic.query.paginate(per_page=5, page=int(page_num), error_out=True)
return traffic_data
def upload_success(link, traffic_row, blob_name):
add_data_to_db(traffic_row)
return render_template('upload_success.html', title='Upload File', file_path=link, filename=blob_name)
def add_data_to_db(traffic_row):
# MANUAL PRE PING
try:
db.session.execute("SELECT 1;")
db.session.commit()
except:
db.session.rollback()
finally:
db.session.close()
# SESSION COMMIT, ROLLBACK, CLOSE
try:
db.session.add(traffic_row)
db.session.commit()
send_response_mail_to_user(traffic_row)
except Exception as e:
db.session.rollback()
raise e
finally:
db.session.close()
def send_response_mail_to_user(traffic_data):
sendgrid_obj = sendgrid_handler.SendgridHandler(sendgrid_key=SENDGRID_KEY)
sendgrid_obj.mails_to_send = URLComparisonEmailBuilder.build_mails(traffic_data)
sendgrid_obj.send()
if __name__ == "__main__":
app.run(port=5000, debug=True, threaded=True)
main.py
os.environ['GOOGLE_APPLICATION_CREDENTIALS'] = r'gcp-cre.json'
storage_client = storage.Client()
def get_file_from_form(form):
# form = forms.CreateXslxForm()
timestr = time.strftime(constants.DatesFormats.DATETIME)
custom_name = f"{constants.GeneralConstants.DEST_DEFAULT_NAME}-{timestr}"
# traffic_data = get_page_of_traffic_data(page_num)
if form.validate_on_submit():
load_filename = secure_filename(form.input_file.data.filename)
valid_file_name = get_valid_filename(request.form["filename"])
if valid_file_name:
custom_name = f"{valid_file_name}"
url_comp_obj = URLCompare()
result = url_comp_obj.compare_all_urls(form.input_file.data)
row_data = {
"upload_file": form.input_file.data.filename,
"output_file": custom_name,
"gcp_link": None,
"user": 'nki-tov'
}
return custom_name, result, constants.GeneralConstants.BUCKET_NAME, row_data
def get_valid_filename(s):
s = s.strip().replace(' ', '_')
return re.sub(r'(?u)[^-\w]', '', s)
def upload_to_bucket(blob_name, file, bucket_name, row_data):
'''
Upload file to a bucket
: blob_name (str) - object name
: file_path (str)
: bucket_name (str)
'''
bucket = storage_client.get_bucket(bucket_name)
blob = bucket.blob(blob_name)
blob.upload_from_file(file)
link = f'https://console.cloud.google.com/storage/browser/_details/{bucket_name}/{blob_name};tab=live_object?authuser=0'
row_data["gcp_link"] = link
traffic_row = urls_comparison_users_traffic(**row_data)
return link, traffic_row, blob_name
def main_func(queue: Queue, form):
res = get_file_from_form(form)
if res:
queue.put(upload_to_bucket(*res))
else:
queue.put(res) # None
What am I doing wrong?
Is it something to do with the architecture?
this is my first question here. I try to rewrite telegram bot in Python. And I cant solve one problem. When I test my bot by myself everything fine, but if another user connect with my bot script doesn`t start for him with initial state of variables. For example, in this code script increment x variable when user send "1". But for new user x already not null. Please help me to fix it.
import StringIO
import json
import logging
import random
import urllib
import urllib2
# for sending images
from PIL import Image
import multipart
# standard app engine imports
from google.appengine.api import urlfetch
from google.appengine.ext import ndb
import webapp2
TOKEN = 'TOKEN HERE'
BASE_URL = 'https://api.telegram.org/bot' + TOKEN + '/'
x = 0
# ================================
class EnableStatus(ndb.Model):
# key name: str(chat_id)
enabled = ndb.BooleanProperty(indexed=False, default=False)
# ================================
def setEnabled(chat_id, yes):
es = EnableStatus.get_or_insert(str(chat_id))
es.enabled = yes
es.put()
def getEnabled(chat_id):
es = EnableStatus.get_by_id(str(chat_id))
if es:
return es.enabled
return False
# ================================
class MeHandler(webapp2.RequestHandler):
def get(self):
urlfetch.set_default_fetch_deadline(60)
self.response.write(json.dumps(json.load(urllib2.urlopen(BASE_URL + 'getMe'))))
class GetUpdatesHandler(webapp2.RequestHandler):
def get(self):
urlfetch.set_default_fetch_deadline(60)
self.response.write(json.dumps(json.load(urllib2.urlopen(BASE_URL + 'getUpdates'))))
class SetWebhookHandler(webapp2.RequestHandler):
def get(self):
urlfetch.set_default_fetch_deadline(60)
url = self.request.get('url')
if url:
self.response.write(json.dumps(json.load(urllib2.urlopen(BASE_URL + 'setWebhook', urllib.urlencode({'url': url})))))
class WebhookHandler(webapp2.RequestHandler):
def post(self):
urlfetch.set_default_fetch_deadline(60)
body = json.loads(self.request.body)
logging.info('request body:')
logging.info(body)
self.response.write(json.dumps(body))
update_id = body['update_id']
message = body['message']
message_id = message.get('message_id')
date = message.get('date')
text = message.get('text')
fr = message.get('from')
chat = message['chat']
chat_id = chat['id']
if not text:
logging.info('no text')
return
def reply(msg=None, img=None):
if msg:
resp = urllib2.urlopen(BASE_URL + 'sendMessage', urllib.urlencode({
'chat_id': str(chat_id),
'text': msg.encode('utf-8'),
'disable_web_page_preview': 'true',
#'reply_to_message_id': str(message_id),
})).read()
elif img:
resp = multipart.post_multipart(BASE_URL + 'sendPhoto', [
('chat_id', str(chat_id)),
#('reply_to_message_id', str(message_id)),
], [
('photo', 'image.jpg', img),
])
else:
logging.error('no msg or img specified')
resp = None
logging.info('send response:')
logging.info(resp)
if text.startswith('/'):
if text == '/start':
reply('Bot start')
setEnabled(chat_id, True)
elif text == '/stop':
reply('Bot disabled')
setEnabled(chat_id, False)
else:
reply('What command?')
elif '1' in text:
global x
x = x + 1
reply(str(x))
else:
if getEnabled(chat_id):
reply('?')
else:
logging.info('not enabled for chat_id {}'.format(chat_id))
app = webapp2.WSGIApplication([
('/me', MeHandler),
('/updates', GetUpdatesHandler),
('/set_webhook', SetWebhookHandler),
('/webhook', WebhookHandler),
], debug=True)
Instead of variable x, you may want to use python dictionary like this -
x = {}
and then use it like this -
key = str(chat_id)
if key in x:
x[key] += 1
else:
x[key] = 1
Flask
Python 2.7
Postgres 9
Ubuntu 14.04
I'm using Flask and SQLAlchemy, after 15 consecutive HTTP requests I get:
QueuePool limit of size 5 overflow 10 reached, connection timed out, timeout 30
Then server stops responding:
Very similar as:
Flask-SQLAlchemy TimeoutError
I don't have session engine, per my understanding Flask-SQLAlchemy should take care of it.
What do I need to configure to support more sessions and to clean existing ones periodically.
app.py
import models
api_app = Flask(__name__)
api_app.config.from_pyfile(settings.celery_config)
db = SQLAlchemy(api_app)
#api_app.teardown_appcontext
def shutdown_session(exception=None):
try:
db.session.close()
except AttributeError,e:
print str(e)
except Exception,e:
print api_app.name
print str(e)
#api_app.route('/api/1.0/job/<string:ref>/')
def get_job_by_id(ref):
"""
:param id:
:return:
"""
try:
if request.method == 'GET':
job = models.Job.query.filter(models.Job.reference == ref)
if job:
job_ = job.all()
if len(job_) == 1:
return jsonify(job_[0].serialize())
resp = Response(status=404, mimetype='application/json')
return resp
else:
resp = Response(status=405, mimetype='application/json')
return resp
except Exception,e:
print str(e)
resp = Response(status=500, mimetype='application/json')
return resp
models.py
from api_app import db
class Job(db.Model, AutoSerialize, Serializer):
__tablename__ = 'job'
__public__ = ('status','description','reference')
id = Column(Integer, primary_key=True, server_default=text("nextval('job_id_seq'::regclass)"))
status = Column(String(40), nullable=False)
description = Column(String(200))
reference = Column(String(50))
def serialize(self):
d = Serializer.serialize(self)
del d['id']
return d
based on #spicyramen comment:
increase SQLALCHEMY_POOL_SIZE The size of the database pool.
I have a funny and strange bug in my facebook for websites. When I log a user in with facebook, as a user I must press reload to get the user data from the cookie. Otherwise the cookie doesn't find a user. If I press reload once after login and reload once after logout I can login and logout but that indicates I've been doing something wrong. Could you help my find the bug?
I used the code from https://gist.github.com/1190267 and tried logging the cookie lookup and it doesn't find a user first time:
def get_user_from_cookie(cookies, app_id, app_secret):
"""Parses the cookie set by the official Facebook JavaScript SDK.
cookies should be a dictionary-like object mapping cookie names to
cookie values.
If the user is logged in via Facebook, we return a dictionary with the
keys "uid" and "access_token". The former is the user's Facebook ID,
and the latter can be used to make authenticated requests to the Graph API.
If the user is not logged in, we return None.
Download the official Facebook JavaScript SDK at
http://github.com/facebook/connect-js/. Read more about Facebook
authentication at http://developers.facebook.com/docs/authentication/.
"""
logging.debug('getting user from cookie')
cookie = cookies.get("fbsr_" + app_id, "")
if not cookie:
logging.debug('no cookie found')
return None
The login URL I use is
https://www.facebook.com/dialog/oauth?client_id=164355773607006&redirect_uri=http://www.koolbusiness.com
and logging a login scenario doesn't get the cookie until a reload:
"GET /?code=AQB9sh9RWdZsUC_TBWFHLOnOKehjk2ls6kN1ZzCBQRFa6s2ra58e5slaBSI8lYwC5q9Q_f524nsrF-Ts-mgxAHc9xIvt3U7rufKlfJuNfkRbGwgPWZZLCYCwnWHPdb00ANd8QOHB_bYMaI-R_mdI3nQW6bRvpD0DR-SOW-jSvhS8bel4_KlzaBFY3DnYNvxhJgY HTTP/1.1" 200 6248 - "Mozilla/5.0 (X11; Linux x86_64; rv:2.0) Gecko/20100101 Firefox/4.0" "www.koolbusiness.com" ms=80 cpu_ms=0 api_cpu_ms=0 cpm_usd=0.000777 instance=00c61b117c460a7d3f730b42451a4153b74e
D 2011-11-22 07:36:28.182
getting user from cookie
D 2011-11-22 07:36:28.183
no cookie found
Why? Similarly when I try to log out I must do it twice and I can't see where the bug is. I've been trying to use as much serverside I can and I suspect that my problem is handling the cookie. Can you tell me what to do? My function to set the cookie is:
def set_cookie(self, name, value, expires=None):
if value is None:
value = 'deleted'
expires = datetime.timedelta(minutes=-50000)
jar = Cookie.SimpleCookie()
jar[name] = value
jar[name]['path'] = '/'
if expires:
if isinstance(expires, datetime.timedelta):
expires = datetime.datetime.now() + expires
if isinstance(expires, datetime.datetime):
expires = expires.strftime('%a, %d %b %Y %H:%M:%S')
jar[name]['expires'] = expires
self.response.headers.add_header(*jar.output().split(': ', 1))
And here are 2 classes that should do it for me. As I said, everything works if I reload which is very strange tht the cookie is not set after a facebook login and that the cookie is set just by reloading my index pge after an FB login.
Thank you
class BaseHandler(webapp2.RequestHandler):
facebook = None
user = None
csrf_protect = True
#property
def current_user(self):
if not hasattr(self, "_current_user"):
self._current_user = None
cookie = facebook.get_user_from_cookie(
self.request.cookies, facebookconf.FACEBOOK_APP_ID, facebookconf.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 = FBUser.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 = FBUser(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
#property
def current_sender(self):
if not hasattr(self, "_current_sender"):
self._current_sender = None
host=os.environ.get('HTTP_HOST', os.environ['SERVER_NAME'])
if host.find('.br') > 0:
sender = 'info#montao.com.br'
else:
sender = 'admin#koolbusiness.com'
self._current_sender = sender
return self._current_sender
#property
def current_logo(self):
if not hasattr(self, "_current_logo"):
self._current_logo = None
self._current_logo = os.environ.get('HTTP_HOST', os.environ['SERVER_NAME'])
return self._current_logo
def initialize(self, request, response):
"""General initialization for every request"""
super(BaseHandler, self).initialize(request, response)
try:
self.init_facebook()
self.init_csrf()
self.response.headers['P3P'] = 'CP=HONK' # iframe cookies in IE
except Exception, ex:
self.log_exception(ex)
raise
def handle_exception(self, ex, debug_mode):
"""Invoked for unhandled exceptions by webapp"""
self.log_exception(ex)
self.render('error',
trace=traceback.format_exc(), debug_mode=debug_mode)
def log_exception(self, ex):
"""Internal logging handler to reduce some App Engine noise in errors"""
msg = ((str(ex) or ex.__class__.__name__) +
': \n' + traceback.format_exc())
if isinstance(ex, urlfetch.DownloadError) or \
isinstance(ex, DeadlineExceededError) or \
isinstance(ex, CsrfException) or \
isinstance(ex, taskqueue.TransientError):
logging.warn(msg)
else:
logging.error(msg)
def set_cookie(self, name, value, expires=None):
if value is None:
value = 'deleted'
expires = datetime.timedelta(minutes=-50000)
jar = Cookie.SimpleCookie()
jar[name] = value
jar[name]['path'] = '/'
if expires:
if isinstance(expires, datetime.timedelta):
expires = datetime.datetime.now() + expires
if isinstance(expires, datetime.datetime):
expires = expires.strftime('%a, %d %b %Y %H:%M:%S')
jar[name]['expires'] = expires
self.response.headers.add_header(*jar.output().split(': ', 1))
def render_jinja(self, name, **data):
logo = 'Koolbusiness.com'
logo_url = '/_/img/kool_business.png'
analytics = 'UA-3492973-18'
domain = 'koolbusiness'
if get_host().find('.br') > 0:
cookie_django_language = 'pt-br'
logo = 'Montao.com.br'
logo_url = '/_/img/montao_small.gif'
analytics = 'UA-637933-12'
domain = None
elif get_host().find('allt') > 0 and not self.request.get('hl'):
logo = ''
cookie_django_language = 'sv'
elif get_host().find('gralumo') > 0 \
and not self.request.get('hl'):
cookie_django_language = 'es_AR'
else:
cookie_django_language = self.request.get('hl', '')
if cookie_django_language:
if cookie_django_language == 'unset':
del self.request.COOKIES['django_language']
else:
self.set_cookie('django_language', cookie_django_language)
translation.activate(cookie_django_language)
"""Render a Jinja2 template"""
if not data:
data = {}
data['js_conf'] = json.dumps({
'appId': facebookconf.FACEBOOK_APP_ID,
'canvasName': facebookconf.FACEBOOK_CANVAS_NAME,
'userIdOnServer': self.user.id if self.user else None,
})
data['logged_in_user'] = self.user
data['message'] = self.get_message()
data['csrf_token'] = self.csrf_token
data['canvas_name'] = facebookconf.FACEBOOK_CANVAS_NAME
data['current_user']=self.current_user
gkeys = ''
if os.environ.get('HTTP_HOST'):
url = os.environ['HTTP_HOST']
else:
url = os.environ['SERVER_NAME']
data['user']=users.get_current_user()
data['facebook_app_id']=facebookconf.FACEBOOK_APP_ID
user = users.get_current_user()
data['logout_url']=users.create_logout_url(self.request.uri) if users.get_current_user() else 'https://www.facebook.com/dialog/oauth?client_id='+facebookconf.FACEBOOK_APP_ID+'&redirect_uri='+self.request.uri
host=os.environ.get('HTTP_HOST', os.environ['SERVER_NAME'])
data['host']=host
if host.find('.br') > 0:
logo = 'Montao.com.br'
logo_url = '/_/img/montao_small.gif'
analytics = 'UA-637933-12'
domain = None
else:
logo = 'Koolbusiness.com'
logo_url = '/_/img/kool_business.png'
analytics = 'UA-3492973-18'
domain = 'koolbusiness'
data['domain']=domain
data['analytics']=analytics
data['logo']=logo
data['logo_url']=logo_url
data['admin']=users.is_current_user_admin()
if user:
data['greeting'] = ("Welcome, %s! (sign out)" %
(user.nickname(), users.create_logout_url("/")))
template = jinja_environment.get_template('templates/'+name+'.html')
self.response.out.write(template.render(data))
"""
self.response.out.write(template.render(
os.path.join(
os.path.dirname(__file__), 'templates', name + '.html'),
data))
"""
def render(self, name, **data):
logo = 'Koolbusiness.com'
logo_url = '/_/img/kool_business.png'
analytics = 'UA-3492973-18'
domain = 'koolbusiness'
if get_host().find('.br') > 0:
cookie_django_language = 'pt-br'
logo = 'Montao.com.br'
logo_url = '/_/img/montao_small.gif'
analytics = 'UA-637933-12'
domain = None
elif get_host().find('allt') > 0 and not self.request.get('hl'):
logo = ''
cookie_django_language = 'sv'
elif get_host().find('gralumo') > 0 \
and not self.request.get('hl'):
cookie_django_language = 'es_AR'
else:
cookie_django_language = self.request.get('hl', '')
if cookie_django_language:
if cookie_django_language == 'unset':
del self.request.COOKIES['django_language']
else:
self.set_cookie('django_language', cookie_django_language)
translation.activate(cookie_django_language)
"""Render a template"""
if not data:
data = {}
data['js_conf'] = json.dumps({
'appId': facebookconf.FACEBOOK_APP_ID,
'canvasName': facebookconf.FACEBOOK_CANVAS_NAME,
'userIdOnServer': self.user.id if self.user else None,
})
data['logged_in_user'] = self.user
data['message'] = self.get_message()
data['csrf_token'] = self.csrf_token
data['canvas_name'] = facebookconf.FACEBOOK_CANVAS_NAME
data['current_user']=self.current_user
data['user']=users.get_current_user()
data['facebook_app_id']=facebookconf.FACEBOOK_APP_ID
user = users.get_current_user()
data['logout_url']=users.create_logout_url(self.request.uri) if users.get_current_user() else 'https://www.facebook.com/dialog/oauth?client_id='+facebookconf.FACEBOOK_APP_ID+'&redirect_uri='+self.request.uri
host=os.environ.get('HTTP_HOST', os.environ['SERVER_NAME'])
data['host']=host
if not host.find('.br') > 0:
logo = 'Koolbusiness.com'
logo_url = '/_/img/kool_business.png'
analytics = 'UA-3492973-18'
domain = 'koolbusiness'
data['domain']=domain
data['analytics']=analytics
data['logo']=logo
data['logo_url']=logo_url
data['admin']=users.is_current_user_admin()
if user:
data['greeting'] = ("Welcome, %s! (sign out)" %
(user.nickname(), users.create_logout_url("/")))
gkeys = ''
if os.environ.get('HTTP_HOST'):
url = os.environ['HTTP_HOST']
else:
url = os.environ['SERVER_NAME']
self.response.out.write(template.render(
os.path.join(
os.path.dirname(__file__), 'templates', name + '.html'),
data))
def init_facebook(self):
facebook = Facebook()
user = None
# initial facebook request comes in as a POST with a signed_request
if 'signed_request' in self.request.POST:
facebook.load_signed_request(self.request.get('signed_request'))
# we reset the method to GET because a request from facebook with a
# signed_request uses POST for security reasons, despite it
# actually being a GET. in webapp causes loss of request.POST data.
self.request.method = 'GET'
#self.set_cookie(
#'', facebook.user_cookie, datetime.timedelta(minutes=1440))
elif 'u' in self.request.cookies:
facebook.load_signed_request(self.request.cookies.get('u'))
# try to load or create a user object
if facebook.user_id:
user = FBUser.get_by_key_name(facebook.user_id)
if user:
# update stored access_token
if facebook.access_token and \
facebook.access_token != user.access_token:
user.access_token = facebook.access_token
user.put()
# refresh data if we failed in doing so after a realtime ping
if user.dirty:
user.refresh_data()
# restore stored access_token if necessary
if not facebook.access_token:
facebook.access_token = user.access_token
if not user and facebook.access_token:
me = facebook.api('/me', {'fields': _USER_FIELDS})
try:
friends = [user['id'] for user in me['friends']['data']]
user = FBUser(key_name=facebook.user_id,
id=facebook.user_id, friends=friends,
access_token=facebook.access_token, name=me['name'],
email=me.get('email'), picture=me['picture'])
user.put()
except KeyError, ex:
pass # ignore if can't get the minimum fields
self.facebook = facebook
self.user = user
def init_csrf(self):
"""Issue and handle CSRF token as necessary"""
self.csrf_token = self.request.cookies.get('c')
if not self.csrf_token:
self.csrf_token = str(uuid4())[:8]
self.set_cookie('c', self.csrf_token)
if self.request.method == 'POST' and self.csrf_protect and \
self.csrf_token != self.request.get('_csrf_token'):
raise CsrfException('Missing or invalid CSRF token.')
def set_message(self, **obj):
"""Simple message support"""
self.set_cookie('m', base64.b64encode(json.dumps(obj)) if obj else None)
def get_message(self):
"""Get and clear the current message"""
message = self.request.cookies.get('m')
if message:
self.set_message() # clear the current cookie
return json.loads(base64.b64decode(message))
class Facebook(object):
"""Wraps the Facebook specific logic"""
def __init__(self, app_id=facebookconf.FACEBOOK_APP_ID,
app_secret=facebookconf.FACEBOOK_APP_SECRET):
self.app_id = app_id
self.app_secret = app_secret
self.user_id = None
self.access_token = None
self.signed_request = {}
def api(self, path, params=None, method='GET', domain='graph'):
"""Make API calls"""
if not params:
params = {}
params['method'] = method
if 'access_token' not in params and self.access_token:
params['access_token'] = self.access_token
result = json.loads(urlfetch.fetch(
url='https://' + domain + '.facebook.com' + path,
payload=urllib.urlencode(params),
method=urlfetch.POST,
headers={
'Content-Type': 'application/x-www-form-urlencoded'})
.content)
if isinstance(result, dict) and 'error' in result:
raise FacebookApiError(result)
return result
def load_signed_request(self, signed_request):
"""Load the user state from a signed_request value"""
try:
sig, payload = signed_request.split('.', 1)
sig = self.base64_url_decode(sig)
data = json.loads(self.base64_url_decode(payload))
expected_sig = hmac.new(
self.app_secret, msg=payload, digestmod=hashlib.sha256).digest()
# allow the signed_request to function for upto 1 day
if sig == expected_sig and \
data['issued_at'] > (time.time() - 86400):
self.signed_request = data
self.user_id = data.get('user_id')
self.access_token = data.get('oauth_token')
except ValueError, ex:
pass # ignore if can't split on dot
#property
def user_cookie(self):
"""Generate a signed_request value based on current state"""
if not self.user_id:
return
payload = self.base64_url_encode(json.dumps({
'user_id': self.user_id,
'issued_at': str(int(time.time())),
}))
sig = self.base64_url_encode(hmac.new(
self.app_secret, msg=payload, digestmod=hashlib.sha256).digest())
return sig + '.' + payload
#staticmethod
def base64_url_decode(data):
data = data.encode('ascii')
data += '=' * (4 - (len(data) % 4))
return base64.urlsafe_b64decode(data)
#staticmethod
def base64_url_encode(data):
return base64.urlsafe_b64encode(data).rstrip('=')
Solution: Avoid javascript, avoid cookies and use serverside OAuth 2.0 and it is much easier to follow what is going on and this works:
class FBUser(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()
access_token = db.StringProperty(required=True)
name = db.StringProperty(required=True)
picture = db.StringProperty()
email = db.StringProperty()
friends = db.StringListProperty()
dirty = db.BooleanProperty()
class I18NPage(I18NHandler):
def get(self):
if self.request.get('code'):
args = dict(
code = self.request.get('code'),
client_id = facebookconf.FACEBOOK_APP_ID,
client_secret = facebookconf.FACEBOOK_APP_SECRET,
redirect_uri = 'http://www.koolbusiness.com/',
)
logging.debug("client_id"+str(args))
file = urllib.urlopen("https://graph.facebook.com/oauth/access_token?" + urllib.urlencode(args))
try:
logging.debug("reading file")
token_response = file.read()
logging.debug("read file"+str(token_response))
finally:
file.close()
access_token = cgi.parse_qs(token_response)["access_token"][-1]
graph = main.GraphAPI(access_token)
user = graph.get_object("me") #write the access_token to the datastore
fbuser = main.FBUser.get_by_key_name(user["id"])
logging.debug("fbuser "+str(fbuser))
if not fbuser:
fbuser = main.FBUser(key_name=str(user["id"]),
id=str(user["id"]),
name=user["name"],
profile_url=user["link"],
access_token=access_token)
fbuser.put()
elif fbuser.access_token != access_token:
fbuser.access_token = access_token
fbuser.put()