Flask CGI app issues with print statement - python

I have a simple flask application deployed using CGI+Apache running on a shared hosting server.
The app runs Flask 0.11.1 on Python 2.6 along with Flask-Mail 0.9.1.
One of the pages in the app has a contact form that sends an email and redirects back to the same page.
The contact form has a POST action to '/sendmail' that is defined in Flask controller as follows -
#app.route("/sendmail", methods=['GET','POST'])
def send_mail():
print "Sending Email"
mail = SendMail(app)
mail.send_mail(request.form['name'], request.form['mail'], request.form['phoneNo'], request.form['message'])
return render_template('contact.html')
Here's the issue -
With the code above, the app sends me an email successfully, however then gives an error '/sendmail' not found. The template fails to render.
If I remove the print statement from the snippet, the app renders contact.html successfully after sending the email.
What explains the behaviour of print statement in the snippet? Considering the execution is sequential, shouldn't the block fail at the print statement itself without sending the email instead of failing during rendering the template?

Print statement should not create an error as it is one of the statement like others. Instead since you are not checking for request.method=='POST', this should create and throw an error in your get request. To redirect to the same page return redirect("/sendmail") Do not forget to import from flask like this from flask import redirect

Related

Django Instagram authentication doesn't work as expected

I have pushed my django project onto pythonanywhere, a free hosting website.
The code works fine in my local and onto the web as well, but somehow have an issue with instagram authentication.
Instagram uses an oauth2 authentication system, in which when the user allows your application, it redirects the user to a specified URI and appends the code inside the URL which further can be used to authenticate the user.
Instagram doesn't allow localhosts as valid redirect URL, therefore for the testing I have used something like this
InstaAuth.html
<script>
history.pushState(null, null, '?code=AQD_4...q6#_');
function reloadThePage() {
window.location.reload();
}
</script>
<button type="submit" class="btn btn-primary" onclick="reloadThePage()">Continue</button>
which changes the state of the url but doesn't actually refresh it. Then I have button which refresh the current page, which directly trigger below code in my views.py and gets the code through request.GET['code'].
Views.py
def instaAuth(request):
if 'code' in dict(request.GET).keys():
code = request.GET['code']
print('the given code is', code)
core = instaCore()
user_id, short_lived_access_token = core.code_to_short_access_with_userid(code_string=code)
print(user_id)
obj = InstaModel.objects.get(username=request.user)
obj.instagram_userid = user_id
obj.short_lived_access_token = short_lived_access_token
obj.is_active = True
obj.save()
print('all data saved!')
messages.success(request, "Your instagram is connected!")
return render(request, 'authentication/success.html')
return render(request, 'authentication/instaAuth.html')
Above code works perfectly fine when I add the code using pushState mehod and refresh the page using button. but when I do the same in my webapp, authorising the app and then clicking continue button, it throughs the KeyError at /instaAuth 'access_token'.
This error usually occurs when someone tries to use the same oauth code more than once. When I looked into the logs I found the error in the same line where I was exchanging the oauth code with the access token. I tried to look into the network tab of the requests, but I am not sure what is missing. I have done similar thing using streamlit and it worked fine, you can check the streamlit app here https://instalogintest.herokuapp.com/
I am stuck at this place, I want to have some logic which either doesn't refresh the page or a way that django knows that this request is coming from Instagram and verify the user using the code.
Problem solved after going through everything for a whole day. Can't believe it was such a small mistake.
I didn't change the redirect uri when I was exchanging the code with access_token.
The problem was I was not printing the error, it always through try and error block, will never do the same again.
Always use this syntax
try
do_something()
except Exception as e:
print(e)
do_something_else()

Problems with django api on second request

I am working on a flutter app for creating schedules for teachers. I created a Django project to generate a schedule based on the data in the post request from the user. This post request is sent from the flutter app. The Django project doesn't use a database or anything, It simply receives the input data, creates the schedule and returns the output data back to the user.
The problem is that the process of creating the schedule only works 1 time after starting the Django server. So when I want another user to send a request and receive a schedule I have to restart the server... Maybe the server remembers part of the data from the previous request?? I don't know. Is there somekind of way to make it forget everything after a request is done?
When I try to repeatedly run the scheduler without being in a Django project it works flawlessly. The Scheduler is based on the Google cp_model sat solver. (from ortools.sat.python import cp_model). The error I get when running the scheduler the second time in a Django project is 'TypeError: LonelyDuoLearner_is_present_Ss9QV7qFVvXBzTe3R6lmHkMBEWn1_0 is not a boolean variable'.
Is there some kind of way to fix this or mimic the effect of restarting the server?
The django view looks like this:
from django.http import HttpResponse
from django.views.decorators.csrf import csrf_exempt
from .scheduler.planning import Planning
from .scheduler.planning import print_json
import json
# Convert the data and creates the schedule.
#csrf_exempt
def generate_schedule(request):
if request.method == 'POST':
try:
data = json.loads(request.body)
planning = Planning()
planning.from_json(data)
output_json = planning.output_to_json()
print_json(output_json)
response = json.dumps(output_json)
except Exception as e:
print(e)
print("The data provided doesn't have the right structure.")
response = json.dumps([{'Error': "The data provided doesn't have the right structure."}])
else:
response = json.dumps([{'Error': 'Nothing to see here, please leave.'}])
return HttpResponse(response, content_type='text/json')
There is no beautiful way to restart the server (aside from just killing it by force, which is hardly beautiful).
You're probably using some global state somewhere in the code you're not showing, and it gets screwed up.
You should fix that instead, or if you can't do so, run the solving in a subprocess (using e.g. subprocess.check_call(), or multiprocessing.Process()).
The CP-SAT solver is stateless. The only persistent/shared object is the Ctrl-C handler, which can be disabled with a sat parameter. (catch_sigint if my memory is correct).

Google signin API using oauth Post Method in python flask server

I got question about implementing google login. I was able to implement Google Login button on my react app using an open source library called react-google-login. I was able to set up the backend server using python flask. I host my api method on the api on Heroku: http://arrangement-server.herokuapp.com/login.
And my react app runs successfully locally, and I am able to use login-in button. But, my issue is that my server displays the following error:
Method not Allowed.
Is this because it is post method?
Why is it my Server shows me that that method is not allowed?
Even though on the client side it runs fine, and I am able to see user profile and user information.
Here's the code to my backend server, you can find it at Github:
#app.route("/login", methods=['POST'])
def login():
data = request.json
session['access_token'] = data['access_token'], ''
return jsonify({'message':'You are logged in.'})
Your "login" endpoint will accept only "POST" HTTP requests. Because of this line:
#app.route("/login", methods=['POST'])
When you try to open your page in a browser - the browser will send the "GET" HTTP request to that URL.
That is why you are getting "Method Not Allowed" error.
Take a look at my answer on upwork for more details.
Your heroku server is only a backend server.
And the route "/login" accepts only POST request.
So you can't send the GET request to this route on web browser.
If you want to look at the response with this route, you can send the POST request by using POSTMAN.
I think this part
#app.route("/")
def home_page():
access_token = session.get('access_token')
if access_token is None:
return redirect(url_for('login'))
Always force user to visit login page with GET method. Unfortunately you don't have method and route defined to handle this GET method.

Changing GET to POST in Python (Flask)

I am trying to create a simple app where an array of integers is generated on the server and sent to the client. Here is some sample (working) code in app.py:
from flask import Flask, render_template, request, url_for
import random
app = Flask(__name__)
#app.route('/')
def form():
s_abc = [random.random() for _ in range(40)]
return render_template('abc.html', s_abc=s_abc)
if __name__ == '__main__':
app.run(debug=True)
And here is a (working) snippet of abc.html:
<div>
{{s_abc}}
</div>
The problem is, this code uses the GET HTTP method (which Flask uses by default when none is specified). I would like to instead use the POST HTTP method, since it is apparently more secure for sending data. (Source: http://blog.teamtreehouse.com/the-definitive-guide-to-get-vs-post)
To do this, I tried to change:
#app.route('/')
to:
#app.route('/', methods=['POST'])
Unfortunately, I got an error: "Method Not Allowed: The method is not allowed for the requested URL."
Question: How should I fix this?
[Note: From what I currently understand, I would need to create a form to use the POST method, but I don't think my website would need a form, since the client isn't sending data to the server. (In my website, the server is sending data to the client.)]
[Note: This is similar to a question I asked previously, but not the same, because here I am asking about a specific error message, Method not Allowed.]
You should not be using the POST method in this instance. The POST method is meant to be used when you are changing data on the server. In this case you are only retrieving data, so GET is the more appropriate method to use here.
In any case, if you do decide to use POST, your code is actually working. You can see this if you use a POST request to access the endpoint:
$ curl -X POST http://127.0.0.1:5000/
<div>
[0.03464541692036849, 0.5588700799957625, 0.4702806873145451, 0.7525198710149907, 0.0674801622743858, 0.28229897849445273, 0.17400190415782735, 0.48911931330821357, 0.8033543541248421, 0.16335301905982258, 0.3307436416488905, 0.11670066397858725, 0.552907551276049, 0.6699689958218984, 0.7444295210533091, 0.8258885497774587, 0.8656500198078877, 0.6826827672886756, 0.27219907080455874, 0.9053285546116574, 0.8328655798090894, 0.2323223157770763, 0.9775485685217323, 0.34887389370958166, 0.17092511319368353, 0.20875570398480459, 0.6744092445507751, 0.6176283706166301, 0.05070680888843082, 0.3441890248079591, 0.17701427714228501, 0.115329649057473, 0.325114272097177, 0.19386610624431766, 0.18892384889766745, 0.511139418514318, 0.019931284111035397, 0.5240369332606203, 0.8936272011794374, 0.9665936114223397]
</div>
If you just access the URL in your browser, this will actually send a GET request, and you have modified your code to specifically only allow the POST method - which is why you get the Method Not Allowed response.
$ curl -X GET http://127.0.0.1:5000/
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
<title>405 Method Not Allowed</title>
<h1>Method Not Allowed</h1>
<p>The method is not allowed for the requested URL.</p>
The best solution is for you to use GET in this instance.
When you use the browser to visit a page, the browser always send 'GET' request to server... so when you've changed the methods to 'POST', flask can't find any GET route for '/' and return "Method Not Allowed" error, as the '/' doesn't allows GET anymore when browsers asks for that page.
You shouldn't use POST for this. POST only used when submitting data from forms or ajax.

Plivo python message

I'm creating a web app in Python with Bottle which has the task to retrieve messages from Plivo. First, when I send a message to Plivo, it's like if I didn't. I can't find a Python example and I don't know much about web protocols and so on to configure all by myself.
I have the following issues which I haven't been able to fix:
1. Setting up Plivo to forward messages. In the site, you can create applications with these input options:
Application name
Sub account
Answer url
Answer method
Fallback_answer url
Fallback method
Hangup url
Hangup method
Message url
Message method
Default number app
Default endpoint app
Public uri
Setting up at least part of it should get my messages to my server. I don't know what.
2. I've got the following python code:
from bottle import route, run, request
#route('/hello', method=['GET', 'POST'])
def hello():
return "Hello World!"
bottlelog = open('bottlelog.txt').read
bottlelog.append(request + '\n')
bottlelog.close()
run(host='0.0.0.0', port=8080, debug=True)
It should save the request information in this file but at least right now it doesn't.
3. Answer. Should my server answer something specific when Plivo notifies me of my messages?
I hope that you can help me at least to find out where I should head to resolve my problems. Excuse me if I'm kind of messy, I'm new to web development and I'm just getting to know stuff.
Thank you all
Your Plivo number must be linked to an application which has a "Message url" present. When an SMS is received on your number, Plivo will send a hook to the "Message url" with the parameters Text, From, To, Type and MessageUUID. The HTTP method used to send these parameters is the "Message method" set in the application.
For the setup you described, your bottle server is listening on 8080 and has a route /hello/ open. Your Message Url should be http://<your-server-name>:8080/hello/ and the Message method should be set as POST. Click on "Create" to create your application
Next step is to link your Plivo number to the application you just created. Click on the "Numbers" tab in the dashboard. You will be able to see all your Plivo numbers under the "Your Numbers" section. By clicking on the number you'll be given an option to choose your application. Select the "Receive Message" app and click on "Update".
This sample code should get you up and running.
from bottle import run, request, HTTPResponse
#route('/hello/', method=['POST'])
def hello():
Text = request.forms.get('Text')
From = request.forms.get('From')
print "Message received: %s - by %s" % (Text, From)
return HTTPResponse(status=200)
run(host='0.0.0.0', port=8080, debug=True)
Run this code on your server and you'll be able to see the incoming messages on the console when an SMS is received on your Plivo number.

Categories