How to create a web push notification using Flask - python

I'm trying to implement a web push notification in my project. Using some tutorials I got create an alert on index page when I post a message. But it's far from being what I want.
index.html
<html>
<head>
<title>Test Page</title>
</head>
<body>
<h1>Testing...</h1>
</body>
<script
src="https://code.jquery.com/jquery-2.2.4.min.js"
integrity="sha256-BbhdlvQf/xTY9gja0Dq3HiwQF8LaCRTXxZKRutelT44="
crossorigin="anonymous"></script>
<script type="text/javascript">
var source = new EventSource('/stream');
source.onmessage = function (event) {
alert(event.data);
};
</script>
</html>
post.html
<html>
<head>
<title>Posting a Message</title>
</head>
<body>
<form action="{{url_for('post')}}" method='post'>
Message: <input type="text" name="message" size='50'> <input type="submit" value="Launch!">
</form>
</body>
</html>
app.py
#!/usr/bin/env python
from flask import Flask, render_template, request, session, Response
from redis import Redis
import datetime
app = Flask(__name__)
app.secret_key = 'asdf'
red = Redis(host='localhost', port=6379, db=0)
def event_stream():
pubsub = red.pubsub()
pubsub.subscribe('notification')
for message in pubsub.listen():
print message
yield 'data: %s\n\n' % message['data']
#app.route('/post', methods=['POST','GET'])
def post():
if request.method=="POST":
message = request.form['message']
now = datetime.datetime.now().replace(microsecond=0).time()
red.publish('notification', u'[%s] %s: %s' % (now.isoformat(), 'Aviso', message))
return render_template('post.html')
#app.route('/stream')
def stream():
return Response(event_stream(),
mimetype="text/event-stream")
#app.route('/')
def index():
return render_template('index.html')
if __name__=="__main__":
app.run(host='0.0.0.0', port=8001, debug=True,threaded=True)
Well, I would like to implement a subscribe system, I think that is how is called. The user allow to receive notification from the website and when he clicks on the "news" it opens a new page with the detailed content.
The index page does not need to be opened for receving the message.

Related

How to upload a (csv) file with an AJAX call and Flask

I'm updating on updating an older project that uses AJAX and have decided to use Flask to do so. For the particular page I'm currently working on, I need to be able to upload a CSV and read the data in the file (no need to save it). I have several other pages that work using AJAX, but they return form data back to Flask (e.g. what semester it is, what year it is, etc). Ideally, I'd like to be able to upload the CSV and read the form data (the variables I have called formData and myFormData below).
I have found this post and based my MWE on it, but when I look at request.files, I get an empty dictionary. Here is the code I have:
run.py:
import os
from app import app
if __name__ == "__main__":
port = int(os.environ.get("PORT", 5000))
app.run(host='0.0.0.0', port=port, debug=True)
__init__.py:
from flask import Flask, session
import flask_excel as excel
from fileUpload import fileUpload_bp
def create_app():
app = Flask(__name__, template_folder="templates")
app.secret_key = 'flask-ajax file upload test'
app.register_blueprint(fileUpload_bp)
excel.init_excel(app)
return app
app = create_app()
file_upload.py:
from flask import Flask, render_template, request, Blueprint
fileUpload_bp=Blueprint('fileUpload',__name__)
#fileUpload_bp.route('/fileUpload',methods=['GET','POST'])
def fileUpload():
if request.method=="POST":
print(request.files)
return render_template("fileUpload.html")
fileUpload.html:
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>file upload test</title>
<script type="text/javascript"
src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<script type="text/javascript"
src="static/scripts/fileUpload.js"></script>
</head>
<body>
<form action="javascript:fileUpload()" method="POST" enctype="multipart/form-data">
<input type="file" id="file_upload_data"><br>
<input type="text" id="form_data" value="sample data">
<button type="submit">Upload</button>
</form>
</body>
</html>
fileUpload.js:
function fileUpload()
{
var formData=new FormData($("file_upload_data")[0]);
var myFormData={form_data: $("#form_data").val()};
$.ajax({
type: 'post',
dataType: 'html',
url: 'fileUpload',
async: false,
data: formData,
contentType: false,
cache: false,
processData: false,
success: function (data){
console.log('Success');
},
error: function(response, status, xml) {
console.log('failure');
}
});
}
A little additional info: This is part of a larger project which is why I'm using Blueprints and flask_excel. I've seen folks recommend using something other than AJAX, but I'm trying to make the pages run with python3 by using Flask without rewriting everything that's already there.
So that the form can be serialized, it is necessary for the input fields to have a name attribute.
I'm using the form's submit event in the following minimal example. The event listener is registered when the document is fully loaded. When the form is submitted, the form data is serialized and sent via ajax.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Upload</title>
</head>
<body>
<form name="upload-form" method="post" enctype="multipart/form-data">
<input type="file" name="file">
<button type="submit">Upload</button>
</form>
<script type="text/javascript"
src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<script type="text/javascript">
$(document).ready(function() {
// Register the listener for submit events.
$('form[name="upload-form"]').submit(function(evt) {
// Prevent the form from default behavior.
evt.preventDefault();
// Serialize the form data. The entire form is passed as a parameter.
const formData = new FormData($(this)[0]);
// Send the data via ajax.
$.ajax({
type: 'post',
url: '/upload',
data: formData,
contentType: false,
cache: false,
processData: false,
}).done(function(data) {
console.log('success');
}).fail(function(xhr, status, error) {
console.error('error');
});
});
});
</script>
</body>
</html>
The server-side code remains essentially the same. However, I advise you, for reasons of cleanliness, to separate endpoints for ajax requests from those that return html.
from flask import Flask
from flask import make_response, render_template, request
app = Flask(__name__)
#app.route('/')
def index():
return render_template('index.html')
#app.route('/upload', methods=['POST'])
def upload():
print(request.files)
return make_response('', 200)

Flask request.args,get not working properly

I want to use request.args.get() and log my data out into the console. So, I want the console to log {username: "ani", room: "1"} but it is only printing out {username: "ani", room: ""}. Here is my app.py-
from flask import Flask, render_template, request, redirect, url_for
from flask_socketio import SocketIO, join_room
app = Flask(__name__)
socketio = SocketIO(app)
#app.route('/')
def home():
return render_template('index.html')
#app.route('/chat')
def chat():
username = request.args.get('username')
room = request.args.get('room')
if username and room:
return render_template('chat.html', username=username, room=room)
else:
redirect(url_for('home'))
#socketio.on('join_room')
def handle_join_room(data):
app.logger.info("{} has joined room {}".format(
data['username'], data['room']))
join_room(data['room'])
socketio.emit('join_room_announcement', data)
if __name__ == '__main__':
socketio.run(app, debug=True)
Here is my chat.html-
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Chat App</title>
</head>
<body>
<h1>Welcome to room {{ room }}</h1>
<div id="messages"></div>
<form>
<input type="text" placeholder="Enter your message here" />
<button type="submit">Send</button>
</form>
</body>
<script
src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/3.1.1/socket.io.js"
integrity="sha512-oFOCo2/3DtjrJG4N27BjSLQWoiBv171sK6a+JiWjp/7agxC2nCUP358AqzxkBUb5jX8g6CYLPdSKQTbC0weCwA=="
crossorigin="anonymous"
></script>
<script>
const socket = io.connect('http://127.0.0.1:5000/');
socket.on('connect', () => {
socket.emit('join_room', {
username: '{{ username }}',
room: '{{ id }}',
});
});
socket.on('join_room_announcement', (data) => {
console.log(data);
});
</script>
</html>
It also does this in the terminal saying ani has joined room when it should say the room id.
Welcome to {{ Room {{ room }} still works in chat.html as it shows me the room id there. Please help. If you need any more information, you can comment.
In your script block in HTML you are trying to access room via variable name id as below
room: '{{ id }}',
But in flask you are setting the value to room. So use below
room: '{{ room }}',
Above change will address both console.log issue and terminal logging issue.

POST method is not working on Flask application - Error 404

I am trying to build a simple Flask application that will run a web app that connects to a Postgres database.
However, when I run the code and click the submit button, the POST method does not work, so it does return the {{url_for('success]}} as specified. I have tried adding and removing several components.
I have methods=['GET', 'POST'] already.
app.py:
from flask import Flask, render_template, request
from flask_sqlalchemy import SQLAlchemy
from sqlalchemy.sql import func
app=Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI']='postgresql://postgres:postgres#localhost/Jeopardy'
db=SQLAlchemy(app)
class Data(db.Model):
__tablename__="allc"
number = db.Column(db.Integer, primary_key=True)
category = db.Column(db.String())
question = db.Column(db.String())
answer = db.Column(db.String())
def __init__(self,number,category,question,answer):
self.number = number
self.category = category
self.question = question
self.answer = answer
#app.route("/")
def index():
return render_template("index.html")
#app.route("/success", methods=['POST','GET'])
def success():
if request.method=='POST':
category=request.form['category']
question=request.form['question']
answer=request.form['answer']
number=request.form['number']
print(email, height)
if db.session.query(Data).filter(Data.number == number).count()== 0:
data=Data(number,category,question,answer)
db.session.add(data)
db.session.commit()
return render_template("success.html")
if __name__ == '__main__':
app.debug=True
app.run()
index.html:
<html lang="en">
<title>Jeopardy</title>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device=width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<link href="../static/style.css" rel="stylesheet" >
</head>
<body>
<div class="="container">
<img src="../static/logo.png" alt="Jeopardy" class ="logo">
<!-- #todo - message-->
<form action = "s{{url_for('success')}}" methods="POST">
<div class = " form-group">
<h3>Jeopardy Question</h3>
<input
type = "number"
name = "Index"
placeholder= "Type number" />
<input
type = "text"
name = "Question"
placeholder= "Type the Jeopardy question here" />
<input
type = "text"
name = "Answer"
placeholder= "Type the Jeopardy Answer here"/>
<button type = "submit"> Submit</button>
</form>
</div>
</body>
</html>
While running the code my app renders successfully, but when submitting a number the server does not register the input. When loading the success page separately, it loads.
In the terminal, I see: "POST /success HTTP/1.1" 404 -
You have a typo in your html
It should be method="post" and not methods="post"
EDIT:
Another typo in
action = "s{{url_for('success')}}"
Remove the "s"
here is typo:
<form action = "s{{url_for('success')}}" methods="POST">
change it to:
<form action = "{{url_for('success')}}" method="POST">

Python flask upload file using ajax request.files empty

I am trying to upload an image about 1.62MB to an end point written using flask. the request.files object is always empty. I've checked the following questions but no luck:
Flask request.files is empty
https://github.com/requests/requests/issues/2505
How to upload a file using an ajax call in flask
here is my server:
from flask import Flask, request, jsonify, render_template
import sys
app = Flask(__name__)
app.config['UPLOAD_FOLDER'] = r"C:\Temp"
app.debug = True
#app.route("/demo-upload", methods=["GET", "POST"])
def ProcessImage():
if request.method == "POST":
print(request.files)
try:
if 'file' in request.files:
with open("test-upload.png", "wb") as iFile:
print(request['file'])
iFile.write(request.files['file'])
except Exception as e:
print(e)
return jsonify("Ok")
#app.route("/", methods=["GET"])
def DemoIndexPage():
return render_template("index.html")
if __name__ == "__main__":
app.run()
my client:
<!DOCTYPE html>
<html lang="en" xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta charset="utf-8" />
<script src="https://code.jquery.com/jquery-2.2.4.min.js"
integrity="sha256-BbhdlvQf/xTY9gja0Dq3HiwQF8LaCRTXxZKRutelT44="
crossorigin="anonymous"></script>
<title>Demo</title>
</head>
<body>
<h1 style="text-align: center">Status Demo</h1>
<span>upload image to process.</span><br/>
<form id="FileForm" name="file" enctype="multipart/form-data">
<input type="file" name="file" id="File" />
<input type="button" name="submit" value="submit" onclick="ProcessImage()" />
</form>
<p id="status" hidden>Success!</p>
<script>
function ProcessImage()
{
var form_data = new FormData($('#File')[0]);
console.log(form_data)
$.ajax({
type: 'POST',
url: '/demo-upload',
data: form_data,
contentType: false,
cache: false,
processData: false,
async: false,
success: function (data) {
console.log('Success!');
$("#status").show();
},
});
}
</script>
</body>
</html>
everything looks clean to me and I do not know where I am going wrong. the files attribute in the request object is always empty. I also tried with postman using post request with form-data key = file and value = uploaded a file, and a header content-type = "multipart/form-data". any help is appreciated thanks a lot!
I made a few changes and make it work:
First, change which html element you read the data from in javascript part:
var formDataRaw = $('#FileForm')[0];
var form_data = new FormData(formDataRaw);
Second, I tried to obtain the uploaded image as follows: (#cross_origin() is only required if you try to upload to your localhost)
#app.route("/demo-upload", methods=["GET", "POST"])
#cross_origin()
def ProcessImage():
if request.method == "POST":
print(request.files)
try:
if 'file' in request.files:
imageFile = request.files['file']
savePath = "/somewhere/somewhere/something.png"
imageFile.save(savePath)
except Exception as e:
print(e)
return jsonify("Ok")

Basic flask form handling

I am trying to create a basic form in Flask that will take in the input, manipulate it and then return the output. I am running into the issue that when I am running the terminal and trying to make my app work on the http://127.0.0.1:5000/ server, the files are not visible. Not sure where the bug is?
This is how I have my files organized:
/Users/eas/Desktop/grota/templates/index.html
/Users/eas/Desktop/grota/templates/age.html
/Users/eas/Desktop/grota/app.py
This is the app.py file
from flask import Flask, render_template,request
app = Flask(__name__)
#app.route('/send',methods = ['GET','POST'])
def send():
if request.method == 'POST':
age = request.form['age']
return render_template('age.html',age=age)
return render_template('index.html')
if __name__ == '__main__':
app.run()
This is the index.html file
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.0/css/bootstrap.min.css" integrity="sha384-9gVQ4dYFwwWSjIDZnLEWnxCjeSWFphJiwGPXr1jddIhOegiu1FwO5qRGvFXOdJZ4" crossorigin="anonymous">
</head>
<body>
<h1>How old are you?</h1>
<form method="POST" action = "/send">
<div class = "form-group">
<input type="text" name = "age">
</div>
<input class="btn btn-primary" type="submit" value="submit">
</form>
</body>
</html>
This is the age.html file
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<h1>Your age is{{age}}</h1>
</body>
While looking for a problem, which I try to solve I found your question. For a solution that includes full code (with py and 2 HTML files) you can see my repl.it : https://repl.it/#AlperenAtik/NaturalShortActivecell#main.py
The problems are:
In the first function, you routed your loop to "/send" page. This is why your send page did not appear. The route of the first function needs to be "/"
In the index file, the source route was shown as '/send'. Whenever I changed it to / the script worked without a problem
The other commentators already mentioned your triggering function has an indentation mistake. When host and port added appropriately, your script would work.
for ones who love the harder way- seeing things in stackoverflow- not in action, I am adding the codeblocks. Enjoy.
for main.py
from flask import Flask, render_template,request
app = Flask(__name__)
#app.route('/',methods = ['GET','POST'])
def send():
if request.method == 'POST':
age = request.form['age']
return render_template('age.html',age=age)
return render_template('index.html')
if __name__ == '__main__':
app.run(host = '0.0.0.0', port = 8080
I left the host as '0.0.0.0' and port as 8080. If you are running Python on a terminal, you may try (host = '127.0.0.1', port:5000').
for templates/index.html
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.0/css/bootstrap.min.css" integrity="sha384-9gVQ4dYFwwWSjIDZnLEWnxCjeSWFphJiwGPXr1jddIhOegiu1FwO5qRGvFXOdJZ4" crossorigin="anonymous">
</head>
<body>
<h1>How old are you?</h1>
<form method="POST" action = "/">
<div class = "form-group">
<input type="text" name = "age">
</div>
<input class="btn btn-primary" type="submit" value="submit">
</form>
</body>
</html>
for templates/age.html
<html>
<head>
</head>
<body>
<h1>Your age is {{age}}</h1>
</body>
You did not set the root route.
Or you open http://127.0.0.1:5000/send
Or you could use this quick and dirty fix (as you see in decorators now both / and /send are taken into account):
from flask import Flask, render_template,request
app = Flask(__name__)
#app.route('/',methods = ['GET'])
#app.route('/send',methods = ['GET','POST'])
def send():
if request.method == 'POST':
age = request.form['age']
return render_template('age.html',age=age)
return render_template('index.html')
if __name__ == '__main__':
app.run()
If you do not handle the '/' route nothing will happen when you open http://127.0.0.1
If you explain more clearly what is the result that you want to obtain I can help better.
Try going here: http://127.0.0.1:5000/send
If that doesn't work, what error are you getting in either your console or in your browser?
EDIT:
I just tried it, and it worked. Try reloading the page in a new tab in your browser, and see if it still occurs. This error has to do with the naming of your inputs on the webpage and the way you index your form with request.form['age']

Categories