v0.3.0 finalizations

master
Keith Irwin 2016-06-13 00:18:34 +00:00
parent 0dee8b8c9b
commit 8d3417e6a5
No known key found for this signature in database
GPG Key ID: 77A9E9D5A51A7431
18 changed files with 260 additions and 292 deletions

1
adminMongo Submodule

@ -0,0 +1 @@
Subproject commit 3cfe0ed9c01c16d10db7dd96701757ea8ee0a1d2

View File

@ -1,4 +1,5 @@
var passport = require('passport'),
crypto = require('crypto'),
secret = require('./secrets.js'),
User = require('./models/user.js'),
GoogleStrategy = require('passport-google-oauth2').Strategy,
@ -30,12 +31,19 @@ passport.use(new GoogleStrategy({
else {
user.googleID = profile.id;
user.lastLogin = Date.now();
user.save(function(err) {
if (err) {
console.log('Error saving new (invited) user '+err);
var failMessage = 'Something went wrong finding your session. Would you like to <a href="/bug">report this error</a>?';
} else { successMessage = 'Your account has been created. Next maybe you should download the <a href="/android">android app</a>. ' }
done(null, user, { success:successMessage, failure:failMessage });
crypto.randomBytes(32, function(err,buf) {
if (err) {console.log('Unable to get random bytes:',err);}
if (!buf) {console.log('Unable to get random buffer');}
else {
user.sk32 = buf.toString('hex');
user.save(function(err) {
if (err) {
console.log('Error saving new (invited) user '+err);
var failMessage = 'Something went wrong finding your session. Would you like to <a href="/bug">report this error</a>?';
} else { successMessage = 'Your account has been created. Next maybe you should download the <a href="/android">android app</a>. ' }
done(null, user, { success:successMessage, failure:failMessage });
});
}
});
}
});

0
config/bundle/map.js Normal file
View File

View File

@ -1,31 +1,33 @@
secret = require('./secrets.js');
module.exports = {
throwErr: function(req,err){
console.log('Middleware error:'+err+'\nfor request:\n'+req);
if (secret.env==='production') {
req.flash('error', 'An error occured. <br>Would you like to <a href="/bug">report it</a>?');
req.flash('error-message',err);
} else {
req.flash('error',err);
req.flash('error-message',err);
}
},
ensureAuth: function(req,res,next){
if (req.isAuthenticated()) { return next(); }
else {
req.session.returnTo = req.path;
console.log('mw.ensureAuth: Going to redirect to '+req.path+' after login.'); // TODO: Correct next path
req.flash('error', 'You must be signed in to do that. <a href="/login">Click here to log in</a>. ');
res.redirect('/');
}
},
ensureAdmin: function(req,res,next){
if (req.user.isAdmin) { return next(); }
else { res.sendStatus(401); }
var throwErr = function(req,err){
console.log('Middleware error:'+err+'\nfor request:\n'+req);
if (secret.env==='production') {
req.flash('error', 'An error occured. <br>Would you like to <a href="/bug">report it</a>?');
req.flash('error-message',err);
} else {
req.flash('error',err);
req.flash('error-message',err);
}
};
var ensureAuth = function(req,res,next){
if (req.isAuthenticated()) { return next(); }
else {
// req.session.returnTo = req.path;
// console.log('mw.ensureAuth: Going to redirect to '+req.path+' after login.'); // TODO: Correct next path
req.flash('error', 'You must be signed in to do that. <a href="/login">Click here to log in</a>. ');
res.redirect(req.path);
}
};
var ensureAdmin = function(req,res,next){
if (req.isAuthenticated()&&req.user.isAdmin) { return next(); }
else { res.sendStatus(401); }
};
module.exports = {
throwErr,
ensureAuth,
ensureAdmin
};

View File

@ -26,5 +26,6 @@ module.exports = mongoose.model('User', {
dir: Number,
alt: Number,
spd: Number
}
},
sk32: {type:String, required:true, unique:true}
});

View File

@ -1,11 +1,23 @@
var router = require('express').Router(),
fs= require('fs'),
mw = require('../middleware.js'),
mail = require('../mail.js'),
User = require('../models/user.js'),
Request = require('../models/request.js');
router.route('/')
.all(mw.ensureAdmin, function(req,res,next){
fs.readFile(__dirname+'/../../adminMongo/config/app.json', 'utf-8', function(err,data) {
if (err) {console.log('Couldn\'t find adminMongo\'s config/app.json due to an error:',err);}
if (!data) {console.log('Couldn\'t find adminMongo\'s config/app.json');}
else {
res.redirect( req.protocol +'://'+ req.get('host') +':'+ JSON.parse(data).app['port'] +'/Local/tracman' );
}
});
});
router.route('/requests')
.all([mw.ensureAuth, mw.ensureAdmin], function(req,res,next){
.all(mw.ensureAdmin, function(req,res,next){
next();
}).get(function(req,res){
User.findById(req.session.passport.user, function(err, user){
@ -45,7 +57,7 @@ router.route('/requests')
});
router.route('/users')
.all([mw.ensureAuth, mw.ensureAdmin], function(req,res,next) {
.all(mw.ensureAdmin, function(req,res,next) {
next();
}).get(function(req,res){
User.findById(req.session.passport.user, function(err, user){

View File

@ -1,44 +0,0 @@
var router = require('express').Router(),
mail = require('../mail.js'),
mw = require('../middleware.js');
router.route('/suggestion')
.get(function(req,res){
res.redirect('https://productpains.com/product/tracman');
// res.render('suggestion.html', {user:req.user});
}).post(function(req,res){
mail.sendSuggestion({
name: (req.body.name)?req.body.name:req.user.name,
email: (req.body.email)?req.body.email:req.user.email,
suggestion: req.body.suggestion
}, function (err, raw) {
if (err){ mw.throwErr(req,err); }
else { req.flash('success','Thanks for the suggestion! '); }
res.redirect('/map');
});
});
router.route('/bug')
.all(mw.ensureAuth, function(req,res,next){
next();
}).get(function(req,res){
res.render('bug.html', {
user: req.user,
errorMessage: req.flash('error-message')
});
}).post(function(req,res){
mail.sendBugReport({
source: (req.query.source)?req.body.name:'web',
name: (req.body.name)?req.body.name:req.user.name,
email: (req.body.email)?req.body.email:req.user.email,
errorMessage: req.body.errorMessage,
recreation: req.body.recreation,
bug: req.body.bug
}, function (err, raw) {
if (err){ mw.throwErr(req,err); }
else { req.flash('success','Thanks for the report! '); }
res.redirect('/map');
});
});
module.exports = router;

View File

@ -13,7 +13,7 @@ router.route('/')
// Get user
User.findById(req.session.passport.user, function(err, user){
if (err){ mw.throwErr(req,err); }
if (!user){ next(); }
if (!user){ console.log(req.session.passport); next(); }
// If user found:
else {
// Open index

View File

@ -1,6 +1,7 @@
var router = require('express').Router(),
mw = require('../middleware.js'),
secret = require('../secrets.js'),
slug = require('slug'),
User = require('../models/user.js');
// Show map
@ -42,7 +43,7 @@ router.get('/:slug?', function(req,res,next){
if (mapuser==''&&user=='') {
res.redirect('/');
} else {
if (mapuser==''&&user!='') { mapuser = user; }
if (user!=''&&mapuser=='') { mapuser = user; }
res.render('map.html', {
api: secret.mapAPI,
mapuser: mapuser,
@ -56,6 +57,26 @@ router.get('/:slug?', function(req,res,next){
});
router.post('/:slug?', mw.ensureAuth, function(req,res,next){
// Set new user settings
User.findByIdAndUpdate(req.session.passport.user, {$set:{name: req.body.name,
slug: slug(req.body.slug),
settings: {
units: req.body.units,
defaultMap: req.body.map,
defaultZoom: req.body.zoom,
showSpeed: (req.body.showSpeed)?true:false,
showAlt: (req.body.showAlt)?true:false,
showStreetview: (req.body.showStreet)?true:false
}
}}, function(err, user){
if (err) { console.log('Error updating user settings:',err); mw.throwErr(req,err); }
else { req.flash('success', 'Settings updated. '); }
res.redirect('/map#');
});
});
// Redirect /id/ to /slug/
router.get('/id/:id', function(req,res,next){
User.findById(req.params.id, function(err, user){

View File

@ -5,6 +5,7 @@
"main": "server.js",
"dependencies": {
"body-parser": "^1.15.0",
"browserify": "^13.0.1",
"connect-flash": "^0.1.1",
"cookie-parser": "^1.4.1",
"email-templates": "^2.1.0",
@ -15,6 +16,7 @@
"moment": "^2.12.0",
"mongodb": "^2.1.4",
"mongoose": "^4.3.5",
"node-jose": "^0.8.0",
"nunjucks": "^2.3.0",
"passport": "^0.3.2",
"passport-google-id-token": "^0.4.0",

View File

@ -11,6 +11,7 @@
User = require('./config/models/user.js'),
app = express(),
http = require('http').Server(app),
// mongo_express = require('mongo-express/lib/middleware'),
io = require('socket.io')(http);
}
@ -102,6 +103,7 @@
}
/* RUNTIME */ {
// Check for tracking users
function checkForUsers(room) {
if (room) {
@ -118,46 +120,68 @@
}
}
// Websockets
io.on('connection', function(socket) {
// Websockets
io.on('connection', function(sock) {
socket.on('room', function(room) {
socket.join(room);
// Set room to map user ID
sock.on('room', function(room) {
sock.join(room);
if (room.slice(0,4)!='app-'){
// External user
User.findById({_id:room}, function(err, user) {
if (err) { console.log('Sockets error finding tracked user of room '+room+'\n'+err); }
if (user) {
io.to('app-'+room).emit('activate','true'); }
});
} else {
} else { // Sets location
checkForUsers(room.slice(4));
}
});
socket.on('app', function(loc){
// Recieving beacon
sock.on('app', function(loc){
loc.time = Date.now();
io.to(loc.usr).emit('trac', loc);
User.findByIdAndUpdate(loc.usr, {last:{
lat: parseFloat(loc.lat),
lon: parseFloat(loc.lon),
dir: parseFloat(loc.dir||0),
spd: parseFloat(loc.spd||0),
time: Date.now()
}}, function(err, user) {
if (err) { console.log('Could not update last location of user '+loc.user+'\n'+err); }
if (!user) { console.log("No user found: "+loc.user); }
// TODO: Fix this error always being thrown with loc.user = undefined
});
// Check for sk32 token
if (loc.tok) {
// Get loc.usr
User.findById(loc.usr, function(err, user) {
if (err) { console.log('Error finding user:',err); }
if (!user) { console.log('User not found'); }
else {
// Confirm sk32 token
if (loc.tok!=user.sk32) { console.log('loc.tok!=user.sk32 || ',loc.tok,'!=',user.sk32); }
else {
// Broadcast location to spectators
io.to(loc.usr).emit('trac', loc);
// Echo broadcast to transmittors
io.to('app-'+loc.usr).emit('trac', loc);
// Save in db as last seen
user.last = {
lat: parseFloat(loc.lat),
lon: parseFloat(loc.lon),
dir: parseFloat(loc.dir||0),
spd: parseFloat(loc.spd||0),
time: loc.time
};
user.save(function(err) {
if (err) { console.log('Error saving user last location:'+loc.user+'\n'+err); }
});
}
}
});
}
});
socket.onclose = function(reason){
// Shutdown (check for users)
sock.onclose = function(reason){
var closedroom = Object.keys(
socket.adapter.sids[socket.id]).slice(1)[0];
sock.adapter.sids[sock.id]).slice(1)[0];
setTimeout(function() {
checkForUsers(closedroom);
}, 3000);
Object.getPrototypeOf(this).onclose.call(this,reason);
}
};
});

12
setsks.js Normal file
View File

@ -0,0 +1,12 @@
var speakeasy = require('speakeasy');
var User = require('./config/models/user.js');
User.update(
{isPro:false},
{sk32: speakeasy.generateSecret({length: 20}).base32},
{ multi: true },
function(err, num){
if (err) {console.log(err);}
else {console.log(num,'updated');}
}
);

3
static/js/bundle.js Normal file
View File

@ -0,0 +1,3 @@
(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
},{}]},{},[1]);

View File

@ -1,6 +1,21 @@
$(document).ready(function(){
$(".hamburger").click(function(){
$(".hamburger").toggleClass("is-active");
// Open drawer with hamburger
$('.hamburger').click(function(){
$('.hamburger').toggleClass('is-active');
$('nav').toggleClass('visible');
});
// Close drawer after tapping on nav
$('nav').click(function(){
$('.hamburger').removeClass('is-active');
$('nav').removeClass('visible');
});
// Close drawer by tapping outside it
$('.wrap, section').click(function(){
$('.hamburger').removeClass('is-active');
$('nav').removeClass('visible');
});
});

View File

@ -1,64 +0,0 @@
{% extends 'templates/base.html' %}
{% block title %}{{ super() }} | Bug Report{% endblock %}
{% block main %}
<section class='dark'>
<div class='container'>
<h1>Submit a Bug Report</h1>
<p>You can use this form to submit a bug report. You can also <a href="https://github.com/Tracman-org/Server/issues/new">post the issue on github</a>. Or maybe you'd like to <a href="/suggestion">suggest a feature</a> instead? </p>
<script src="/static/js/validator.min.js"></script>
<form id='suggestions-form' class='col-lg-10 col-lg-offset-1 form-horizontal' role="form" method="POST" data-toggle="validator">
<div class='form-group' id='error-message' title="If you recieved an error message, put it here. An error message may be added automatically. ">
<label class='control-label col-sm-2 col-lg-3' for="errorMessage">Error message (if any) </label>
<div class='input-group col-xs-12 col-sm-10 col-lg-9'>
<textarea class='form-control' name="errorMessage" rows="3" maxlength="2400" {% if errorMessage.length %}disabled{% endif %}>{{ errorMessage }}</textarea>
</div>
<div class='help-block with-errors col-xs-12 col-sm-10 col-sm-offset-2 col-lg-9 col-lg-offset-3'></div>
</div>
<div class='form-group' id='recreation' title="Help me recreate the issue. ">
<label class='control-label col-sm-2 col-lg-3' for="recreation">What were you doing when this happened? </label>
<div class='input-group col-xs-12 col-sm-10 col-lg-9'>
<textarea class='form-control' name="recreation" rows="4" maxlength="2400"></textarea>
</div>
<div class='help-block with-errors col-xs-12 col-sm-10 col-sm-offset-2 col-lg-9 col-lg-offset-3'></div>
</div>
<div class='form-group' id='bug' title="Describe the problem here. ">
<label class='control-label col-sm-2 col-lg-3' for="bug">What happened? </label>
<div class='input-group col-xs-12 col-sm-10 col-lg-9'>
<textarea class='form-control' name="bug" rows="4" maxlength="2400"></textarea>
</div>
<div class='help-block with-errors col-xs-12 col-sm-10 col-sm-offset-2 col-lg-9 col-lg-offset-3'></div>
</div>
<div class='form-group' id='name' title="Put your name here if you want. ">
<label class='control-label col-sm-2 col-lg-3' for="name">Name</label>
<div class='input-group col-xs-12 col-sm-10 col-lg-9'>
<input class='form-control' name="name" type="text" value="{{ user.name }}"
maxlength="160"><br>
</div>
<div class='help-block with-errors col-xs-12 col-sm-10 col-sm-offset-2 col-lg-9 col-lg-offset-3'></div>
</div>
<div class='form-group' id='email' title="Put an email address if you want a reply. ">
<label class='control-label col-sm-2 col-lg-3' for="email">Email</label>
<div class='input-group col-xs-12 col-sm-10 col-lg-9'>
<input class='form-control' name="email" type="email" value="{{ user.email }}"
maxlength="160" data-error="That's not an email address"><br>
</div>
<div class='help-block with-errors col-xs-12 col-sm-10 col-sm-offset-2 col-lg-9 col-lg-offset-3'></div>
</div>
<div class='form-group flexbox' id='buttons'>
<button type="submit" class='btn yellow'>SUBMIT</button>
<a class='btn' href="/dashboard">nevermind</a>
</div>
</form>
</div>
</section>
{% endblock %}

View File

@ -12,12 +12,13 @@
<div class='container'>
<h1>Tracman</h1>
<h3>Display your realtime GPS location on a map</h3>
<a class='btn' href="#" data-scrollto="overview">More info<i class='fa fa-angle-down'></i></a>
<!--<a class='btn' href="#" data-scrollto="overview">More info<i class='fa fa-angle-down'></i></a>-->
{% if user %}
<a class='btn' href="/map">Map<i class='fa fa-angle-right'></i></a>
{% else %}
<a class='btn' href="#" data-scrollto="get">Request invite<i class='fa fa-angle-down'></i></a>
<a class='btn' href="/map/keith">View example<i class='fa fa-angle-right'></i></a>
<a class='btn' href="#" data-scrollto="get">Request invite<i class='fa fa-angle-down'></i></a>
<a class='btn' href="/login">Login<i class='fa fa-angle-right'></i></a>
{% endif %}
</div>
</section>

View File

@ -5,6 +5,7 @@
{{super()}}
<link href="/static/css/map.css" rel="stylesheet">
<style>
#notset {display:none}
.popup {
padding: 5vw;
border-radius: 5vw;
@ -15,9 +16,11 @@
-moz-box-shadow: 3px 4px 6px #000;
-webkit-box-shadow: 3px 4px 6px #000;
box-shadow: 3px 4px 6px #000;
top: 10vh; bottom: 10vh;
left:10vw; right: 10vw;
top: calc(60px + 5vw);
bottom: calc(30px + 5vw);
left:5vw; right: 5vw;
overflow-y: auto;
overflow-x: hidden;
}.popup .close {
position: relative;
top: -15px;
@ -100,7 +103,7 @@
</div>
<h2>Share</h2>
<p>This link will display the map of your location:
<br><a href="/map/{{user.slug}}">https://tracman.org/map/{{user.slug}}</a>
<a href="/map/{{user.slug}}">https://tracman.org/map/{{user.slug}}</a>
<br>Here are some buttons for your convienence:
<a href="https://twitter.com/home?status=A%20map%20of%20my%20realtime%20location:%20https://tracman.org/map/{{user.slug}}" target="_blank"><i class="share fa fa-twitter"></i></a>
<a href="https://www.facebook.com/sharer/sharer.php?u=https://tracman.org/map/{{user.slug}}" target="_blank"><i class="share fa fa-facebook"></i></a>
@ -225,8 +228,8 @@
</div>
</form>
<!--{% if not user.isPro %}<p style="clear:both">Want to try <a href="/pro">Tracman Pro</a>? It's free during beta testing. </p>{% endif %}-->
<!--<p style="clear:both">Would you like to submit a <a href="/suggestion">suggestion</a> or <a href="/bug">bug report</a>? </p>-->
{% if not user.isPro %}<p style="clear:both">Want to try <a href="/pro">Tracman Pro</a>? It's free during beta testing. </p>{% endif %}
<p style="clear:both">Would you like to submit a <a href="https://productpains.com/create/tracman">suggestion</a> or <a href="https://github.com/Tracman-org/Server/issues/new">bug report</a>? </p>
</div>
{% endif %}
@ -254,6 +257,7 @@
display: flex;
justify-content: space-around;
}#controls .btn {
padding: 15px 0;
background: #222;
width: 30vw;
}#controls .btn:hover {
@ -276,11 +280,12 @@
</div>
<script src="https://cdn.socket.io/socket.io-1.2.0.js"></script>
<script src="/static/js/bundle.js"></script>
<script src="https://maps.googleapis.com/maps/api/js?key={{api}}&callback=gmapsCb" async defer></script>
<script>
// Variables
{ var wpid, map, pano, sv, marker, elevator,
socket = io.connect(),
sock = io.connect(),
mapuserid = {{mapuser._id |dump|safe}},
userid{% if user._id %} = {{user._id |dump|safe}}{% endif %},
settings = JSON.parse('{{mapuser.settings |dump|safe}}'),
@ -292,12 +297,16 @@
}
// Connect to socket.io
socket.on('connect', function(){
socket.emit('room',
sock.on('connect', function(){
sock.emit('room',
(userid)? 'app-'+userid :mapuserid
);
});
// }).on('data', function (data) {
// console.log(data);
}).on('error', function (err){
console.error('Unable to connect Socket.IO', err);
});
// Check for location.hash capability (IE9+)
if (!'onhashchange' in window) {
alert("location.hash won't work in IE<9. If you don't know how to fix this, google 'how to update browser'. ");
@ -421,26 +430,21 @@
// Open popups
function setPopups() {
console.log('Setting popups');
if (location.hash === "#share") {
console.log('Setting popups to share');
$('.settings.popup').hide();
$('.share.popup').show();
} else if (location.hash === "#settings") {
console.log('Setting popups to settings');
$('.share.popup').hide();
$('.settings.popup').show();
} else {
console.log('Setting popups to default');
} else {
$('.settings.popup').hide();
$('.share.popup').hide;
$('.share.popup').hide();
}
} setPopups(); // Execute immediately
window.onhashchange = setPopups; // Execute on change
// Get location
socket.on('trac', function(loc) {
console.log('recieved location');
sock.on('trac', function(loc) {
loc = parseLoc(loc);
if (disp!='1' || !settings.showStreetview) {
$('.tim').text('location updated '+loc.time);
@ -457,69 +461,86 @@
updateStreetView(loc,10);
});
// Set location
function setLocation() {
if (!userid==mapuserid) {alert('You are not logged in! ');}
else {
if (!navigator.geolocation) {alert('Geolocation not enabled. ');}
{% if user %}
var token = '{{user.sk32}}';
// Set location
function setLocation() {
if (!userid==mapuserid) {alert('You are not logged in! '); next();}
else {
navigator.geolocation.getCurrentPosition(function(pos){
console.log('Emitting location');
socket.emit('app',{
usr: userid,
lat: pos.coords.latitude,
lon: pos.coords.longitude,
spd: (pos.coords.speed||0)
});
}, function(err) {
if (err) { alert('ERROR: '+err); }
else { location.reload(); }
}, { enableHighAccuracy:true });
}
}
}
// Track location
function trackLocation() {
if (!userid==mapuserid) { alert('You are not logged in! '); }
else {
// Stop tracking
if (wpid) {
$('#controls > .track').html('<i class="fa fa-crosshairs"></i>&emsp;Track').tooltip('hide');
navigator.geolocation.clearWatch(wpid);
wpid = undefined;
// Start tracking
} else {
$('#controls > .track').html('<i class="fa fa-crosshairs fa-spin"></i>&emsp;Stop').tooltip('show');
if (!navigator.geolocation) { alert('Unable to track location. '); }
if (!navigator.geolocation) {alert('Geolocation not enabled. ');}
else {
wpid = navigator.geolocation.watchPosition(function(pos) {
socket.emit('app', {
usr: '{{user.id}}',
navigator.geolocation.getCurrentPosition(function(pos){
newloc = {
tok: token,
usr: userid,
lat: pos.coords.latitude,
lon: pos.coords.longitude,
spd: (pos.coords.speed||0)
});
// console.log('Sent location:',pos.coords.latitude.toFixed(2)+','+pos.coords.longitude.toFixed(2));
}, function(err){
alert('Failed to track: \n'+err);
}
sock.emit('app',newloc);
toggleMaps(newloc);
}, function(err) {
console.log('done getting position');
if (err) { console.log('ERROR: '+err); }
}, { enableHighAccuracy:true });
}
}
}
}
// Clear location
function clearLocation() {
if (!userid==mapuserid) { alert('You are not logged in! '); }
else {
socket.emit('app', {
usr: userid,
lat:0, lon:0, spd:0
});
location.reload();
}
}
// Track location
function trackLocation() {
if (!userid==mapuserid) { alert('You are not logged in! '); }
else {
// Stop tracking
if (wpid) {
$('#controls > .track').html('<i class="fa fa-crosshairs"></i>&emsp;Track').tooltip('hide');
navigator.geolocation.clearWatch(wpid);
wpid = undefined;
// Start tracking
} else {
$('#controls > .track').html('<i class="fa fa-crosshairs fa-spin"></i>&emsp;Stop').tooltip('show');
if (!navigator.geolocation) { alert('Unable to track location. '); }
else {
wpid = navigator.geolocation.watchPosition(function(pos) {
newloc = {
tok: token,
usr: '{{user.id}}',
lat: pos.coords.latitude,
lon: pos.coords.longitude,
spd: (pos.coords.speed||0)
};
sock.emit('app',newloc);
toggleMaps(newloc);
}, function(err){
alert('Failed to track: \n'+err);
}, { enableHighAccuracy:true });
}
}
}
}
// Clear location
function clearLocation() {
if (!userid==mapuserid) { alert('You are not logged in! '); }
else {
// Stop tracking
if (wpid) {
$('#controls > .track').html('<i class="fa fa-crosshairs"></i>&emsp;Track').tooltip('hide');
navigator.geolocation.clearWatch(wpid);
wpid = undefined;
}
newloc = {
tok: token,
usr: userid,
lat:0, lon:0, spd:0
}
sock.emit('app',newloc);
toggleMaps(newloc);
}
}
{% endif %}
// Check altitude
function getAltitude(loc,elev,cb){
@ -586,4 +607,5 @@
}
</script>
{% endblock %}

View File

@ -1,48 +0,0 @@
{% extends 'templates/base.html' %}
{% block title %}{{super()}} | Suggestion{% endblock %}
{% block main %}
<section class='dark'>
<div class='container'>
<h1>Suggest a Feature</h1>
<p>You can use this form to suggest new features. Or maybe you need to <a href="/bug">submit a bug report</a> instead? </p>
<script src="/static/js/validator.min.js"></script>
<form id='suggestions-form' class='col-lg-10 col-lg-offset-1 form-horizontal' role="form" method="POST" data-toggle="validator">
<div class='form-group' id='suggestion'>
<label class='control-label col-sm-2 col-lg-3' for="suggestion">What feature could improve Tracman? </label>
<div class='input-group col-xs-12 col-sm-10 col-lg-9'>
<textarea class='form-control' name="suggestion" rows="5" required maxlength="2400" data-error="You have to make a suggestion! "></textarea>
</div>
<div class='help-block with-errors col-xs-12 col-sm-10 col-sm-offset-2 col-lg-9 col-lg-offset-3'></div>
</div>
<div class='form-group' id='name' title="Put your name here if you want. ">
<label class='control-label col-sm-2 col-lg-3' for="name">Name</label>
<div class='input-group col-xs-12 col-sm-10 col-lg-9'>
<input class='form-control' name="name" type="text" value="{{ user.name }}"
maxlength="160"><br>
</div>
<div class='help-block with-errors col-xs-12 col-sm-10 col-sm-offset-2 col-lg-9 col-lg-offset-3'></div>
</div>
<div class='form-group' id='email' title="Put an email address if you want a reply. ">
<label class='control-label col-sm-2 col-lg-3' for="email">Email</label>
<div class='input-group col-xs-12 col-sm-10 col-lg-9'>
<input class='form-control' name="email" type="email" value="{{ user.email }}"
maxlength="160" data-error="That's not an email address"><br>
</div>
<div class='help-block with-errors col-xs-12 col-sm-10 col-sm-offset-2 col-lg-9 col-lg-offset-3'></div>
</div>
<div class='form-group flexbox' id='buttons'>
<button type="submit" class='btn yellow'>SUBMIT</button>
<a class='btn' href="/dashboard">nevermind</a>
</div>
</form>
</div>
</section>
{% endblock %}