Adds setting home in account

This commit is contained in:
Joachim Lusiardi 2017-11-07 22:33:14 +01:00
parent 958a9bdd9f
commit 028b52d12f
7 changed files with 274 additions and 16 deletions

View File

@ -1,12 +1,13 @@
from flask import Flask from flask import Flask, make_response
from flask import g from flask import g
from flask_mail import Mail from flask_mail import Mail
from flask_security import Security, SQLAlchemyUserDatastore, user_registered from flask_security import Security, SQLAlchemyUserDatastore, user_registered
from flask_security.forms import LoginForm
from flask_sqlalchemy import SQLAlchemy from flask_sqlalchemy import SQLAlchemy
import os import os
from config import config from config import config
from flask.ext.security.forms import LoginForm from flask_security.forms import LoginForm
from flask_limiter import Limiter
from flask_limiter.util import get_remote_address
from .forms import * from .forms import *
@ -14,6 +15,19 @@ from .forms import *
app = Flask(__name__) app = Flask(__name__)
app.config.from_object(config[os.getenv('FLASK_CONFIG') or 'default']) app.config.from_object(config[os.getenv('FLASK_CONFIG') or 'default'])
limiter = Limiter(
app,
key_func=get_remote_address,
default_limits=["200 per day", "50 per hour"]
)
@app.errorhandler(429)
def ratelimit_handler(e):
return make_response(
jsonify(error="ratelimit exceeded %s" % e.description)
, 429
)
db = SQLAlchemy(app) db = SQLAlchemy(app)
mail = Mail(app) mail = Mail(app)

View File

@ -34,6 +34,9 @@ class User(db.Model, UserMixin):
password = db.Column(db.String(255)) password = db.Column(db.String(255))
active = db.Column(db.Boolean()) active = db.Column(db.Boolean())
confirmed_at = db.Column(db.DateTime()) confirmed_at = db.Column(db.DateTime())
home_lat = db.Column(db.Numeric(2, 5), default=0)
home_long = db.Column(db.Numeric(2, 5), default=0)
home_zoom = db.Column(db.Integer(), default=0)
vehicles = db.relationship( vehicles = db.relationship(
'Vehicle' 'Vehicle'

View File

@ -1,18 +1,21 @@
from flask import url_for, redirect, render_template, request from flask import url_for, redirect, render_template, request, jsonify
from flask_security import login_required from flask_security import login_required
from flask_security.core import current_user from flask_security.core import current_user
from sqlalchemy.exc import IntegrityError from sqlalchemy.exc import IntegrityError
import requests
from ..entities import Vehicle, Consumable from ..entities import Vehicle, Consumable
from ..forms import EditVehicleForm, DeleteVehicleForm, DeleteAccountForm from ..forms import EditVehicleForm, DeleteVehicleForm, DeleteAccountForm
from ..tools import db_log_update, db_log_delete, db_log_add from ..tools import db_log_update, db_log_delete, db_log_add
from .. import app, db, user_datastore from .. import app, db, user_datastore, limiter
@app.route('/account', methods=['GET']) @app.route('/account', methods=['GET'])
@login_required @login_required
def get_account_page(): def get_account_page():
return render_template('account.html') print(current_user.home_lat, current_user.home_long)
return render_template('account.html',
map_pos=(current_user.home_lat, current_user.home_long, current_user.home_zoom))
@app.route('/account/vehicle/edit/<int:vid>', methods=['GET', 'POST']) @app.route('/account/vehicle/edit/<int:vid>', methods=['GET', 'POST'])
@ -37,7 +40,7 @@ def edit_vehicle(vid):
vehicle.name = form.name.data vehicle.name = form.name.data
# we cannot delete consumables where there are pitstops for => report error # we cannot delete consumables where there are pitstops for => report error
vehicle.consumables = [] vehicle.consumables = []
for consumable_id in form.consumables.data: for consumable_id in form.consumables.data:
consumable = Consumable.query.get(consumable_id) consumable = Consumable.query.get(consumable_id)
if consumable is not None: if consumable is not None:
vehicle.consumables.append(consumable) vehicle.consumables.append(consumable)
@ -130,19 +133,60 @@ def delete_account():
return render_template('deleteAccountForm.html', form=form) return render_template('deleteAccountForm.html', form=form)
@app.route('/account/home', methods=['GET'])
@login_required
def get_users_home():
return jsonify(
{'lat': float(current_user.home_lat), 'long': float(current_user.home_long), 'zoom': current_user.home_zoom})
@app.route('/account/home', methods=['POST'])
@login_required
def set_users_home():
current_user.home_lat = request.json['lat']
current_user.home_long = request.json['long']
current_user.home_zoom = request.json['zoom']
db.session.commit()
return jsonify({'lat': float(current_user.home_lat)})
@app.route('/filling_stations', methods=['GET']) @app.route('/filling_stations', methods=['GET'])
#@login_required @login_required
@limiter.limit('1 per second')
def query_filling_stations(): def query_filling_stations():
api_key = app.config['TANKERKOENIG_API_KEY'] api_key = app.config['TANKERKOENIG_API_KEY']
lat = request.args.get('latitude')
lon = request.args.get('longitude') latitude = request.args.get('latitude')
rad = request.args.get('radius', default=10) longitude = request.args.get('longitude')
radius = request.args.get('radius', default=1.5)
type = request.args.get('type', default='all') type = request.args.get('type', default='all')
sort = request.args.get('sort', default='price') sort = request.args.get('sort', default='dist')
return lat
url = 'https://creativecommons.tankerkoenig.de/json/list.php'
params = {
'lat': latitude, 'lng': longitude, 'rad': radius, 'apikey': api_key, 'type': type, 'sort': sort
}
response = requests.get(url, params=params)
print(response.url)
return jsonify(response.json())
@app.route('/filling_stations/<fsid>', methods=['GET']) @app.route('/filling_stations/<fsid>', methods=['GET'])
#@login_required @login_required
@limiter.limit('1 per second')
def query_filling_station_details(fsid): def query_filling_station_details(fsid):
api_key = app.config['TANKERKOENIG_API_KEY'] api_key = app.config['TANKERKOENIG_API_KEY']
return fsid
if ',' in fsid:
# more than one id, redirect to method 2 (preisabfrage)
url = 'https://creativecommons.tankerkoenig.de/json/prices.php'
params = {
'apikey': api_key, 'ids': fsid
}
else:
url = 'https://creativecommons.tankerkoenig.de/json/detail.php'
params = {
'apikey': api_key, 'id': fsid
}
response = requests.get(url, params=params)
return jsonify(response.json())

View File

@ -0,0 +1,162 @@
// initially go to Brandenburger Tor
var lat = 52.516275,
lon = 13.377704,
zoom = 13;
var map;
var filling_stations = {};
var filling_station_markers;
query_location = function(updater) {
if(navigator.geolocation) {
navigator.geolocation.getCurrentPosition(function(position) {
lat = position.coords.latitude;
lon = position.coords.longitude;
if(updater){
updater(lat, lon);
}
});
}
}
update_map = function() {
var lonLat = new OpenLayers.LonLat( lon, lat )
.transform(
new OpenLayers.Projection("EPSG:4326"), // transform from WGS 1984
map.getProjectionObject() // to Spherical Mercator Projection
);
map.setCenter (lonLat, zoom);
//load_filling_stations();
}
load_filling_stations = function() {
var url = '/filling_stations?latitude=' + lat + '&longitude='+ lon + '&type=all&radius=5&sort=dist';
$.ajax({
type: 'GET',
url: url,
success: function(data) {
data.stations.forEach(function(station) {
if (!(station.id in filling_stations)) {
filling_stations[station.id] = station;
filling_stations[station.id].marker = false;
}
});
update_filling_station_markers();
}
});
}
clicked_on_filling_station_marker = function(station) {
return function() {
console.log(station)
/*
var desc = '<div>'+
'<div class="row">' +
'<div class="col-md-6" style="text-align: left;">' + station.brand + '</div>' +
'<div class="col-md-3" style="text-align: left;">Super:</div>' +
'<div class="col-md-3" style="text-align: left;">'+ station.e5 + '€</div>' +
'</div>' +
'<div class="row">' +
'<div class="col-md-6" style="text-align: left;">' + station.name + '</div>' +
'<div class="col-md-3" style="text-align: left;">Super E10:</div>' +
'<div class="col-md-3" style="text-align: left;">'+ station.e10 + '€</div>' +
'</div>' +
'<div class="row">' +
'<div class="col-md-6" style="text-align: left;">' + station.street + ' ' + station.houseNumber + '</div>' +
'<div class="col-md-3" style="text-align: left;">Diesel:</div>' +
'<div class="col-md-3" style="text-align: left;">'+ station.diesel + '€</div>' +
'</div>' +
'<div class="row">' +
'<div class="col-md-6" style="text-align: left;">' + station.postCode + ' ' + station.place + '</div>' +
'<div class="col-md-3" style="text-align: left;">Open:</div>' +
'<div class="col-md-3" style="text-align: left;">'+ station.isOpen + '€</div>' +
'</div>' +
'</div>';
$('#station_info').empty();
$('#station_info').html(desc);
*/
}
}
update_filling_station_markers = function() {
for(id in filling_stations) {
var station = filling_stations[id];
if(!station.marker) {
console.log(station.id);
var lonLat = new OpenLayers.LonLat(station.lng, station.lat)
.transform(new OpenLayers.Projection('EPSG:4326'), map.getProjectionObject());
var marker = new OpenLayers.Marker(lonLat);
marker.events.register('click', marker, clicked_on_filling_station_marker(station));
filling_station_markers.addMarker(marker);
station.marker = true;
}
}
}
activate_map = function(map_div_id, button_ids, home_lat, home_long, home_zoom) {
// resize to reasonable height
$('#' + map_div_id).css('height',0.75*($('#' + map_div_id).css('width')));
// init map
map = new OpenLayers.Map(map_div_id);
map.addLayer(new OpenLayers.Layer.OSM());
map.events.register('moveend', null, function(e){
var p = e.object.center.clone();
var p = p.transform(map.getProjectionObject(), 'EPSG:4326');
lon = p.lon;
lat = p.lat;
zoom = e.object.zoom;
});
filling_station_markers = new OpenLayers.Layer.Markers('Filling Stations');
map.addLayer(filling_station_markers);
update_map();
if ((home_lat == 0) && (home_long == 0)) {
query_location(update_map);
} else {
lat = home_lat;
lon = home_long;
zoom = home_zoom;
console.log(lat, long);
update_map();
}
// get button
$('#'+button_ids[0]).click(function(e){
console.log('clicked get button');
load_filling_stations();
});
// set home button
$('#'+button_ids[1]).click(function(e){
console.log('clicked set home');
console.log(lon);
console.log(lat);
console.log(zoom);
$.ajax({
type: 'POST',
url: '/account/home',
data: JSON.stringify({'long': lon, 'lat': lat, 'zoom': zoom}),
dataType: 'json',
timeout: 1000,
contentType : 'application/json'
});
});
// go home button
$('#'+button_ids[2]).click(function(e){
console.log('clicked the go home button');
$.ajax({
type: 'GET',
url: '/account/home',
dataType: 'json',
timeout: 1000,
success: function(data) {
console.log(data);
lat = data.lat;
lon = data.long;
zoom = data.zoom;
update_map();
},
contentType : 'application/json'
});
});
}

View File

@ -63,6 +63,37 @@
</tbody> </tbody>
</table> </table>
</div> </div>
<div class="panel panel-default">
<div class="panel-heading">Filling Stations</div>
<div class="panel-body">
<div class="row">
<div class="col-md-6 olMap" style="height: 400px" id="mapdiv"></div>
<div class="col-md-6">
<div class="btn-group" role="group">
<button type="button" class="btn btn-default glyphicon glyphicon-home" id="go_home_button" />
<button type="button" class="btn btn-default glyphicon glyphicon-screenshot " id="set_home_button" />
<button type="button" class="btn btn-default glyphicon glyphicon-download" id="get_button" />
</div>
<table class="table">
<thead>
<tr>
<th>Station</th><th></th>
</tr>
</thead>
</table>
<div id="station_info">
</div>
</div>
</div>
</div>
<script>
var lat = {{map_pos[0]}};
var long = {{map_pos[1]}};
var zoom = {{map_pos[2]}};
activate_map('mapdiv', ['get_button', 'set_home_button', 'go_home_button'], lat, long, zoom);
</script>
</div>
<div class="panel panel-default"> <div class="panel panel-default">
<div class="panel-heading">Account</div> <div class="panel-heading">Account</div>
<div class="panel-body"> <div class="panel-body">

View File

@ -133,7 +133,9 @@
<script src="https://www.amcharts.com/lib/3/amcharts.js"></script> <script src="https://www.amcharts.com/lib/3/amcharts.js"></script>
<script src="https://www.amcharts.com/lib/3/serial.js"></script> <script src="https://www.amcharts.com/lib/3/serial.js"></script>
<script src="https://www.amcharts.com/lib/3/themes/patterns.js"></script> <script src="https://www.amcharts.com/lib/3/themes/patterns.js"></script>
<script src="http://openlayers.org/api/OpenLayers.js"></script>
<script src="{{ url_for('static', filename='main.js') }}"></script> <script src="{{ url_for('static', filename='main.js') }}"></script>
<script src="{{ url_for('static', filename='fillingstations.js') }}"></script>
</head> </head>
<body> <body>
<nav class="navbar navbar-inverse navbar-fixed-top"> <nav class="navbar navbar-inverse navbar-fixed-top">

View File

@ -4,3 +4,5 @@ Flask-Security
Flask-WTF Flask-WTF
PyMySQL PyMySQL
markdown markdown
Flask-Limiter
requests