Flask session variables cannot be retrieved for various actions on google - flask

I am using Dialogflow to receive user input and the received values are passed to the flask program using a webhook call. Session variables are set for this action on webhook call. For another google action, I am trying to retrieve the session variables. But, I am not able to access them. Let me know where I am going wrong. Thanks in advance.
DialogFlow Intent - setclass
Receives the parameter 'class' (grade) from the User and invokes the Action setclass, which sets the session variables class and grade through webhook call.
Dialogflow Intent - getclass
Action getclass gets the values set in the session through webhook call.
Flask program to store and receive values from session:
from flask import Flask, request, session, jsonify
app = Flask(__name__)
app.secret_key = "abc"
#app.route("/sessiontrial",methods=['POST','GET'])
def sessiontrial():
req = request.get_json(silent=True, force=True)
value = req.get('queryResult')
params = value.get('parameters')
action = value.get('action')
print("Inside sessiontrial")
if (action == "setclass"):
classno = params.get('class')
print (classno)
session['class'] = classno
session['grade'] = str(classno) + " Grade"
print (session['grade'])
res = {"fulfillmentText": classno}
return(jsonify(res))
if (action == "getclass"):
if 'class' in session:
classs = session['class']
print("Class is: ", classs)
gradee = session['grade']
print("Grade is: ", gradee)
res = {"fulfillmentText": gradee}
return(jsonify(res))
else:
print("Class not found in Session")
res = {"fulfillmentText": "Class not found in Session"}
return(jsonify(res))
if __name__ == '__main__':
app.run()

You can use Redis Session Store to solve your problem. Since you've created the session in the webbook without allowing end-users to interact with the application, this could be the culprit.
You can do the following.
Go to the following link: https://github.com/aws-samples/amazon-elasticache-samples/blob/master/session-store/example-4.py
Download the class example-4.py from the session store section
Setup in your flask app.
If you are using Heroku, you can create Heroku Redis by executing the following command:
heroku addons:create heroku-redis:hobby-dev -a your-app-name
Redis Session store requires two input values: TOKEN and REDIS URL.
You can get the REDIS_URL configuration variable in the settings section of Heroku app after you setup the Redis as described in the step 4.
You must create a unique token for each user that remains active for as long as you want by specifying it in the session store. It is known as TTL (remaining time of key expiry in seconds). If you're using the dialogflow-fullfilment package, you can create this in the dialogflow and get it easily by using agent.session. In the example below, I've set the expiration time to one hour.
ttl=3600
Then do the following in your code snippets.
store = SessionStore(token, REDIS_URL)
if (action == "setclass"):
classno = params.get('class')
print (classno)
store.set('class', classno)
#session['class'] = classno
store.set('grade', str(classno) + " Grade")
#session['grade'] = str(classno) + " Grade"
print (store.get('grade'))
res = {"fulfillmentText": classno}
return(jsonify(res))
if (action == "getclass"):
if 'class' in session:
classs = session['class']
print("Class is: ", classs)
gradee = store.get('grade')
#gradee = session['grade']
print("Grade is: ", gradee)
res = {"fulfillmentText": gradee}
return(jsonify(res))
If you get the data in byte format, then you can easily convert this into integers or whatever format you like. Here is an example: How could I convert a bytes to a whole hex string?

Related

How to get response from redirect request using flask API in Python?

I have two containers (docker) running the application and I'm trying to redirect the request from one of the container to another. The container where I'm redirecting from has this code and the 172.17.0.3 is the IP of the second container. I have seen that it can be pinged. In the other container I don't have the else part and no if condition check. When I run a curl request to this container using another client container in the same network curl http://172.17.0.2:3333?count=100, it should ideally redirect but I get Internal Server Error as the response. However, when I login to the container 2 and run curl, I get redirected to ... response.
from flask_restful import Resource, Api
app = Flask(__name__)
api = Api(app)
class Greeting (Resource):
def get(self):
offload = True
if offload == False:
count = request.args.get('count')
count = int(count)
for i in range(count):
continue
return count
else:
count = request.args.get('count')
redirect_str = "http://172.17.0.3:3333?count=" + count
return redirect(redirect_str, code=302)
api.add_resource(Greeting, '/') # Route_1
if __name__ == '__main__':
app.run('0.0.0.0', '3333')
I want to be able to wait for the response back from the server 172.17.0.3 and once I receive the message, send the response back to the client. Can anyone tell me how it can be done?
You need to send a request to the other container instead of redirect to it if you want to wait for its response. Using e.g. the requests library this would look something like
import requests
resp = requests.get('http://172.17.0.3:3333?count=' + count)
return resp.text
Check request's Quickstart guide for more info: https://requests.readthedocs.io/en/master/user/quickstart.

Storing the data in the console in a database and accessing it

I'm building a web app which accesses the location of the user when a particular button is pressed for this I'm using the HTML geolocation api.
Below is the location.js file:
`var x = document.getElementById("demo");
function getLocation() {
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(showPosition);
} else {
x.innerHTML = "Geolocation is not supported by this browser.";
}
}
function showPosition(position) {
x.innerHTML = "Latitude: " + position.coords.latitude +
"<br>Longitude: " + position.coords.longitude;
console.log(position.coords.latitude)
console.log(position.coords.longitude)
}
Below is the snippet of the HTML file:
<button onclick="getLocation()">HELP</button>
<p id="demo"></p>
<script src="../static/location.js"></script>
What I want to do is send this information ( i.e. longitude/latitude of the user ) to list of e-mails associated with that user but I don't know how to store this data and access this after the button is pressed.
It would be of great use if someone could get me started on how to save this data corresponding to the user and accessing it from the database.
If you want to store this info to a django DB, then if might be easier to do this in a django view. This could be a RedirectView that just redirects to the same view after the button is clicked.
I have previously used a downloaded DB of the GeoLite2-City.mmdb, which might not always be up to date, but is ok.
You can get the ip address of a request in django with the ipware library. Then convert it into a python IP object in IPy. You can then use the geoip library to get the information out of the DB.
Import the following libraries;
from ipware.ip import get_ip
from IPy import IP
import geoip2.database
Then your method to get the IPs would be something like
class MyRedirectView(RedirectView)
def get_redirect_url(self, request, *args, **kwargs):
## Write some code to handle the redirect url first ##
ip_address = get_ip(self.request)
"""Ensure that the IP address is a valid IP first"""
try:
IP(ip_address)
except Exception:
logger.exception("GEOIP2 error: ")
"""Then get the IP location"""
geo_path = settings.GEOIP_PATH
reader = geoip2.database.Reader(geo_path + '/GeoLite2-City.mmdb')
try:
response = reader.city(ip_address)
city = response.city.name
country = response.country.name
### Some code here to save to your DB
return super(MyRedirectView, self).get_redirect_url(*args, **kwargs)
If you need a much more accurate IP location service you could involce an API call to something like http://ip-api.com/. But then you would have to wait for this response before serving the next view.

how to store python json.dumps into firebase as one payload; without firebase auto creating indexs in front of each object

First time poster, and I'm not really a developer, so perspective is always appreciated :)
Objective:
I am attempting to put (or patch) a json.dumps(mergedFile) into firebase as one payload without firebase auto creating indexes (0, 1, etc..) in front of each object
Problem statement:
I am submitting the following json object into the /testObject path:
[{"test1":"226.69"},{"test2":"7.48"}]
In firebase the response is stored as:
[
{
"testObject": {
0: {
"test1": "226.69"
},
1: {
"test2": "7.48"
}
}
}
]
Background:
The total # of items in the payload of the data I need to store is
just over 5000
If I parse each object via a for loop the data is written as
expected, however, it initiates a new request for each itteriation of
the loop and has a large overhead impact compared to just
dumping one large object in one request.
Here is my Code:
import json
import requests
import xml.etree.ElementTree as ET
def get_data():
try:
print 'hampsters are running...'
# OFFLINE TESTING
sourceFile = 'response.xml'
tree = ET.parse(sourceFile)
root = tree.getroot()
for symbol in root.iter('symbol'):
company = symbol.attrib['company']
location = symbol.attrib['location']
destinationData = {company: location}
mergedFile.append(destinationData)
print('downlaoding the info was a success! :)')
except:
print 'Attempt to download information did not complete successfully :('
def patch_data():
try:
print 'attempting to upload info to database...'
data = json.dumps(mergedFile)
print data
try:
req = requests.put(url, data=data, headers=headers)
req.raise_for_status()
except requests.exceptions.HTTPError as e:
print e
print req.json()
print 'upload to database complete!'
except:
print 'Attempt to upload information did not complete successfully :('
if __name__ == "__main__":
mergedFile = []
auth = "*****"
databaseURL = 'https://*****.firebaseio.com'
headers = {"auth": auth, "print": "pretty"}
# headers = {"auth": auth, "print": "pretty", "Accept": "text/event-stream"}
requestPath = '/testObject.json?auth=' + auth
url = databaseURL + requestPath
get_data()
patch_data()
I feel like its storing an array, but I'm leveraging data = json.dumps(mergedFile) before the put request. Do I have a mis-understanding of how json.dumps works? Based on the output before the request I feel it looks good. I'm also leveraging the requests python module... is this converting the data to an array?
Any insight anyone could provide would be greatly appreciated!
Regards,
James.
The Firebase Database stores arrays as regular key-value pairs, with the keys being numbers. So what you see is the expected behavior.
There are many reasons why Firebase recommends against storing arrays in the database. A few can be found in these links:
Best Practices: Arrays in Firebase
Proper way to store values array-like in Firebase
Firebase documentation on structuring data
Other questions about arrays in Firebase
this answer on arrays vs sets

gspread Invalid token: Stateless token expired [duplicate]

I am using gspread and a Service Account Key, Other, json file. to continually update a google spreadsheet with python 2.7. I have this running off a Raspberry Pi running the latest Raspian Jessie. my oauth and gspread should all be the latest versions available for my platform. My script runs for one hour(the max token life span),then stops working with the error message : "Invalid token: Statless token expired error" My code is as follows
import gspread
from oauth2client.service_account import ServiceAccountCredentials
import httplib2
from httplib2 import Http
scope = ['https://spreadsheets.google.com/feeds']
credentials = ServiceAccountCredentials.from_json_keyfile_name(filename.json,scope)
gc = gspread.authorize(credentials)
wks = gc.open('spreadsheet name')
p1 = wks.worksheet('Printer One')
def functon()
...
p1.append_row(printing)
Any Help would be greatly appreciated, Thank You.
Authorisation expires every 0.5/1 hour (I think it depends on which of the two available methods you use to connect).
I have a google sheet connected 24/7 that updates every 2 seconds. Almost always the reason for a bad read/write is an authorisation error but also Google API can throw a variety of errors at you too that normally resolve after a few seconds. Here's one of my functions to update a cell, but using your details for auth_for_worksheet. Every operation (update single cell, update a range, read a column of values) has some similar construct as a function, which always returns an authorised worksheet. It's probably not the most elegant solution but the sheet has been connected for 3 months fine with no downtime.
def auth_for_worksheet():
scope = ['https://spreadsheets.google.com/feeds']
credentials = ServiceAccountCredentials.from_json_keyfile_name(filename.json,scope)
gc = gspread.authorize(credentials)
wks = gc.open('spreadsheet name')
p1 = wks.worksheet('Printer One')
return p1
def update_single_cell(worksheet, counter, message):
""" No data to return, update a single cell in column B to reflect this """
single_cell_updated = False
while not single_cell_updated:
try:
cell_location = "B" + str(counter)
worksheet.update_acell(cell_location, message)
single_cell_updated = True
except gspread.exceptions.HTTPError:
logger.critical("Could not update single cell")
time.sleep(10)
worksheet = auth_for_worksheet()
logger.info("Updated single cell")
return worksheet
if __name__ == '__main__':
# your code here, but now to update a single cell
wksheet = update_single_cell(wksheet, x, "NOT FOUND")

gspread w/ OAuth2Client Service Account Key

I am using gspread and a Service Account Key, Other, json file. to continually update a google spreadsheet with python 2.7. I have this running off a Raspberry Pi running the latest Raspian Jessie. my oauth and gspread should all be the latest versions available for my platform. My script runs for one hour(the max token life span),then stops working with the error message : "Invalid token: Statless token expired error" My code is as follows
import gspread
from oauth2client.service_account import ServiceAccountCredentials
import httplib2
from httplib2 import Http
scope = ['https://spreadsheets.google.com/feeds']
credentials = ServiceAccountCredentials.from_json_keyfile_name(filename.json,scope)
gc = gspread.authorize(credentials)
wks = gc.open('spreadsheet name')
p1 = wks.worksheet('Printer One')
def functon()
...
p1.append_row(printing)
Any Help would be greatly appreciated, Thank You.
Authorisation expires every 0.5/1 hour (I think it depends on which of the two available methods you use to connect).
I have a google sheet connected 24/7 that updates every 2 seconds. Almost always the reason for a bad read/write is an authorisation error but also Google API can throw a variety of errors at you too that normally resolve after a few seconds. Here's one of my functions to update a cell, but using your details for auth_for_worksheet. Every operation (update single cell, update a range, read a column of values) has some similar construct as a function, which always returns an authorised worksheet. It's probably not the most elegant solution but the sheet has been connected for 3 months fine with no downtime.
def auth_for_worksheet():
scope = ['https://spreadsheets.google.com/feeds']
credentials = ServiceAccountCredentials.from_json_keyfile_name(filename.json,scope)
gc = gspread.authorize(credentials)
wks = gc.open('spreadsheet name')
p1 = wks.worksheet('Printer One')
return p1
def update_single_cell(worksheet, counter, message):
""" No data to return, update a single cell in column B to reflect this """
single_cell_updated = False
while not single_cell_updated:
try:
cell_location = "B" + str(counter)
worksheet.update_acell(cell_location, message)
single_cell_updated = True
except gspread.exceptions.HTTPError:
logger.critical("Could not update single cell")
time.sleep(10)
worksheet = auth_for_worksheet()
logger.info("Updated single cell")
return worksheet
if __name__ == '__main__':
# your code here, but now to update a single cell
wksheet = update_single_cell(wksheet, x, "NOT FOUND")