How to have Google Form submit event trigger be caught by a Flask website to update that website? - flask

I have a website written on Flask, and I would like to update it when answers to a Google Form has been submitted.
More precisely, I have already associated the form to a Google spreadsheet and I can read that spreadsheet from Flask, but the key component missing is how to trigger the website to update its content when new answers have been submitted to the form.
What would be the best way to do this?

Webhook solution:
Google Forms:
Enter the Google Forms editor
Click 3 vertical dots next to profile picture, and select 'script editor'
Customize this snippet to your WebHook url and set a custom token (this is not really secure, but better than nothing ).
function onFormSubmit(e) {
const url = "https://example.com/webhook";
var options = {
"method": "post",
"headers": {
"Content-Type": "application/json"
},
"payload": JSON.stringify({"token": "sometokenheretocheckonbackend"})
};
UrlFetchApp.fetch(url, options);
}
( Dialog may popup where you have to approve that you connect to an unauthorized service )
Handling on the Flask side:
from http import HTTPStatus
from flask import (
abort,
request
)
#blueprint.route('/webhook', methods=['POST'])
def handle_webhook():
payload = request.get_json()
if payload.get('token') != "sometokenheretocheckonbackend":
abort(HTTPStatus.UNAUTHORIZED)
# Update your content
return jsonify({'success': True}), HTTPStatus.OK
Periodic updates (Alternative solution):
I would consider launching a daemon Thread that periodically updates this content. This is obviously not as elegant, but should work quite stable and wouldn't be much more demanding for the server if the content update procedure is reasonably lightweight.

You could create an Form Submit trigger to trigger a Google Apps Script function that calls out to your Flask site and triggers the update.
https://developers.google.com/apps-script/guides/triggers/installable

Related

What is the best approach of using django and ajax?

I'm now working on my first big project and can't understand how to use Django with ajax.
On my website there are several services which works separately and are written on javascript, but soemtimes I have to send some information to the server.
Also I have custom admin interface which contains of different changing database operations. All these actions should be done without reloading the page (using ajax post and get requests).
So, I think I have two ways of doing it:
Using ajax and classic Django views for each operation.
Using ajax and integrated into my website Django REST Framework API methods.
The stumbling block is that I wouldn't use this API methods from any other types of clients, just call them from users' browsers via ajax. What is the best approach in my situation? It seems to me that the second way is more "serious", but I don't have much experience of making projects like this and can't speak directly.
You don't need to integrate REST. You can do ajax call to normal view like you do with user interaction. The view can return http response or JSON or whatever you need. If you would like to change somethink in DOM without refreshing page I can sugest HTMX (https://htmx.org/)
standard ajax call to get some json:
let datas = {id: $(this).val(),};
$.ajax({
url: "{% url 'to_your_view' %}",
type: "POST",
data: datas,
success: function (json) {
console.log(json);
},
error: function (xhr, errmsg, err) {
console.log(xhr.status + ": " + xhr.responseText);
}
});
and in view:
def to_your_view(request):
if request.method == "POST":
id = request.POST.get('id', 0)
if id != 0:
return HttpResponse(json.dumps(100), content_type="application/json")

django async/background for long running task

I have a django app with an endpoint that kicks off a long running task. I want to do this in the background. I know I could do this with celery or django-q, but I wanted to try something simpler first.
First thing I tried was ajax. In the python code I did this:
cookie = request.META.get('HTTP_COOKIE')
csrf_cookie = request.META.get('CSRF_COOKIE')
host = '{}://{}'.format(request.scheme, request.META['HTTP_HOST'])
data = {...}
resp = requests.post('{}/report/TASKS/Work/ajax/run.json'.format(host),
headers={'COOKIE': cookie, 'X-CSRFToken': csrf_cookie, 'referer': host}, data=data)
The function being called has the #login_required decorator, and when that runs it does the auth as the anonymous user, which fails so it redirects to the login page. The thread sending in the request is logged in and I have verified the cookies are all correct. Why would it use the anonymous user? How can I get it to auth using the logged in user?
Tried something else next - instead of using ajax I call it with multiprocessing.Process. This fails because the thread does not have a database connection.
Anyone have any thought on how I could make this work?

Change the edit url, dynamically using the Datatable Editor

I'm looking on how to update the ajax configuration dynamically using data from a resource when updating a record. Django REST expects the id at the end of the url and the request method must be type PUT
I've spent some time figuring out how to update the ajax request made by the Datatable Editor plugin. I'm using Django Rest as the backend. This might be useful for some people looking for a similar answer.
Technically you can update the ajax options if the editor object before it sends the request by using the preSubmit Event.
editor.on('preSubmit', (e, request,) =>{
let _url = new URL(window.location.origin + "/" + editor.ajax().url)
if(request.action == 'edit'){
editor.ajax().url = `${_url.protocol}//${_url.host}/api/v1/some-endpoint/${Object.keys(request.data)[0]}/${_url.search}`;
editor.ajax().type = 'PUT'
}
editor.ajax().data = request.data[Object.keys(request.data)]
})
This will update the ajax configuration of the edit request right before it get sent. Django Rest expects a PUT request and the id of the record to be added at the end of the URL. As you can see we grab the id from the data object (Its the first key of the request.data object), and we can also change the type of request to PUT.

Django REST to React - getting social auth tokens without password

I want to pass info to React about the current authenticated user within an app that only uses social authentication on the backend (that is processed by social_django). All of my user and user token info is stored within django REST, and to access the tokens, I normally have to send POST requests to rest_framework.authtoken's obtain_auth_token view. My django root urls.py file looks like:
...
from rest_framework.authtoken.views import obtain_auth_token
urlpatterns = [
...
url(r'^obtain-auth-token/$', obtain_auth_token),
...
]
However, in order to actually get the auth tokens associated with the users in my database, I need to supply the username and password within my POST request. Social authentication automatically creates new users without assigning any passwords, so how do I get those tokens?
Have you got this working? If no, here is what I did. Hope it helps.
My Setup:
Django with Postgres
Django Rest Framework for REST API implementation
Python Social Auth (PSA) for Social Authentication (For now using Google+ libraries)
Reactjs frontend
While using Login for login, it translates to /login/google-plus/. This not only get's the acess_token but also creates a "social user" in your database. I used oauth 2.0 client side libraries in my case and roughly followed this approach to fetch the google user object with all the details on the client side. I replaced form in above link with ajax call which is more flexible and gives control to me to access tokens and other information necessary. The ajax call here ensures creation of social user in social auth table within the database.
<script type="text/javascript">
gapi.load('auth2', function () {
let auth2;
auth2 = gapi.auth2.init({
client_id: "YOUR CLIENT ID",
scope: "profile",
cookie_policy: 'single_host_origin'
});
auth2.then(function () {
let button = document.getElementById("google-plus-button");
auth2.attachClickHandler(button, {}, function (googleUser) {
// Send access-token to backend to finish the authenticate
// with your application
let authResponse = googleUser.getAuthResponse();
$.ajax({
"type": "POST",
"url": "/complete/google-plus/",
"data": {
"access_token": authResponse.access_token,
"CSRF": "{% csrf_token %}"
}
}).then(function(data){
console.log(data);
// Your success code
}).fail(function(error){
console.log(error);
});
});
});
});
</script>
Once you fetch the access_tokens you can store them in browser local storage till the user logs out. On log out you can delete them.
This method works well for me for the setup I mentioned. Also the problem of querying /obtain-auth-token with username and password is not there at all.
Would definitely be interested to know if there are other ways of accessing social auth tokens from PSA django. Cheers!

Send push notification with Parse and a webservices with django

Is there some way to send push notifications using Parse and a web service built in Django? I mean, I have a dashboard built in django, in this dashboard I can set it up some parameters, when I create for example a new news, this has to be notified to the user through a push notifications. How can I achieve this?
See that page... https://www.parse.com/docs/rest/guide you should try make a request similar to this....every time you make some news
import json,httplib
connection = httplib.HTTPSConnection('api.parse.com', 443)
connection.connect()
connection.request('POST', '/1/classes/GameScore', json.dumps({
"score": 1337,
"playerName": "Sean Plott",
"cheatMode": False
}), {
"X-Parse-Application-Id": "${APPLICATION_ID}",
"X-Parse-REST-API-Key": "${REST_API_KEY}",
"Content-Type": "application/json"
})
results = json.loads(connection.getresponse().read())
print results