Prahlad Yeri
Prahlad Yeri

Reputation: 3653

Flask throwing "Could not build url for endpoint 'index'" after adding a decorator

I've a custom app written with flask and I'm trying to add an authentication decorator (d_auth), so that I don't have to check whether the user has authenticated or not within each routing function. The decorator works fine, but the problem is that url_for("index") fails after the user signs in. Here is my code for the decorator and the index routing function where I've added that decorator:

def d_auth(func):
    wraps(func)
    def decorated(*ags, **kgs):
        #print("DECORATOR_RUNNING")
        login_valid = (flask.session.get('auth_email') != None)
        if not login_valid: 
            return redirect(url_for("login"))
        else:
            #func(*args, **kwargs)
            return func(*ags, *kgs)
            #pass
    return decorated

@app.route("/", methods=["GET", "POST"])
@d_auth
def index():
    creds = gdrive.get_gdrive_credentials(session['auth_user_id'])
    if not creds:
        info = "<h2 id='lblGAuthStatus' class='text-center text-danger'> <span class='glyphicon glyphicon-alert'></span> NOT Authenticated. <a href='/gdrive_auth'>Click here to Authenticate.</a></h2>"
    elif creds.access_token_expired:
        info = "<h2 id='lblGAuthStatus' class='text-center text-danger'> <span class='glyphicon glyphicon-alert'></span> Access Token EXPIRED. <a href='/gdrive_auth'>Click here to Authenticate.</a></h2>"
    else:
        info = "<h2 id='lblGAuthStatus' class='text-center text-success'> <span class='glyphicon glyphicon-ok'></span> Successfully Authenticated.</h2>"

    return render_template('static/index.html', info=info)

What the decorator basically does is check whether the user has logged-in or not (not login_valid) and redirects them to login page if they haven't. This works perfectly. Problem is that once the user logs in and the login page tries to redirect them to the index page back again, it throws this error:

werkzeug.routing.BuildError: Could not build url for endpoint 'index'. Did you mean 'view' instead?

Here is the code for the /login route:

@app.route("/login", methods=["GET", "POST"])
def login():
    if request.method == 'GET':
        return render_template("static/login.html")
    elif request.method == 'POST':
        email = request.form['email']
        password = request.form['password']
        conn, cursor = db.opendb()
        cursor.execute("select id, is_admin, first_name, last_name from user where email=? and password=?", (email, password))
        row = cursor.fetchone()
        if row == None:
            return render_template("static/login.html", error="Invalid Credentials")
        else:
            session['auth_user_id'] = str(row['id'])
            session['auth_email'] = email
            session['auth_first_name'] = row['first_name']
            session['auth_last_name'] = row['last_name']
            session['auth_is_admin'] = row['is_admin']
            return redirect(url_for("index"))

On that last line, url_for("index") is being called and that's where the error is coming. I know I can workaround with url_for("/") instead which is working, but I want to fix this permanently so that something else may not stop working in my relatively large code-base.

Upvotes: 2

Views: 835

Answers (1)

Prahlad Yeri
Prahlad Yeri

Reputation: 3653

I just found an answer to my question here. Turns out that I've to wrap a decorator function using the @wraps(func), not simply wraps(func) like I'd done. Wonder why it didn't throw an error!

Upvotes: 3

Related Questions