Related
I am trying to get this webpage to update asynchronously using a python flask server and MQTT values coming in from Arduino devices. All values are coming through and getting saved correctly however the values do not show up on the webpage.
I think it might have something to do with trying to write to the id tag using the $('#humidity').text
Here's the relevant HTML:
<script type="text/javascript" charset="utf-8">
$(document).ready(function() {
var socket = io.connect('http://' + document.domain + ':' + location.port);
socket.on('connect', function() {
socket.emit('my event', {data: 'I\'m connected!'});
});
socket.on('dht_temperature', function(msg) {
var nDate = new Date();
$('#readingsUpdated').text(nDate.getHours() + 'h:' + nDate.getMinutes() +
'm:' + nDate.getSeconds() + 's').html();
$('#temperature').text(msg.data).html();
});
socket.on('dht_humidity', function(msg) {
$('#humidity').text(msg.data).html();
});
});
</script>
<body>
<h1>RPi Web Server - ESP8266 MQTT</h1>
{% for pin in pins %}
<h2>{{ pins[pin].name }}
{% if pins[pin].state == 'True' %}
is currently <strong>on</strong></h2><div class="row"><div class="col-md-2">
Turn off</div></div>
{% else %}
is currently <strong>off</strong></h2><div class="row"><div class="col-md-2">
Turn on</div></div>
{% endif %}
{% endfor %}
<h3>DHT Readings (updated <span id="readingsUpdated"></span>)</h3>
<h3>Temperature: <span id="temperature"></span>ÂșC</h3>
<h3>Humidity: <span id="humidity"></span>%</h3>
</body>
</html>
And here is the Python Script
import paho.mqtt.client as mqtt
from flask import Flask, render_template, request
from flask_socketio import SocketIO, emit
app = Flask(__name__)
app.config['SECRET_KEY'] = 'secret!'
socketio = SocketIO(app)
# The callback for when the client receives a CONNACK response from the server.
def on_connect(client, userdata, flags, rc):
print("Connected with result code "+str(rc))
# Subscribing in on_connect() means that if we lose the connection and
# reconnect then subscriptions will be renewed.
client.subscribe("/esp8266/temperature")
client.subscribe("/esp8266/humidity")
# The callback for when a PUBLISH message is received from the ESP8266.
def on_message(client, userdata, message):
#socketio.emit('my variable')
print("Received message '" + str(message.payload) + "' on topic '"
+ message.topic + "' with QoS " + str(message.qos))
if message.topic == "/esp8266/temperature":
print("temperature update")
socketio.emit('dht_temperature', {'data': message.payload})
if message.topic == "/esp8266/humidity":
print("humidity update")
socketio.emit('dht_humidity', {'data': message.payload})
mqttc=mqtt.Client()
mqttc.on_connect = on_connect
mqttc.on_message = on_message
mqttc.connect("localhost",1883,60)
mqttc.loop_start()
# Create a dictionary called pins to store the pin number, name, and pin state:
pins = {
4 : {'name' : 'GPIO 4', 'board' : 'esp8266', 'topic' : 'esp8266/4', 'state' : 'False'},
5 : {'name' : 'GPIO 5', 'board' : 'esp8266', 'topic' : 'esp8266/5', 'state' : 'False'}
}
# Put the pin dictionary into the template data dictionary:
templateData = {
'pins' : pins
}
#app.route("/")
def main():
# Pass the template data into the template main.html and return it to the user
return render_template('main.html', async_mode=socketio.async_mode, **templateData)
# The function below is executed when someone requests a URL with the pin number and action in it:
#app.route("/<board>/<changePin>/<action>")
def action(board, changePin, action):
# Convert the pin from the URL into an integer:
changePin = int(changePin)
# Get the device name for the pin being changed:
devicePin = pins[changePin]['name']
# If the action part of the URL is "1" execute the code indented below:
if action == "1" and board == 'esp8266':
mqttc.publish(pins[changePin]['topic'],"1")
pins[changePin]['state'] = 'True'
if action == "0" and board == 'esp8266':
mqttc.publish(pins[changePin]['topic'],"0")
pins[changePin]['state'] = 'False'
# Along with the pin dictionary, put the message into the template data dictionary:
templateData = {
'pins' : pins
}
return render_template('main.html', **templateData)
#socketio.on('my event')
def handle_my_custom_event(json):
print('received json data here: ' + str(json))
if __name__ == "__main__":
socketio.run(app, host='0.0.0.0', port=8181, debug=True)
Hey i am trying to make a bar graph in my html page. I am using Google Charts, flask and html. Whenever I manually enter data it works perfectly. But when I try to send the data through flask, it doesn't show anything.
Here is my application.py:
import flask
import mysql.connector
app = flask.Flask(__name__)
f = mysql.connector.connect(host = "localhost", user = "root", passwd = "")
mycur = f.cursor()
#app.route("/")
def get_vals():
mycur.execute("use one_stop_healthcare;")
mycur.execute("select NAME, ACTIVE, DISCHARGED from ccinfo;")
dat = mycur.fetchall()
active=[[]]
for i in range(0,5,1):
for j in range(0,2,1):
active[i].append(dat[i][j])
active.append([])
del active[5]
active.insert(0, ['All the wards', 'Active cases', 'Recovered'])
print(active)
return flask.render_template("index.html", active=active)
app.run()
Here is my index.html(In a template folder)
<html>
<head>
<script type="text/javascript" src="https://www.gstatic.com/charts/loader.js"></script>
<script type="text/javascript">
google.charts.load('current', {packages: ['corechart', 'bar']});
google.charts.setOnLoadCallback(drawMultSeries);
var active
function drawMultSeries() {
// Here is where i manually add the data. It works like this.
var active = [['All the wards', 'Active cases', 'Recovered'], ['Ward-1', 357, 153], ['Ward-2', 744, 349], ['Ward-3', 83, 54], ['Ward-4', 1360, 433], ['Ward-5', 149, 100]]
var data = google.visualization.arrayToDataTable(active);
var options = {
title: 'Covid care centers',
chartArea: {width: '50%'},
hAxis: {
title: 'Active cases',
minValue: 0
},
vAxis: {
title: 'Wards'
}
};
var chart = new google.visualization.BarChart(document.getElementById('chart_div'));
chart.draw(data, options);
}
</script>
</head>
<body>
<div id="chart_div"></div>
</body>
You currently don't use the python object 'active' at all.
Replace this line in your html-code:
var active
by
var active = {{active}}
(and remove the manuall declaration)
I'm trying to access the web services of a Moodle installation I have using Python's requests library. I have the API's documentation and an example project written in php (I haven't looked at php before and is way more difficult than I would expect for me to understand) but am really struggling to properly format the request. The site is returning invalid paramater detected so I'm pretty sure my endpoint, authorization token, and server config is working and it's just the format of the data that is letting me down.
First here is the error...
<?xml version="1.0" encoding="UTF-8" ?>
<EXCEPTION class="invalid_parameter_exception">
<ERRORCODE>invalidparameter</ERRORCODE>
<MESSAGE>Invalid parameter value detected</MESSAGE>
</EXCEPTION>
And now my code...
import requests
target = 'http://example.com/moodle/webservice/rest/server.php?'
moodle_create_token = 'xxx'
moodle_enrol_token = 'yyy'
url_payload = {
"wstoken":moodle_create_token,
"wsfunction":"core_user_create_users"
}
###not sure if I should just be passing this as a dict or some deeper more layered struct
payload = {
"username":"testuser",
"password":'testpass',
"firstname":'testf',
"lastname":'testl',
"email":"test#example.com",
"idnumber":"1234"
}
###not sure how to include the payload as the last argument in the function (currently data=)
###I feel like at this point I've just been throwing random data at it and hoping something sticks haha.
r=requests.post(target, params=url_payload, data=payload)
Here is the site's documentation
moodle api general structure
moodle api XML-RPC (PHP structure)
moodle api REST (POST parameters)
moodle response format 1
moodle response format 2
Finally the example in php.
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>V6</title>
</head>
<body>
<?php
//load curl.php
require_once('curl.php');
function randomPassword() //according to Moodle password requirements
{
$part1 = "";
$part2 = "";
$part3 = "";
//alphanumeric LOWER
$alphabet = "abcdefghijklmnopqrstuwxyz";
$password_created = array(); //remember to declare $pass as an array
$alphabetLength = strlen($alphabet) - 1; //put the length -1 in cache
for ($i = 0; $i < 3; $i++)
{
$pos = rand(0, $alphabetLength); // rand(int $min , int $max)
$password_created[] = $alphabet[$pos];
}
$part1 = implode($password_created); //turn the array into a string
//echo"<br/>part1 = $part1";
//alphanumeric UPPER
$alphabet = "ABCDEFGHIJKLMNOPQRSTUWXYZ";
$password_created = array(); //remember to declare $pass as an array
$alphabetLength = strlen($alphabet) - 1; //put the length -1 in cache
for ($i = 0; $i < 3; $i++)
{
$pos = rand(0, $alphabetLength); // rand(int $min , int $max)
$password_created[] = $alphabet[$pos];
}
$part2 = implode($password_created); //turn the array into a string
//echo"<br/>part2 = $part2";
//alphanumeric NUMBER
$alphabet = "0123456789";
$password_created = array(); //remember to declare $pass as an array
$alphabetLength = strlen($alphabet) - 1; //put the length -1 in cache
for ($i = 0; $i < 2; $i++)
{
$pos = rand(0, $alphabetLength); // rand(int $min , int $max)
$password_created[] = $alphabet[$pos];
}
$part3 = implode($password_created); //turn the array into a string
//echo"<br/>part3 = $part3";
$password = $part1 . $part2 . $part3 . "#";
return $password;
}
function getCDate()
{
$format = "Ymd";
$fulldate = date($format);
//echo"<br/>fulldate = $fulldate";
return $fulldate;
}
function enrol($user_id, $course_id)
{
$role_id = 5; //assign role to be Student
$domainname = 'http://www.yoursite.eu'; //paste your domain here
$wstoken = '8486ed14f3ghjec8967a0229d0a28zzz'; //here paste your enrol token
$wsfunctionname = 'enrol_manual_enrol_users';
$enrolment = array( 'roleid' => $role_id, 'userid' => $user_id, 'courseid' => $course_id );
$enrolments = array($enrolment);
$params = array( 'enrolments' => $enrolments );
header('Content-Type: text/plain');
$serverurl = $domainname . "/webservice/rest/server.php?wstoken=" . $wstoken . "&wsfunction=" . $wsfunctionname;
$curl = new curl;
$restformat = ($restformat == 'json')?'&moodlewsrestformat=' . $restformat:'';
$resp = $curl->post($serverurl . $restformat, $params);
print_r($resp);
}
function getUserDetails()
{
$firstname = "TestUser";
$lastname = "TestUser";
$email = "TestUser#zzz.gr";
$city = "Thessaloniki";
$country = "EL";
$description= "ZZZ";
//assign username
//get first two letters of name and surname
//$strlength_user = strlen($firstname);
//$strlength_pass = strlen($lastname);
$rest_firstname = substr($firstname, 0, 2);
$rest_lastname = substr($lastname, 0, 2);
$part1 = $rest_firstname . $rest_lastname;
$part1 = strtolower($part1);
//echo"<br/>part1 = $part1";
$dt = getCDate();
$part2 = substr($dt, -4);
//echo"<br/>part2 = $part2";
$username = $part1 . "." . $part2;
echo"<br/>Username = $username";
//assign password
$password = randomPassword();
echo"<br/>Password = $password";
//call WS core_user_create_user of moodle to store the new user
$domainname = 'http://www.yoursite.eu';
$wstoken = 'ed1f6d3ebadg372f95f28cd96bd43zzz'; //here paste your create user token
$wsfunctionname = 'core_user_create_users';
//REST return value
$restformat = 'xml';
//parameters
$user1 = new stdClass();
$user1->username = $username;
$user1->password = $password;
$user1->firstname = $firstname;
$user1->lastname = $lastname;
$user1->email = $email;
$user1->auth = 'manual';
$user1->idnumber = 'numberID';
$user1->lang = 'en';
$user1->city = $city;
$user1->country = $country;
$user1->description = $description;
$users = array($user1);
$params = array('users' => $users);
//REST call
header('Content-Type: text/plain');
$serverurl = $domainname . "/webservice/rest/server.php?wstoken=" . $wstoken . "&wsfunction=" . $wsfunctionname;
$curl = new curl;
$restformat = ($restformat == 'json')?'&moodlewsrestformat=' . $restformat:'';
$resp = $curl->post($serverurl . $restformat, $params);
print_r($resp);\
//get id from $resp
$xml_tree = new SimpleXMLElement($resp);
print_r($xml_tree);
$value = $xml_tree->MULTIPLE->SINGLE->KEY->VALUE;
$user_id = intval(sprintf("%s",$value));
echo"<br/>user_id number = $user_id";
//enrol_manual_enrol_users
//for($i = 64; $i < 70; $i++) //where 64,65,66,67,68,69 are the six ids of the six courses of phase 1
for($i = 64; $i < 65; $i++)
{
echo "\nThe user has been successfully enrolled to course " . $i;
$course_id = $i;
enrol($user_id, $course_id);
}
}
getUserDetails();
?>
</body>
</html>
Here is an example drawn from mrcinv/moodle_api.py that shows the usage of Python's requests to hit the Moodle Web Services API:
from requests import get, post
# Module variables to connect to moodle api
KEY = "SECRET API KEY"
URL = "https://moodle.site.com"
ENDPOINT="/webservice/rest/server.php"
def rest_api_parameters(in_args, prefix='', out_dict=None):
"""Transform dictionary/array structure to a flat dictionary, with key names
defining the structure.
Example usage:
>>> rest_api_parameters({'courses':[{'id':1,'name': 'course1'}]})
{'courses[0][id]':1,
'courses[0][name]':'course1'}
"""
if out_dict==None:
out_dict = {}
if not type(in_args) in (list,dict):
out_dict[prefix] = in_args
return out_dict
if prefix == '':
prefix = prefix + '{0}'
else:
prefix = prefix + '[{0}]'
if type(in_args)==list:
for idx, item in enumerate(in_args):
rest_api_parameters(item, prefix.format(idx), out_dict)
elif type(in_args)==dict:
for key, item in in_args.items():
rest_api_parameters(item, prefix.format(key), out_dict)
return out_dict
def call(fname, **kwargs):
"""Calls moodle API function with function name fname and keyword arguments.
Example:
>>> call_mdl_function('core_course_update_courses',
courses = [{'id': 1, 'fullname': 'My favorite course'}])
"""
parameters = rest_api_parameters(kwargs)
parameters.update({"wstoken": KEY, 'moodlewsrestformat': 'json', "wsfunction": fname})
response = post(URL+ENDPOINT, parameters).json()
if type(response) == dict and response.get('exception'):
raise SystemError("Error calling Moodle API\n", response)
return response
class CourseList():
"""Class for list of all courses in Moodle and order them by id and idnumber."""
def __init__(self):
# TODO fullname atribute is filtered
# (no <span class="multilang" lang="sl">)
courses_data = call('core_course_get_courses')
self.courses = []
for data in courses_data:
self.courses.append(Course(**data))
self.id_dict = {}
self.idnumber_dict = {}
for course in self.courses:
self.id_dict[course.id] = course
if course.idnumber:
self.idnumber_dict[course.idnumber] = course
def __getitem__(self, key):
if 0<= key < len(self.courses):
return self.courses[key]
else:
raise IndexError
def by_id(self, id):
"Return course with given id."
return self.id_dict.get(id)
def by_idnumber(self, idnumber):
"Course with given idnumber"
return self.idnumber_dict.get(idnumber)
def update_courses(courses_to_update, fields):
"Update a list of courses in one go."
if not ('id' in fields):
fields.append('id')
courses = [{k: c.__dict__[k] for k in fields} for c in courses_to_update]
return call("core_course_update_courses",
courses = courses)
.. and also shows how to define custom classes for Course. In the same fashion one could create classes for User, Grades, etc.
Furthermore, there are some wrapper modules on PyPi, e.g. moodle, and moodle-ws-client.
Okay so I found a solution that works but I suspect it is a bit hodgepodge and not utilizing requests library to its fullest.
What I did was pass all the arguments as parameters in the url.
target = 'http://example.com/moodle/webservice/rest/server.php'
moodle_create_token = 'xxx'
payload = {
"wstoken":moodle_create_token,
"moodlewsrestformat":"json", #just to get response as json
"wsfunction":"core_user_create_users",
"users[0][username]":"testusername",
"users[0][password]":'testpassword',
"users[0][firstname]":'testfirstname',
"users[0][lastname]":'testlastname',
"users[0][email]":"testemail#example.com",
"users[0][idnumber]":"0000001"
}
r=requests.post(target, params=payload)
Obviously I won't usually have the data hard-coded as strings but apparently the list of dictionaries for url params will be.
I have made a python library named moodlepy
pip install moodlepy
Its easy to use, example
from moodle import Moodle
target = 'http://example.com/moodle/webservice/rest/server.php'
moodle_create_token = 'xxx'
moodle = Moodle(target, moodle_create_token)
r = moodle(
'core_user_create_users',
username="testusername",
password='testpassword',
firstname='testfirstname',
lastname='testlastname',
email="testemail#example.com",
idnumber="0000001"
) # return the data (dict, list, etc)
You can also use typed response, for example calling core_webservice_get_site_info
site_info = moodle.core.webservice.get_site_info()
site_info.username
site_info.version
Note: Not all functions are implemented (yet).
I'm creating a web application using Flask and the Google Maps Directions API, where I ask the user to enter a starting point, waypoints, and a destination, and pass this data to the Google API to render a map illustrating the user's route. No matter what these data points are, however, the API keeps interpreting all 3 data points as a single location, and renders the map accordingly. The rendered map is
here, where you can also see what this exact wrong address is.
The relevant source files are as follows:
run.py (where I call my template to render the Google Map in the "/finalize_new_trip" route):
from os.path import abspath, dirname, join
from flask import flash, Flask, Markup, redirect, render_template, url_for, request
from flask.ext.sqlalchemy import SQLAlchemy
from flask_wtf import FlaskForm
from wtforms import StringField
from wtforms.validators import DataRequired
import os
import googlemaps
from datetime import datetime
import json
_cwd = dirname(abspath(__file__))
SECRET_KEY = 'flask-session-insecure-secret-key'
SQLALCHEMY_DATABASE_URI = 'sqlite:///' + join(_cwd, 'TripLogger.db')
SQLALCHEMY_ECHO = True
WTF_CSRF_SECRET_KEY = 'this-should-be-more-random' #TODO: RANDOMIZE THIS KEY
app = Flask(__name__)
app.config.from_object(__name__)
db = SQLAlchemy(app)
class Trip(db.Model):
__tablename__ = 'trips'
id = db.Column(db.Integer, primary_key=True)
trip_name = db.Column(db.String, unique=True)
origin = db.Column(db.String)
destination = db.Column(db.String)
waypoints = db.Column(db.String) #SEE IF ANOTHER DATA TYPE IS BETTER- IDEALLY WANT TO STORE LIST OF STRINGS
def __init__(self, trip_name, origin, destination, waypoints):
self.trip_name = trip_name
self.origin = origin
self.destination = destination
self.waypoints = waypoints
def __repr__(self):
return '<Trip %r(name = %r, origin = %r, destination = %r)>' % (self.id, self.trip_name, self.origin, self.destination)
def __str__(self):
return self.trip_name
#CONSIDER CUSTOM VALIDATORS TO ENSURE THAT TRIP_NAME IS UNIQUE FOR A SPECIFIC USER/ACCOUNT
class TripForm(FlaskForm):
trip_name = StringField('Trip Name', validators=[DataRequired()])
origin = StringField('Origin', validators=[DataRequired()])
destination = StringField('Destination', validators=[DataRequired()])
waypoints = StringField('Waypoint')
#app.route("/", methods = ["GET", "POST"])
def index():
trip_form = TripForm(request.form)
if trip_form.validate_on_submit():
flash("Submitted new trip form, now redirecting to /finalize_new_trip to render map...")
return redirect(url_for("complete_trip", trip_name = trip_form.trip_name.data, origin = trip_form.origin.data, destination = trip_form.destination.data, waypoints = trip_form.waypoints.data))
return render_template("index.html", trip_form = trip_form)
# Route to display trip on map (in future, to modify trip details, e.g. waypoints)
#app.route("/finalize_new_trip", methods=["POST"])
def complete_trip():
return render_template("finish_new_trip.html", trip_name = request.args.get("trip_name"), origin = request.args.get("origin"), destination = request.args.get("destination"), waypoints = request.args.get("waypoints"))
# Store new trip data in database
#app.route("/store_trip", methods=["POST"])
def store_trip():
trip_data = request.form("trip_data")
return json.loads(trip_data)[0]
def query_to_list(query, include_field_names=True):
"""Turns a SQLAlchemy query into a list of data values."""
column_names = []
for i, obj in enumerate(query.all()):
if i == 0:
column_names = [c.name for c in obj.__table__.columns]
if include_field_names:
yield column_names
yield obj_to_list(obj, column_names)
def obj_to_list(sa_obj, field_order):
"""Takes a SQLAlchemy object - returns a list of all its data"""
return [getattr(sa_obj, field_name, None) for field_name in field_order]
if __name__ == "__main__":
app.debug = True
db.create_all()
app.run()
finish_new_trip.html (the template using the Google Maps API to render the map):
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="initial-scale=1.0, user-scalable=no">
<meta charset="utf-8">
<script async defer
src="https://maps.googleapis.com/maps/api/js?v=3.exp&key=<MY_API_KEY>&callback=getOriginCoordinates" type="text/javascript">
</script>
<title>Finish New Trip</title>
</head>
<body>
<div id="trip_name">
<h1> {{ trip_name }} </h1>
</div>
<div id="map"></div>
<div id="right-panel">
<div>
<form>
<input type="submit" id="finish-new-trip-button" value="Add My Trip!">
</form>
</div>
<div id="directions-panel"></div>
</div>
<script>
//Wrapper function to AJAX POST request that passes data back to server.
/*function passTripData() {
document.getElementById("finish-new-trip-button").onclick = function() {
// Retrieve data from displayed map (after user makes changes) after testing
$.post( "{{ url_for('store_trip') }}", {
trip_data: {
"trip_name": "{{ trip_name }}",
"origin": "{{ origin }}",
"destination": "{{ destination }}",
"waypoints": [
"{{ waypoints }}"
]
}
});
}
}*/
//Use Geocoding API to get coordinates for origin, destination, and waypoints.
function getOriginCoordinates() {
//passTripData(); // function that sets onClick event for "Submit" button
var geocoder = new google.maps.Geocoder();
geocoder.geocode( { 'address': "{{ origin }}"}, function(results, status) {
if (status == 'OK') {
originCoordinates = results[0].geometry.location;
console.log("Origin coords: " + "lat = " + originCoordinates.lat() + ", lng = " + originCoordinates.lng());
getDestCoordinates(originCoordinates);
} else {
alert('Geocode of origin was not successful for the following reason: ' + status);
}
});
}
function getDestCoordinates(originCoords) {
var geocoder = new google.maps.Geocoder();
geocoder.geocode( { 'address': "{{ destination }}"}, function(results, status) {
if (status == 'OK') {
destCoordinates = results[0].geometry.location;
console.log("Dest coords: " + "lat = " + destCoordinates.lat() + ", lng = " + destCoordinates.lng());
getWaypointCoordinates(originCoords, destCoordinates);
} else {
alert('Geocode of destination was not successful for the following reason: ' + status);
}
});
}
function getWaypointCoordinates(originCoords, destCoords) {
var geocoder = new google.maps.Geocoder();
geocoder.geocode( { 'address': "{{ waypoints }}"}, function(results, status) {
if (status == 'OK') {
waypointCoordinates = results[0].geometry.location;
console.log("Waypoint coords: " + "lat = " + waypointCoordinates.lat() + ", lng = " + waypointCoordinates.lng());
initMap(originCoords, destCoords, waypointCoordinates);
} else {
alert('Geocode of waypoints was not successful for the following reason: ' + status);
}
});
}
function initMap(originCoords, destCoords, waypointCoords) {
var directionsService = new google.maps.DirectionsService;
var directionsDisplay = new google.maps.DirectionsRenderer;
//Center map between origin and destination.
//TEST LATLNG OBJECTS FIRST
console.log("Origin: lat=" + originCoords.lat() + ", lng=" + originCoords.lng());
console.log("Destination: lat=" + destCoords.lat() + ", lng=" + destCoords.lng());
var mapLatitudeCenter = (originCoords.lat() + destCoords.lat())/2;
var mapLongitudeCenter = (originCoords.lng() + destCoords.lng())/2;
var map = new google.maps.Map(document.getElementById('map'), {
zoom: 6,
center: {lat: mapLatitudeCenter, lng: mapLongitudeCenter}
});
directionsDisplay.setMap(map);
calculateAndDisplayRoute(directionsService, directionsDisplay, originCoords, destCoords, waypointCoords);
}
function calculateAndDisplayRoute(directionsService, directionsDisplay, originCoords, destCoords, waypointCoords) {
var waypts = [];
waypts.push({
location: waypointCoords,
stopover: true
});
directionsService.route({
origin: originCoords,
destination: destCoords,
waypoints: waypts,
optimizeWaypoints: true,
travelMode: 'DRIVING'
}, function(response, status) {
if (status === 'OK') {
directionsDisplay.setDirections(response);
var route = response.routes[0];
var summaryPanel = document.getElementById('directions-panel');
summaryPanel.innerHTML = '';
// For each route, display summary information.
for (var i = 0; i < route.legs.length; i++) {
var routeSegment = i + 1;
summaryPanel.innerHTML += '<b>Route Segment: ' + routeSegment +
'</b><br>';
summaryPanel.innerHTML += route.legs[i].start_address + ' to ';
summaryPanel.innerHTML += route.legs[i].end_address + '<br>';
summaryPanel.innerHTML += route.legs[i].distance.text + '<br><br>';
}
} else {
window.alert('Directions request failed due to ' + status);
}
});
}
</script>
</body>
</html>
When I test my app locally, the console displays the latitude/longitude coordinates of each data point (origin, destination, and waypoints), and they all correspond to this incorrect address in Italy. I also previously received a "404" error message, but I am not receiving that now.
I attempted to regenerate my API key and use this new key, but this didn't fix the problem. How can I go about resolving this issue?
When I change complete_trip(): to
#app.route("/finalize_new_trip", methods=["GET"])
def complete_trip():
return render_template("finish_new_trip.html", trip_name ='new trip', origin='new york, ny', destination='los angeles, california', waypoints='topeka, kansas')
and request the page, the results are perfect (a trip from NY to LA that goes through Topeka). You've got a lot of commented out code everywhere. I have a feeling that somewhere you're not getting the data you expect (for example, we can't see the form HTML used to post this data).
I'm trying to handle disconnect / connect states using Presence in the Channel API.
Here are some of my code.
app.yaml
handlers:
- url: /(.*\.(gif|png|jpg|ico|js|css))
static_files: \1
upload: (.*\.(gif|png|jpg|ico|js|css))
- url: .*
script: main.py
inbound_services:
- channel_presence
main.py
class onConnect(webapp.RequestHandler):
def post(self):
for user in users:
users = User.all().fetch(1000)
client = client_id = self.request.get('from')
channel.send_message(user.channel,' connected');
class onDisconnect(webapp.RequestHandler):
def post(self):
Mainpage()
for user in users:
users = User.all().fetch(1000)
client = client_id = self.request.get('from')
channel.send_message(user.channel, ' disconnected');
application = webapp.WSGIApplication(
[('/', MainPage),
('/_ah/channel/connected/',onConnect),
('/_ah/channel/disconnected/',onDisconnect),
('/chat',handleChat)],
debug=True)
Javascript
<script>
openChannel = function(){
var token = '{{ token }}';
var channel = new goog.appengine.Channel(token);
var handler = {
'onopen': onOpened,
'onmessage': onMessage,
'onerror': function() {},
'onclose': function() {}
};
var socket = channel.open(handler);
socket.onopen = onOpened;
socket.onmessage = onMessage;
var chat = document.getElementById('chatinput');
chat.onkeyup = function(e){
if(e.keyCode == 13){
sendChat(this.value);
this.value = '';
}
}
}
sendMessage = function(path, opt_param) {
if (opt_param) {
path += '?' + opt_param;
}
var xhr = new XMLHttpRequest();
xhr.open('POST', path, true);
xhr.send();
};
onOpened = function(){
console.log('Channel Opened');
var chatlog = document.getElementById('chatlog');
var msg = document.createElement('div');
msg.innerHTML = 'Channel Opened';
chatlog.appendChild(msg);
sendMessage('/chat','m='+'A User Joined.');
}
onMessage = function(m){
console.log('Message Recieved');
var chatlog = document.getElementById('chatlog');
var msg = document.createElement('div');
var d = new Date();
msg.innerHTML = d.toLocaleTimeString() + ': ' + m.data;
chatlog.appendChild(msg);
}
sendChat = function(msg){
console.log(msg);
sendMessage('/chat','m='+msg);
}
openChannel();
</script>
Using this code, connnect and disconnect is not triggering when a user closes their browser or whatever.
Are there anything wrong with this code?
Yes, route list is wrong. Put ('/', MainPage) in the end of the routes list. From webapp2 URI routing guide:
When the application receives a request, it tries to match each one in order until one matches, and then call the corresponding handler.