I have a Flask app where I want to create playlists using Spotify API. My issue is similar to this Stackoverflow question.
The difference is that I am using OAuthlib instead of requests and the solution posted there didn't work in my case.
The problem
In the http request, when I set data={'name': 'playlist_name', 'description': 'something'},
I am getting a response: "error": {"status": 400,"message": "Error parsing JSON."}
But when I follow the answer mentioned above and try this: data=json.dumps({'name': 'playlist_name', 'description': 'something'}),
I am getting following error in the console: "ValueError: not enough values to unpack (expected 2, got 1)".
How I can fix this? Here is a simplified version of my app:
app.py
from flask import Flask, url_for, session
from flask_oauthlib.client import OAuth
import json
app = Flask(__name__)
app.secret_key = 'development'
oauth = OAuth(app)
spotify = oauth.remote_app(
'spotify',
consumer_key=CLIENT,
consumer_secret=SECRET,
request_token_params={'scope': 'playlist-modify-public playlist-modify-private'},
base_url='https://accounts.spotify.com',
request_token_url=None,
access_token_url='/api/token',
authorize_url='https://accounts.spotify.com/authorize'
)
#app.route('/', methods=['GET', 'POST'])
def index():
callback = url_for(
'create_playlist',
_external=True
)
return spotify.authorize(callback=callback)
#app.route('/playlist', methods=['GET', 'POST'])
def create_playlist():
resp = spotify.authorized_response()
session['oauth_token'] = (resp['access_token'], '')
username = USER
return spotify.post('https://api.spotify.com/v1/users/' + username + '/playlists',
data=json.dumps({'name': 'playlist_name', 'description': 'something'}))
#spotify.tokengetter
def get_spotify_oauth_token():
return session.get('oauth_token')
if __name__ == '__main__':
app.run()
You are using the data parameter, which takes a dict object, but you are dumping it to a string, which is not necessary. Also, you have to set the format to json, as follow:
#app.route('/playlist', methods=['GET', 'POST'])
def create_playlist():
resp = spotify.authorized_response()
session['oauth_token'] = (resp['access_token'], '')
username = USER
return spotify.post('https://api.spotify.com/v1/users/' + username + '/playlists',
data={'name': 'playlist_name', 'description': 'something'}, format='json')
Related
I'm currently having some trouble with my flask webapp, where I have written it as below, but when I try to run the flask app, I run into a Bad Request Error. (The browser (or proxy) sent a request that this server could not understand)
Essentially, I am trying to allow users to log in to an external website through the flask webapp
What is the cause of this error? Apologies if I am making a stupid mistake, I'm very new to flask.
from flask import Flask,render_template, request, redirect
import requests
from bs4 import BeautifulSoup as bs
app = Flask(__name__)
#app.route('/', methods = ["POST", "GET"])
def login():
username = request.form['username']
pin = request.form['password']
s = requests.Session()
r = s.get("https://www.example.com/User/Login")
soup = bs(r.text, 'html.parser')
loginToken = soup.findAll(attrs={"name" : "__RequestVerificationToken"})[0]['value']
#Create Login Payload
login_payload = {
"__RequestVerificationToken" : loginToken,
"UserName" : username,
"Password" : pin,
"returnUrl" : "https://example.com/user-action/?action=login&returnUrl=https://www.example.com/User/Information",
}
#Post Login Payload
r = s.post("https://www.example.com/Account/Login", data = login_payload)
if r.status_code == 200:
return render_template('home.html')
else:
return render_template('login.html')
return render_template('login.html')
#app.route('/home') #If login works, redirect to this page
def hello_world():
return 'Hello, World!'
if __name__ == "__main__":
app.run(debug = True)
In addition, if there are other resources that I could refer to with regards to allowing a user to log in to a external URL from the flask webapp as compared to the conventional tutorials that only show a user logging in to the flask webapp itself, do share it with me, thank you!
Your endpoint' s has two Http verbs ["POST", "GET"]. You should specify your methods as below.
#app.route('/', methods = ["POST", "GET"])
def login():
if request.method == "GET":
#something do stuff
return render_template("your_html_page")
if request.method == "POST":
#something do stuff
return your_response, 200
Edited Block
#app.route('/', methods = ["POST", "GET"])
def login():
if request.method == "GET":
return render_template('login.html')
if request.method == "POST":
#same logic here
if status_code == 200:
return redirect(url_for('home'))
return render_template('login.html')
New to Flask and Python. I've cloned a github Flask chat app example and am trying to get a referrer URL (i.e. the URL the user was in before going into my app). However, when I run the app locally, the referrer link always come back as None if the request comes from an external URL. If it is sent from within the app, I am getting the right referrer URL.
Here's the relevant bits of code. I've tried looking at previous questions, but couldn't find a solution.
My routing logic:
from flask import session, redirect, url_for, render_template, request
from . import main
from .forms import LoginForm
#main.before_request
def before_request():
print("Ref1:", request.referrer)
print("Ref2:", request.values.get("url"))
#main.route('/', methods=['GET', 'POST'])
def index():
form = LoginForm()
ip_address = request.access_route[0] or request.remote_addr
print("ip_addr:", ip_address)
if form.validate_on_submit():
session['name'] = form.name.data
session['room'] = form.room.data
return redirect(url_for('.chat'))
elif request.method == 'GET':
form.name.data = session.get('name', '')
form.room.data = session.get('room', '')
return render_template('index.html', form=form)
#main.route('/chat')
def chat():
name = session.get('name', '')
room = session.get('room', '')
if name == '' or room == '':
return redirect(url_for('.index'))
return render_template('chat.html', name=name, room=room)
My main app code is:
#!/bin/env python
from app import create_app, socketio
app = create_app(debug=True)
if __name__ == '__main__':
socketio.run(app)
Would really appreciate any advice.
Thanks!
I am new to flask and python, i am trying to add login required and all routes other than home page. I read about flask-login module, haven't had any success. Looking for suggestions !
I tried using flask-login and prevent access of "/data" route. It did not work. My login requirement is very simple, allow login if user pass is admin/admin. And make sure the user is logged in for all subsequent routes.
Here is my flask code
from flask import Flask, render_template, redirect, url_for, request
import subprocess
import os
import datetime
import time
app = Flask(__name__)
#app.route("/")
def home():
now = datetime.datetime.now()
timeString = now.strftime("%Y-%m-%d %H:%M")
templateData = {
'title' : 'HELLO!',
'time': timeString
}
return render_template('main.html', **templateData)
#app.route('/login', methods=['GET', 'POST'])
def login():
error = None
if request.method == 'POST':
if request.form['username'] != 'admin' or request.form['password'] != 'admin':
error = 'Invalid Credentials. Please try again.'
else:
return redirect(url_for('data'))
return render_template('login.html', error=error)
#app.route("/data")
def data():
now = datetime.datetime.now()
timeString = now.strftime("%Y-%m-%d %H:%M")
templateData = {
'title' : 'HELLO!',
'time': timeString
}
return render_template('api.html', **templateData)
if __name__ == "__main__":
app.run(host='0.0.0.0', debug=True)
I dont want /data route to be accessed without login as admin/admin
flask_login should do the trick.
import and use the '#login_required' decorator on any route that you want to make unavailable to users who aren't currently logged in.
from flask_login import login_required
#app.route("/data")
#login_required
def data():
...
...
leave the decorator off of any routes that don't require login.
since you only have need for generic authentication you might look into session login.
for this, you'll need a secret key...
import secrets
app = Flask(__name__)
app.config['SECRET_KEY'] = secrets.token_hex(16)
and an example usage of flask session management.
from flask import session
#app.route('/login', methods=['GET', 'POST'])
def login():
error = None
if request.method == 'POST':
if request.form['username'] != 'admin' or request.form['password'] != 'admin':
error = 'Invalid Credentials. Please try again.'
else:
session['logged_in'] = True
return redirect(url_for('data'))
return render_template('login.html', error=error)
I have a flask application, where I want to add a recaptcha field. I use it to verify, that an email can be sent. here is my code so far:
from flask import render_template, request, flash, session, url_for, redirect
from flask import Flask
from flask_mail import Mail, Message
from flask_recaptcha import ReCaptcha
app.config.update({'RECAPTCHA_ENABLED': True,
'RECAPTCHA_SITE_KEY':
'6LdJ4GcUAAAAAN0hnsIFLyzzJ6MWaWb7WaEZ1wKi',
'RECAPTCHA_SECRET_KEY':
'secret-key'})
app=Flask(__name__)
recaptcha = ReCaptcha(app=app)
mail_settings = {
"MAIL_SERVER": 'smtp.gmail.com',
"MAIL_PORT": 465,
"MAIL_USE_SSL": True,
"MAIL_USERNAME": 'USERNAME',
"MAIL_PASSWORD": 'PASSWORD'
}
app.config.update(mail_settings)
mail = Mail(app)
#app.route('/')
def index():
return render_template('index.html')
#app.route('/mail', methods=['GET', 'POST'])
def send_mail():
r = requests.post('https://www.google.com/recaptcha/api/siteverify',
data = {'secret' :
'secret_key',
'response' :
request.form['g-recaptcha-response']})
google_response = json.loads(r.text)
print('JSON: ', google_response)
if google_response['success']:
msg = Message('Thank you for contacting me', sender='kristofferlocktolboll#gmail.com', recipients = [request.form['email']])
msg.body ='sut den'
mail.send(msg)
return render_template('index.html')
else:
return render_template('index.html')
app.run(debug=True)
The problem is that whenever I have the flask_recaptcha import ReCaptcha I get the following error:
it looks like the import statement is incorrect, but since I'm not using WTForms, I don't know what do else. Whenever I remove the import statement it gives a syntax error instead (which makes sense)
Usage: flask run [OPTIONS]
Error: The file/path provided (routes) does not appear to exist.
Please verify the path is correct. If app is not on PYTHONPATH,
ensure the extension is .py
I'm currently working on creating a Cookie from an endpoint. As my backend and frontend only interacts via RESTful endpoints, is there anyway I can create a cookie when the frontend calls my backend's endpoint?
flask.make_response.set_cookie() doesn't seem to work for me. Also, I can't use app.route('/') to set my cookie either.
You can do this with Set-Cookie header returning with a response.
from flask import Flask
from flask_restful import Resource, Api
app = Flask(__name__)
api = Api(app)
class HelloWorld(Resource):
def get(self):
return {'task': 'Hello world'}, 200, {'Set-Cookie': 'name=Nicholas'}
api.add_resource(HelloWorld, '/')
if __name__ == '__main__':
app.run(debug=True)
Setting the header in the response tuple is one of the standard approaches. However, keep in mind that the Set-Cookie header can be specified multiple times, which means that a python Dictionary won't be the most effective way to set the cookies in the response.
According to the flask docs the header object can also be initialized with a list of tuples, which might be more convenient in some cases.
Example:
from flask import Flask
from flask_restful import Api, Resource
app = Flask(__name__, static_url_path='')
api = Api(app)
class CookieHeaders(Resource):
def get(self):
# Will only set one cookie "age = 23"
return { 'message' : 'Made with dict'}, 200, { 'Set-Cookie':'name=john', 'Set-Cookie':'age=23' }
def post(self):
# Will set both cookies "name = john" and "age = 23"
headers = [ ('Set-Cookie', 'name=john'), ('Set-Cookie', 'age=23') ]
return { 'message' : ' Made with a list of tuples'}, 200, headers
api.add_resource(CookieHeaders, '/')
if __name__ == '__main__':
app.run(debug=True)
The GET call will only set 1 cookie (due to the lack of multi-key support in python dictionaries), but the POST call will set both.
Flask has a #after_this_request callback decorator. (see: http://flask.pocoo.org/docs/1.0/api/#flask.after_this_request)
so you can set your cookies in it
from flask import after_this_request
from flask_restful import Resource
class FooResource(Resource):
def get(self):
#after_this_request
def set_is_bar_cookie(response):
response.set_cookie('is_bar', 'no', max_age=64800, httponly=True)
return response
return {'data': 'foooo'}
or even
from flask import after_this_request, request
from flask_restful import Resource, abort
class FooResource(Resource):
def get(self):
self._check_is_bar()
return {'data': 'foooo'}
def _check_is_bar(self)
if request.cookies.get('is_bar') == 'yes':
abort(403)
#after_this_request
def set_is_bar_cookie(response):
response.set_cookie('is_bar', 'no', max_age=64800, httponly=True)
return response