500 error while deploying telegram bot to google app engine - google-app-engine

I'm new to telegram bot development, and I got stuck, while deploying project to GAE and creating webhooks
I have a simple bot, which I took from here https://github.com/sooyhwang/Simple-Echo-Telegram-Bot:
from flask import Flask, request
import telegram
import config
import logging
bot = telegram.Bot(config.token)
app = Flask(__name__)
URL = 'my-service-dot-kristik-160312.appspot.com/'
#def sendPhotoToServer() -> Bool:
# sending photo to server
# return
#app.route('/HOOK', methods=['POST'])
def webhook_handler():
if request.method == "POST":
update = telegram.Update.de_json(request.get_json(force=True))
chat_id = update.message.chat.id
text = update.message.text.encode('utf-8')
bot.sendMessage(chat_id=chat_id, text=text)
logging.getLogger().setLevel(logging.INFO)
logging.info('===============TEXT=================')
return 'ok'
#app.route('/set_webhook', methods=['GET', 'POST'])
def set_webhook():
s = bot.setWebhook('https://my-service-dot-kristik-160312.appspot.com/HOOK')
if s:
return "webhook setup ok"
else:
return "webhook setup failed"
#app.route('/')
def index():
return 'App is ready'
When I go to https://my-service-dot-kristik-160312.appspot.com/set_webhook I get 500 error.
What am I doing wrong?
Server logs:
5.254.65.88 - - [04/Mar/2017:00:53:54 +0300] "GET /set_webhook HTTP/1.1" 500 264 - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36" "my-service-dot-kristik-160312.appspot.com" ms=12 cpu_ms=18 cpm_usd=2.9504e-8 loading_request=0 instance=00c61b117c22a1c62e3fac7b35862e68e42b61f0284c2de4c4f50e319bcfa0d57efafc3b4e58 app_engine_release=1.9.48 trace_id=28ae78361cb2dde6bf4f6388ba535198
00:53:54.036
Entering: setWebhook
00:53:54.040
[2017-03-03 21:53:54,039] ERROR in app: Exception on /set_webhook [GET]
00:53:54.040
Traceback (most recent call last):
00:53:54.040
File "/base/data/home/apps/e~kristik-160312/my-service:20170303t195857.399582377782761728/lib/flask/app.py", line 1982, in wsgi_app
00:53:54.040
response = self.full_dispatch_request()
00:53:54.040
File "/base/data/home/apps/e~kristik-160312/my-service:20170303t195857.399582377782761728/lib/flask/app.py", line 1614, in full_dispatch_request
00:53:54.040
rv = self.handle_user_exception(e)
00:53:54.040
File "/base/data/home/apps/e~kristik-160312/my-service:20170303t195857.399582377782761728/lib/flask/app.py", line 1517, in handle_user_exception
00:53:54.040
reraise(exc_type, exc_value, tb)
00:53:54.040
File "/base/data/home/apps/e~kristik-160312/my-service:20170303t195857.399582377782761728/lib/flask/app.py", line 1612, in full_dispatch_request

Telegram Bot API Webhooks are not made to support redirections.
When you set the Webhook URL as the GAE, nothing works. Upon checking getWebhooInfo, you will get the last_error_message as Wrong response from the webhook: 302 Moved Temporarily
And yes, Google Script Content Service documentation says, content returned by the Content service isn't served from script.google.com, but instead redirected to a one-time URL at script.googleusercontent.com. This means that if you use the Content service to return data to another application, you must ensure that the HTTP client is configured to follow redirects
So, you cannot use Google Script URL as webhook

Related

React and Flask with Socket.IO - CORS problem

I'm trying to make a Flask server (port 5000) that has a socket.io connection with a React client (port 3000). When I try to execute the server script (shown below), I get an error that says "http://localhost:3000 is not an accepted origin" even though I am using CORS.
server-test.py:
from flask import Flask
from flask_socketio import SocketIO, emit
from flask_cors import CORS, cross_origin
import os
from dotenv import load_dotenv, find_dotenv
load_dotenv(find_dotenv())
app = Flask(__name__)
app.config['CORS_HEADERS'] = 'Content-Type'
app.config['SECRET_KEY'] = os.environ.get('SECRET')
socketio = SocketIO(app)
CORS(app)
#socketio.on('connect')
#cross_origin()
def handle_connection():
emit('server-client', 'Test message')
#socketio.on('client-server')
#cross_origin()
def handle_client_msg(msg):
print("\n" + str(msg))
if __name__ == '__main__':
app.run(host="localhost", port=os.environ.get('PORT'))
socketio.run(app)
App.jsx:
import { io } from 'socket.io-client';
// ...
useEffect(() => {
const socket = io('http://localhost:5000');
socket.on('server-client', msg => {
alert(msg);
socket.emit('client-server', 'Client: Message received!');
});
}, []);
Error message in WSL terminal:
* Serving Flask app 'server-test' (lazy loading)
* Environment: production
WARNING: This is a development server. Do not use it in a production deployment.
Use a production WSGI server instead.
* Debug mode: off
* Running on http://localhost:5000/ (Press CTRL+C to quit)
http://localhost:3000 is not an accepted origin. (further occurrences of this error will be logged with level INFO)
127.0.0.1 - - [16/May/2021 00:27:31] "GET /socket.io/?EIO=4&transport=polling&t=NboMpZQ HTTP/1.1" 400 -
127.0.0.1 - - [16/May/2021 00:27:31] "GET /socket.io/?EIO=4&transport=polling&t=NboMpZS HTTP/1.1" 400 -
127.0.0.1 - - [16/May/2021 00:27:31] "GET /socket.io/?EIO=4&transport=polling&t=NboMpZR.0 HTTP/1.1" 400 -
127.0.0.1 - - [16/May/2021 00:27:31] "GET /socket.io/?EIO=4&transport=polling&t=NboMpZR HTTP/1.1" 400 -
The Flask SocketIO documentation says this:
If an incoming HTTP or WebSocket request includes the Origin header, this header must match the scheme and host of the connection URL. In case of a mismatch, a 400 status code response is returned and the connection is rejected.
and this:
If necessary, the cors_allowed_origins option can be used to allow other origins. This argument can be set to a string to set a single allowed origin, or to a list to allow multiple origins. A special value of '*' can be used to instruct the server to allow all origins, but this should be done with care, as this could make the server vulnerable to Cross-Site Request Forgery (CSRF) attacks.
So instead of this:
socketio = SocketIO(app)
you could do this:
socketio = SocketIO(app, cors_allowed_origins="*")
Unrelated to the cors issue, but I also added return statements to the functions. Without returning something I got:
TypeError: The view function did not return a valid response.
Seems to be required if using the #cross_origin() decorators, so you could also remove those and then you don't need the return statements.

Permission denied during gcloud app deploy using Google Cloud SDK

It is insanely hard, to deploy an app to Google App Engine, using Google Cloud SDK.
I had tried the below 2 commands
C:\Users\yccheok\Desktop\jstock-android-appengine>gcloud config set project jstock-android
Updated property [core/project].
C:\Users\yccheok\Desktop\jstock-android-appengine>gcloud app deploy app.yaml --log-http --verbosity=debug
DEBUG: Running [gcloud.app.deploy] with arguments: [--log-http: "true", --verbosity: "debug", DEPLOYABLES:1: "['app.yaml']"]
DEBUG: No staging command found for runtime [python27] and environment [STANDARD].
DEBUG: API endpoint: [https://appengine.googleapis.com/], API version: [v1]
=======================
==== request start ====
uri: https://appengine.googleapis.com/v1/apps/jstock-android?alt=json
method: GET
== headers start ==
Authorization: Bearer ya29.GlxEBb1XVP1JK93-ARiaN_ZgiMbvZmw5KWfvJVfibDJ4FK_ZaMRoU1jVDTiWzsY606GSduJKJd9Nm8zA-_Iql5mGn4AMk4QVl8mPRycfekeZnOOHtbUvpkBMgOLOQA
accept: application/json
accept-encoding: gzip, deflate
content-length: 0
user-agent: google-cloud-sdk x_Tw5K8nnjoRAqULM9PFAC2b gcloud/184.0.0 command/gcloud.app.deploy invocation-id/c9ae232d33b346d787b95a36e28c38c0 environment/None environment-version/None interactive/True python/2.7.13 (Windows NT 10.0.16299)
== headers end ==
== body start ==
== body end ==
==== request end ====
---- response start ----
-- headers start --
-content-encoding: gzip
alt-svc: hq=":443"; ma=2592000; quic=51303431; quic=51303339; quic=51303338; quic=51303337; quic=51303335,quic=":443"; ma=2592000; v="41,39,38,37,35"
cache-control: private
content-length: 335
content-type: application/json; charset=UTF-8
date: Tue, 16 Jan 2018 19:16:21 GMT
server: ESF
status: 403
transfer-encoding: chunked
vary: Origin, X-Origin, Referer
x-content-type-options: nosniff
x-frame-options: SAMEORIGIN
x-xss-protection: 1; mode=block
-- headers end --
-- body start --
{
"error": {
"code": 403,
"message": "Operation not allowed",
"status": "PERMISSION_DENIED",
"details": [
{
"#type": "type.googleapis.com/google.rpc.ResourceInfo",
"resourceType": "gae.api",
"description": "The \"appengine.applications.get\" permission is required."
}
]
}
}
-- body end --
total round trip time (request+response): 1.796 secs
---- response end ----
----------------------
DEBUG: (gcloud.app.deploy) Permissions error fetching application [apps/jstock-android]. Please make sure you are using the correct project ID and that you have permission to view applications on the project.
Traceback (most recent call last):
File "C:\Program Files (x86)\Google\Cloud SDK\google-cloud-sdk\lib\googlecloudsdk\calliope\cli.py", line 797, in Execute
resources = calliope_command.Run(cli=self, args=args)
File "C:\Program Files (x86)\Google\Cloud SDK\google-cloud-sdk\lib\googlecloudsdk\calliope\backend.py", line 757, in Run
resources = command_instance.Run(args)
File "C:\Program Files (x86)\Google\Cloud SDK\google-cloud-sdk\lib\surface\app\deploy.py", line 65, in Run
parallel_build=False)
File "C:\Program Files (x86)\Google\Cloud SDK\google-cloud-sdk\lib\googlecloudsdk\command_lib\app\deploy_util.py", line 543, in RunDeploy
app = _PossiblyCreateApp(api_client, project)
File "C:\Program Files (x86)\Google\Cloud SDK\google-cloud-sdk\lib\googlecloudsdk\command_lib\app\deploy_util.py", line 703, in _PossiblyCreateApp
api_client._FormatApp()))) # pylint: disable=protected-access
HttpException: Permissions error fetching application [apps/jstock-android]. Please make sure you are using the correct project ID and that you have permission to view applications on the project.
ERROR: (gcloud.app.deploy) Permissions error fetching application [apps/jstock-android]. Please make sure you are using the correct project ID and that you have permission to view applications on the project.
C:\Users\yccheok\Desktop\jstock-android-appengine>
Then, I went through https://cloud.google.com/appengine/docs/admin-api/accessing-the-api , it mentioned I need to use Admin API. So, I do it step by step carefully.
Step 1
Step 2
It mentions Admin API is enabled. Now I need credential.
Step 3
Step 4
OK. Now they mention I don't need create new credential. I can use Application Default Credentials ?!
Step 5
So, I went to https://developers.google.com/identity/protocols/application-default-credentials?hl=en_GB . I learn that I need to run
C:\Users\yccheok\Desktop\jstock-android-appengine>gcloud auth application-default login
Your browser has been opened to visit:
https://accounts.google.com/o/oauth2/auth?redirect_uri=http%3A%2F%2Flocalhost%3A8085%2F&prompt=select_account&response_type=code&client_id=764086051850-6qr4p6gpi6hn506pt8ejuq83di341hur.apps.googleusercontent.com&scope=https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fuserinfo.email+https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fcloud-platform&access_type=offline
Credentials saved to file: [C:\Users\yccheok\AppData\Roaming\gcloud\application_default_credentials.json]
These credentials will be used by any library that requests
Application Default Credentials.
Step 6
Step 7
Still, after completing the above 7 steps, I still get the exact same error message, when trying to run
gcloud app deploy app.yaml --log-http --verbosity=debug
Can anyone let me know, what step I'm still require, in order to deploy my Python app to Google App Engine, using Google Cloud SDK?
The Admin API is for programmatically deploying the app, not for deploying using gcloud app deploy, for which you don't even need the Admin API enabled for your app.
From Deploying a Python App:
To programmatically deploy your apps, use the Admin API.
Before you begin
Before you can deploy your app:
The Owner of the GCP project must create the App Engine application.
Ensure that your user account includes the required privileges.
(but I can see how the above could be mis-intrepreted as an invitation to use the Admin API)
Most likely the account actually used by gcloud app deploy is missing or doesn't have the required permissions.
You can check the acount used with gcloud auth list. In my case the account is my email address, not a service account (I'm not sure if a service account can be used).
Use gcloud auth login (and maybe gcloud auth revoke) if you need a different account.
And you can check the account's privileges (if any) on the project/app on the IAM Page.
One additional note on this,
When you enable the App Engine API and the cloud builder api, make sure the Cloud Build Service Account also has access to the project.
I ran into that problem after enabling the correct apis.
This was using a build trigger. I could deploy locally from a command line because I was authenticated as myself. However, if you are using a build trigger, it will use the build service account, which needs access.
Hope this helps.
I had this issue. In my case it was solved by setting the project using the project ID, rather than the project name. See this answer
gcloud app deploy ERROR: Permissions error fetching application [apps/<PROJECT_NAME>]

Google App Engine Admin SDK Reports API returning 403 Insufficient Permission error

I started with some sample code for App Engine from Google.
My app needs to use the Directory API and the Reports API from the Google Admin SDK.
I have created a project in the API Console and turned on the Admin SDK in Services.
I added the scopes (the same ones as used in the code below) to the "Manage API client access" section of Advanced Tools in my domain's Google cpanel.
The call to the Directory API works.
After that, the call to the Reports API fails with the error message:
"HttpError: https://www.googleapis.com/admin/reports/v1/activity/users/all/applications/admin?alt=json returned "Insufficient Permission">"
Thanks much for the assistance.
import webapp2
import os
from apiclient.discovery import build
from oauth2client.appengine import OAuth2Decorator
from oauth2client.appengine import OAuth2DecoratorFromClientSecrets
from apiclient import errors
import logging
import json
decorator = OAuth2DecoratorFromClientSecrets(
os.path.join(os.path.dirname(__file__), 'client_secrets.json'),
'https://www.googleapis.com/auth/admin.directory.user.readonly')
directoryauthdecorator = OAuth2Decorator(
client_id='123.apps.googleusercontent.com',
client_secret='456-abc',
callback_path='/oauth2callback',
scope='https://www.googleapis.com/auth/admin.directory.user.readonly '
'https://www.googleapis.com/auth/admin.reports.audit.readonly '
'https://www.googleapis.com/auth/admin.reports.usage.readonly'
)
class MainHandler(webapp2.RequestHandler):
def get(self):
self.response.write('Hello world!')
class OAuthHandler(webapp2.RequestHandler):
#directoryauthdecorator.oauth_required
def get(self):
users = []
# Get the authorized Http object created by the decorator.
auth_http = directoryauthdecorator.http()
# Get the directory service
service = build("admin", "directory_v1", http=auth_http)
result = []
page_token = None
while True:
try:
param = {}
param['domain'] = 'mydomain.com'
if page_token:
param['pageToken'] = page_token
files = service.users().list(**param).execute()
result.extend(files['users'])
page_token = files.get('nextPageToken')
if not page_token:
break
except errors.HttpError, error:
print 'An error occurred: %s' % error
break
users = []
for user in result:
logging.info(user['primaryEmail'])
users.append(user['primaryEmail'])
param = {}
param['userKey'] = 'all'
param['applicationName'] = 'admin'
service = build('admin', 'reports_v1', http=auth_http)
# this call fails with the 403 Insufficient Permissions error
results = service.activities().list(**param).execute()
logging.info(results)
app = webapp2.WSGIApplication([
('/', MainHandler),
('/users', OAuthHandler),
(directoryauthdecorator.callback_path, directoryauthdecorator.callback_handler()),
], debug=True)
I read this post and cleared the credentials from the datastore.
Hitting the /users url again I got the redirect_uri error message.
I went back to the API project, fixed the Redirect URIs, and downloaded the client_secrets.json file.
Now both calls work (one to Directory API, the other to Reports API).

Receiving mail using Bottle on Google App Engine

I'm new to programming. I'm using Bottle on GAE. I want to receive and read mails (if it's possible).
This is my app.yaml file:
- url: /_ah/mail/contact#appid.appspotmail.com
script: main.py
login: admin
inbound_services:
- mail
This is (should be) my mail handler in the main.py file:
from google.appengine.api import mail
from google.appengine.ext.webapp.mail_handlers import InboundMailHandler
#route('/_ah/mail/contact#appid.appspotmail.com', method = 'POST')
def receive_mail():
pass
When I send an email to the above address in logs appears:
2012-09-03 17:03:00.878 /_ah/mail/contact#appid.appspotmail.com 200 187ms 0kb
0.1.0.20 - - [03/Sep/2012:07:03:00 -0700] "POST /_ah/mail/contact#appid.appspotmail.com HTTP/1.1" 200 59
How can I read/parse the mail?
Thank you in advance for any answer or comment.
You should be able to decode the POST body using mail.InboundEmailMessage like in webapp.InboundMailHandler
from google.appengine.api import mail
#route('/_ah/mail/contact#appid.appspotmail.com', method = 'POST')
def receive_mail():
message = mail.InboundEmailMessage(request.body)
logging.info("received email from: %s" % message.sender)

Error in deployed GAE RequestHandler using Webapp2

I am using the webapp2 framework on Google App Engine, and I'm getting a basic error in one of my Request Handlers.
The app is running ok in the local instance, but causes the following traceback on the deployed version of Google App Engine:
Here's the code:
import os
from google.appengine.ext.webapp import template
import webapp2
import logging
class MainHandler(webapp2.RequestHandler):
def get(self):
logging.info('hi there 34')
template_values = {}
self.response.out.write('hello world 4')
path = os.path.join(os.path.dirname(__file__), 'index.html')
## This is the code that causes the bug ##
self.response.out.write(template.render(path, template_values))
## ## ## ##
debug = os.environ.get('SERVER_SOFTWARE', '').startswith('Dev')
app = webapp2.WSGIApplication(
[(r'/main', MainHandler)],
debug = debug)
def main():
app.run()
traceback error:
Traceback (most recent call last):
File "/base/python27_runtime/python27_dist/lib/python2.7/wsgiref/handlers.py",
line 86, in run
self.finish_response()
File "/base/python27_runtime/python27_dist/lib/python2.7/wsgiref/handlers.py",
line 127, in finish_response
self.write(data)
File "/base/python27_runtime/python27_dist/lib/python2.7/wsgiref/handlers.py",
line 202, in write
assert type(data) is StringType,"write() argument must be string"
AssertionError: write() argument must be string
What does this error mean?
I think response does not take unicode data, so you have to encode it first:
content = template.render(path, template_values)
self.response.out.write(content.encode('utf-8'))
Also I recommend Werkzeug. It works well on appengine and makes life so much easier. It helps to deal with request and response data, url routing, provides http exceptions, has great debugger for offline development and more. I think Werkzeug is a must to have for every python web dev in their toolbox.

Resources