Cherrypy respond to unmounted or incorrect url - url

I have been confused by the following:
I have a class TestLink mounted to the url /testlink
class TestLink(object):
exposed = True
#cherrypy.expose
#cherrypy.tools.accept(media='text/plain')
def GET(self, var=None, **params):
return "data:1,2\\nzelta:3,4"
if __name__ == '__main__':
app = cherrypy.tree.mount(
TestLink(), '/testlink',
"test.config"
)
And I use the Cherrypy rest dispatcher in my "test.config" file:
request.dispatch = cherrypy.dispatch.MethodDispatcher()
And when I hit start the server and hit the url "http://127.0.0.1:8080/testlink", I get the result. However, I also get result if I hit the url http://127.0.0.1:8080/testlink/x or "http://127.0.0.1:8080/testlink/anything_string". Why does this happen, shouldn't only the url "http://127.0.0.1:8080/testlink" return data?

Given your code example, if you try to access http://127.0.0.1:8080/testlink/foo/bar cherrypy will respond with 404 Not Found. This is because MethodDispatcher is interpreting 'foo' as value of the parameter 'var', as you specified in the signature of GET().
Here's a modified working version of your example:
import cherrypy
config = {
'/': {
'request.dispatch': cherrypy.dispatch.MethodDispatcher(),
'tools.trailing_slash.on': False,
}
}
class TestLink(object):
exposed = True
## not necessary, you want to use MethodDispatcher. See docs.
##cherrypy.expose
#cherrypy.tools.accept(media='text/plain')
def GET(self, var=None, **params):
print var, params
return "data:1,2\\nzelta:3,4"
if __name__ == '__main__':
app = cherrypy.tree.mount(TestLink(), '/testlink', config)
cherrypy.engine.start()
cherrypy.engine.block()
Now try http://127.0.0.1:8080/testlink/foo, it will print
foo {}
whereas hitting http://127.0.0.1:8080/testlink/foo/bar will lead to 404.
See the docs https://cherrypy.readthedocs.org/en/3.3.0/refman/_cpdispatch.html, or of course you could investigate the code in the module cherrypy/_cpdispatch.py yourself.

Related

Rails 6 how to handle 404 from Github file fetching using Octokit

In my Rails 6 app I'm trying to implement functionality which is responsible for fetching the file from a different Github repo. The code should try to fetch file name.json or name.master.json from GitHub (because the file could be either master json or standard json).
Code below:
#lib/github_client.rb
module GithubClient
extend self
def fetch_file(file_name)
if (response = translate(file_name)).success?
response
else
translate(file_name, master: true)
end
end
private
def client
#client ||= Octokit::Client.new(access_token: Rails.application.credentials.github[:access_token])
end
def translate(file_name, master: false)
return client.contents('user/my-repo-name', path: "#{file_name}.master.json") if master == 'true'
client.contents('user/my-repo-name', path: "#{file_name}.json")
end
end
Line if (response = translate(file_name)).success?does not work because if there is no file e.g. book.master.json it will return:
Octokit::NotFound (GET https://api.github.com/repos/user/my-repo-name/book.json: 404 - Not Found // See: https://docs.github.com/rest/reference/repos#get-repository-content)
How can I check the status of this response so that it will search for another file if necessary?
I'm not sure if there's an #exists? method or similar, which would probably be a better solution (I can't see such a method in the documentation!...), but you could always just rescue the exception in order to handle an expected failure gracefully. For example:
client.contents('user/my-repo-name', path: "#{file_name}.json")
rescue Octokit::NotFound
client.contents('user/my-repo-name', path: "#{file_name}.master.json")
Note that your current code is also slightly wrong since you're checking if master == 'true' -- but master is a boolean value (true / false), not a String ("true").
true != "true"

Get and Post data in Flask request

Hello and thanks in advance for any help.
I am trying to set up a ReactJS & Flask Web App, but i am having trouble getting the data into Flask, i am using Insomnia to test send the data to Flask, and the POST request returns code 200, but i keep on getting the error on the printscreen below, UnboundLocalError: local variable 'text' referenced before assignment. The string is not passed to the TTS (text-to-speech) class for processing, when i use direct assignment for the strings on the comented code bellow the imports works fine.
I have tried to send the data with JSON, now i am trying with form format, it returns the same error.
Can you help me, please, and take a look at my code ?
from flask import Flask, render_template, request
import speak
# text = "AI AI minha machadinha !!"
# lang = "pt"
app = Flask(__name__, static_folder="../static/dist", template_folder="../static")
#app.route("/", methods=["GET","POST"])
def index():
return render_template("index.html")
#app.route("/hello", methods=["GET","POST"])
def hello():
if request.method == "POST":
text = request.form["text"]
lang = request.form["lang"]
print("passou")
return speak.get_speak(text,lang)
if __name__ == "__main__":
app.run()
Insomnia code 200 message
error on console log
Try this below :
#app.route("/hello", methods=["GET","POST"])
def hello():
text = ''
if request.method == "POST":
text = request.form["text"]
lang = request.form["lang"]
print("passou")
return speak.get_speak(text,lang)
This is beacause your text is defined inside if condition and your return is outside the if condition. You need to define it above the if and give it a default value.

How to create a fallback intent in Amazon Lex or call a Lamda when error is triggered?

I have a small bot on amazon lex, I am unable to figure out a way to define a default intent or a fallback intent.
As of now, Amazon Lex does not support any fallback intent or default intent. However I have found a workaround. Here's what I did.
Setup an API Gateway and Lambda function in between your chat-client and the Lex.
Your chat-client will send request to API Gateway, API Gateway will forward this to Lambda function and Lambda function will forward the request to Lex (Lex will have one more lambda function). While returning the response from Lex, you can check in the Lambda function if it's an error message and trigger some action.
In the Lambda function we can use something like this:
import logging
import boto3
logger = logging.getLogger()
logger.setLevel(logging.DEBUG)
client_run = boto3.client('lex-runtime')
client_model = boto3.client('lex-models')
def lambda_handler(event, context):
response = client_run.post_text(
botName='name_of_your_bot',
botAlias='alias_of_your_bot',
userId='some_id',
sessionAttributes={
'key1': 'value1'
},
inputText=event['user_query']
)
bot_details = client_model.get_bot(
name='name_of_your_bot',
versionOrAlias='$LATEST'
)
for content in bot_details['clarificationPrompt']['messages']:
if response["message"] == content['content']:
return error_handling_method(event)
for content in bot_details['abortStatement']['messages']:
if response["message"] == content['content']:
return error_handling_method(event)
return response["message"]
Hope it helps.

Account Kit returning previous number and account kit ID when a new number is verified

I am testing Account Kit (Basic Web version - phone number verification) on a Django (Python) based web app. One thing I try is logging with multiple accounts on localhost, and trying to link a different number to each one successively. If a number has already successfully attached to a previous account, I show an "already taken" error prompt. Standard stuff.
I've been noticing that I sporadically get the "already taken" error prompt on unused numbers as well. Investigating deeper, I found that although I had input and verified (via SMS) a new number, the account kit ID and mobile number returned to me was the previous pair.
I can't tell why this is happening. Can someone help me in debugging this? In case it matters, my authorization flow uses the app secret.
Following are some relevant snippets. First, the Account Kit Manager class I've written:
from myproj.account_kit_settings import FAID, AKAS
class AccountKitManager(object):
obj = None
def __init__(self, app_id, app_secret):
self.app_secret = app_secret
self.app_access_token = 'AA|{0}|{1}'.format(app_id, app_secret)
def get_user_cred(self, auth_code):
if not self.obj:
self.set_user_cred(auth_code)
return self.obj
def set_user_cred(self, auth_code, url=None):
if not url:
url = 'https://graph.accountkit.com/v1.2/access_token?grant_type=authorization_code&code={0}&access_token={1}&appsecret_proof={2}'.\
format(auth_code,self.app_access_token,self.get_appsecret_proof(self.app_access_token))
data = self.retrieve_data(url)
data = self.evaluate_data(data)
string_obj = self.retrieve_user_cred(data["access_token"])
self.obj = self.evaluate_data(string_obj)
def retrieve_user_cred(self, user_access_token, url=None):
if not url:
url = 'https://graph.accountkit.com/v1.2/me/?access_token={0}&appsecret_proof={1}'.\
format(user_access_token,self.get_appsecret_proof(user_access_token))
return self.retrieve_data(url)
def retrieve_data(self, url):
return requests.get(url).text
def evaluate_data(self, data):
return ast.literal_eval(data)
def get_appsecret_proof(self, access_token):
h = hmac.new(self.app_secret.encode('utf-8'),msg=access_token.encode('utf-8'),digestmod=hashlib.sha256)
return h.hexdigest()
Next, here's how I use it:
mobile_data = AccountKitManager(FAID, AKAS)
def account_kit_handshake(csrf, state, status, auth_code):
if csrf == state and status=='PARTIALLY_AUTHENTICATED':
user_data = mobile_data.get_user_cred(auth_code)
if FAID == user_data["application"]["id"]:
return user_data["id"], user_data["phone"]
else:
# app id mismatch
return None, None
else:
# csrf mismatch, or could not authenticate
return None, None
def get_requirements(request):
status = request.GET.get('status', None)
auth_code = request.GET.get('code', None)
state = request.GET.get('state', None)
return account_kit_handshake(request.session["csrf"], state, status, auth_code)
def verify_consumer_number(request,*args,**kwargs):
AK_ID, MN_data = get_requirements(request)
request.session.pop("csrf",None)
if AK_ID and MN_data:
if someone_elses_number(MN_data['national_number'], request.user.id):
return render(request,"used_number.html",{})
else:
save_consumer_credentials.delay(AK_ID, MN_data, request.user.id)
return redirect("classified_listing")
else:
return render(request,"unverified_number.html",{})
UPDATE: Seems the user access token isn't always being returned. This could be a problem with variable scope.
The problem emanated from the scope of the AccountKitManager class instance. It was being set globally (i.e. see mobile_data variable in my code). Making this variable local solved the problem.

python-eve custom media storage file upload not working

I am trying to build a python-eve REST API with mysql backend and I would like to have a custom mediastorage backend. Basicly I want the filenames saved into database and files in filesystem.
Here is a draft of the mediastorage based on the GridFS in the core:
class CustomMediaStorage(MediaStorage):
def __init__(self, app=None):
super(CustomMediaStorage, self).__init__(app)
self.validate()
def validate(self):
if self.app is None:
raise TypeError('Application object cannot be None')
if not isinstance(self.app, Flask):
raise TypeError('Application object must be a Eve application')
def get(self, path, resource=None):
pprint(path)
_file = None
try:
_file = open(path, 'r')
except:
pass
return _file
def post(self, content, filename=None, content_type=None, resource=None):
pprint('post')
if(filename):
path = 'var/www/koodit/upload/'+filename
try:
_file = open(path, 'w')
_file.write(content)
_file.close()
except:
pass
return path
My specific problem here is that while the class catches the get-method the post-method does not seem to be able even to print out the comment.
Calling the media storage this way:
app = Eve(data=SQL,settings=SETTINGS, media=CustomMediaStorage)
From client side I tried to send the image as base64.
"file was expected, got 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAgAAAQABAAD/7QCEUGhvdG9zaG9wIDMu...
instead.",

Resources