问题
It should be a trivial job but i cannot get it out.
I need to call the Google Calendar API from Gae; thus I set all up as per Google docs and examples:
I've an /auth.py
:
CLIENT_SECRETS = os.path.join(os.path.dirname(__file__), 'client_secrets.json')
SCOPES = [
'https://www.googleapis.com/auth/calendar',
]
decorator = appengine.OAuth2DecoratorFromClientSecrets(
filename=CLIENT_SECRETS,
scope=SCOPES,
cache=memcache,
prompt='consent',
)
called by main.py
functions:
class Landing(webapp2.RequestHandler):
@auth.decorator.oauth_aware
def get(self):
if auth.decorator.has_credentials():
self.redirect('/in')
else:
self.response.out.write('''
etc. {}'''.format(auth.decorator.authorize_url()))
class Main(webapp2.RequestHandler):
@auth.decorator.oauth_required
def get(self):
links = { ... }
render(self, 'base.html', template_values=links)
class Calendar(webapp2.RequestHandler):
@auth.decorator.oauth_required
def get(self):
service = build('calendar', 'v3', http=auth.decorator.http())
api_request = service.events().list(calendarId='primary')
api_response = api_request.execute()
self.response.headers['Content-Type'] = 'application/json; charset=utf-8'
self.response.out.write(json.dumps(api_response, indent=4))
class PutEvent(webapp2.RequestHandler):
@auth.decorator.oauth_required
def post(self):
# ...
# http = httplib2.Http(memcache)
service = build('calendar', 'v3') #, http=http)
api_response = []
for i in json.loads(self.request.get('events')):
# ...
event = { ... } # Google Calendar event
api_request = service.events().insert(calendarId='primary', body=scadenza)
api_response.append(api_request.execute(http=auth.decorator.http()))
self.response.headers['Content-Type'] = 'application/json; charset=utf-8'
self.response.out.write(json.dumps(api_response, indent=4))
As you can see this is a fairly simple post
requested by an Ajax jQuery call ($.post('{{ putEvent_url }}', jsonData, function( data ){ console.log(data); })
...
I'm in the development server, using test@example
user, and the app is authorized to access my personal account's Google Calendar.
Strange thing to me is that any call to Calendar() works as expected, but call to PutEvent() end in ERROR 500.
Looking to the end of the traceback in console:
File "/home/pierpaolo/Devnos/whiterabbit/include/oauth2client/contrib/appengine.py", line 644, in check_oauth
resp = method(request_handler, *args, **kwargs)
File "/home/pierpaolo/Devnos/whiterabbit/main.py", line 211, in post
api_response.append(api_request.execute(http=auth.decorator.http()))
File "/home/pierpaolo/Devnos/whiterabbit/include/oauth2client/_helpers.py", line 133, in positional_wrapper
return wrapped(*args, **kwargs)
File "/home/pierpaolo/Devnos/whiterabbit/include/googleapiclient/http.py", line 838, in execute
raise HttpError(resp, content, uri=self.uri)
HttpError: <HttpError 403 when requesting https://www.googleapis.com/calendar/v3/calendars/primary/events?alt=json returned "Forbidden">
INFO 2017-01-04 15:13:32,385 module.py:788] default: "POST /api/put/scadenze HTTP/1.1" 500 -
I cannot understand the
HttpError: https://www.googleapis.com/calendar/v3/calendars/primary/events?alt=json returned "Forbidden">
it looks to me I already granted the app access to my account and that Google App Engine decorators have been correctly put in place to make the OAuth2.0 thing as per https://developers.google.com/api-client-library/python/guide/google_app_engine...
EDIT: I was wondering if my trouble can be related to the way i call Google Calendar API:
HTML/JS GAE/Py
+------------------+
| |
| <form> |
| ...data |
| <\JS/Ajax |
| $.post(...data | --> GAE/main.py
| | @auth.decorator.oauth_required
| | def post(self, data):
+------------------+ event = elaborate(data)
service = build('calendar', 'v3')
api_request = service.events()
.insert(calendarId='primary',
body=event)
api_response = api_request
.execute(auth.decorator
.http())
self.response(api_response)
EDIT 3:
I looked a bit into oauth2client.contrib.appengine and I added some logger.debug
here and there: I think the problem could be in execute(http=decorator.http())
call, but it is the same in my other handlers! Neither positional nor keyword nor put authrized Http in service build
changes the misbehaviour...
Nor can I see what problem may pose _helpers.py", line 133, in positional_wrapper
...
Dear all, some hint on how to research further?
Actually, I can insert Acl and/or insert a secondary calendar in the same RequestHandler that throws Forbidden exception with events().insert()...!
回答1:
I haven't got enough reputation to comment so I'll just leave it as an answer:
Firstly, double check that you've got calandar api enabled at https://console.cloud.google.com/apis/dashboard?project=yourproject
Secondly. I've used the contacts API and discovered that once you've granted access once you cannot be granted access again unless you first revoke the initial allowance. I encountered this when a user connected my app to Google Contacts, then disconnected, then tried to reconnect - the second reconnect would fail. To check / revoke, head to https://security.google.com/settings/security/permissions
回答2:
Apparently, the problem is to try to insert an all-day event with endTimeUnspecified: True
...
I opened an issue on google-api-python-client GitHub tracker: https://github.com/google/google-api-python-client/issues/334.
Maybe someone will look into it or post a more precise answer.
Thank you all.
来源:https://stackoverflow.com/questions/41467982/app-engine-call-to-google-api-python-client-return-403-with-oauth-required