4

I have a protected view in my app which just accepts POST requests.

@app.route("/booking", methods=("POST", ))
@login_required
def booking():
     arg1 = request.form.get("arg1")
     arg2 = request.form.get("arg2")

When an unauthorized user tries to access this view, I want them to login and then be redirected here.

Right now, my login view looks like this:

@app.route("/login", methods=("GET", "POST"))
@login_required
def login():
     do_login()
     return redirect(request.args.get('next') or url_for('home'))

So what ends up happening is a POST request to /booking (which is the "next" parameter) and I get a NOT ALLOWED error.

The problem is that login() makes a GET request to booking(). I can get around that, but I am not sure how to retrieve the original POST form arguments from /booking? Any ideas to get round that?

taras
  • 6,566
  • 10
  • 39
  • 50
signalseeker
  • 4,100
  • 7
  • 30
  • 36
  • If you're asking how to make it so that redirect will redirect the user to back to `/booking` as a POST with the body of the original POST, you can't do that as part of HTTP. See the answer to [this question](http://stackoverflow.com/questions/46582/response-redirect-with-post-instead-of-get) for why. Redirects in HTTP use GET methods. That question is about ASP.NET, but the answer talks about HTTP in general. – Mark Hildreth Feb 10 '14 at 16:33
  • Thanks, I am happy making a GET request for the redirect, but I am not sure, how to preserve the body of the original POST request. – signalseeker Feb 10 '14 at 16:42
  • 2
    Any way you want to. Of course, you cannot continue to use the login_required decorator, since it assumes you're just forgetting anything the user sent. You'll need to change your view to, if the user is not logged in, save the data (in the session or a database with a way to identify the user's session) then after the user logs in look to see if there is any "saved" data. If so, perhaps forward them to a screen that says "Do you want to continue with this", with a form that they can POST and continue the process from that data. – Mark Hildreth Feb 10 '14 at 17:05

2 Answers2

0

I would solve this by pulling the data and putting it in the session. You can remove the @login_required decorator and check this in the function using current_user.is_authorized. See Flask Sessions and Flask Login.

Something like this might work for you, I didn't test it:

from flask import session
from flask_login import current_user

@app.route("/booking", methods=("POST", ))
def booking():
     if not 'arg1' in session.keys() and not 'arg2' in session.keys():  
         session['arg1'] = request.form.get("arg1")
         session['arg2'] = request.form.get("arg2")
         # Now the data will persist in the session

     if current_user.is_authorized:
       # Do what you need...
     else:
       # Redirect to login, session will persist
Mike
  • 2,514
  • 2
  • 23
  • 37
-1

Why would you only use POST in the booking view ? You are probably rendering a form which should also allow GET.

@app.route("/booking", methods=['GET','POST'])
@login_required
def booking():
    # render the form. something like
    form = BookingForm()

    # Check if POST
    if request.method == 'POST':
        # process the form now and do whatever you need. 
        return redirect(url_for('index'))

    # code below will run if not POST. You should render the template here
    return render_templte('booking.html')
codegeek
  • 32,236
  • 12
  • 63
  • 63