Various updates

master
keith24 2016-03-26 19:04:56 -04:00
parent 9dd203750e
commit 51c46bc032
22 changed files with 526 additions and 514 deletions

View File

@ -1 +1 @@
{ "_id" : { "$oid" : "56b020279f740067540f96e9" }, "googleID" : 1.044820980603112e+20, "slug" : "keith", "email" : "mail@keithirwin.us", "name" : "Keith", "created" : { "$date" : "2016-02-01T22:19:03.062-0500" }, "lastLogin" : { "$date" : "2016-03-11T02:00:47.868-0500" }, "last" : { "time" : { "$date" : "2016-03-11T04:29:49.046-0500" }, "spd" : 0, "dir" : 0, "lon" : -74.8288264, "lat" : 39.9087593 }, "settings" : { "showStreetview" : false, "showAlt" : true, "showSpeed" : true, "defaultZoom" : 11, "defaultMap" : "sat", "units" : "imperial" }, "isAdmin" : true, "isPro" : true }
{ "_id" : { "$oid" : "56b020279f740067540f96e9" }, "googleID" : 1.044820980603112e+20, "slug" : "keith", "email" : "mail@keithirwin.us", "name" : "Keith", "created" : { "$date" : "2016-02-02T04:19:03.062+0100" }, "lastLogin" : { "$date" : "2016-03-19T22:59:48.941+0100" }, "last" : { "time" : { "$date" : "2016-03-19T23:58:20.990+0100" }, "spd" : 0, "dir" : 0, "lon" : -74.8288264, "lat" : 39.9087593 }, "settings" : { "showStreetview" : false, "showAlt" : true, "showSpeed" : true, "defaultZoom" : 11, "defaultMap" : "sat", "units" : "imperial" }, "isAdmin" : true, "isPro" : true }

View File

@ -22,7 +22,7 @@ passport.use(new GoogleStrategy({
});
done(null, user);
} else { // No existing user with google auth
if (req.session.passport.user) { // Creating new user
if (req.session.passport) { // Creating new user
User.findById(req.session.passport.user, function(err, user){
user.googleID = profile.id;
user.lastLogin = Date.now();

View File

@ -13,11 +13,18 @@ app.use(bodyParser.urlencoded({
}));
app.use(bodyParser.json());
// Test authentication/admin
function ensureAuthenticated(req,res,next) {
function throwErr(req,err) {
console.log(err);
req.flash('error-message',err);
req.flash('error', (err.message||'')+'<br>Would you like to <a href="/bug">report this error</a>?');
}
function ensureAuth(req,res,next) {
if (req.isAuthenticated()) { return next(); }
else { req.flash('error', 'You must be signed in to do that. <a href="/login">Click here to log in</a>. ');
res.redirect('/'); }
else {
req.session.returnTo = req.path;
req.flash('error', 'You must be signed in to do that. <a href="/login">Click here to log in</a>. ');
res.redirect('/');
}
}
function ensureAdmin(req,res,next) {
if (req.user.isAdmin) { return next(); }
@ -38,11 +45,10 @@ module.exports = function(app){
.all(function(req,res,next){
next();
}).get(function(req,res){
if (req.session.passport!=undefined) {
if (req.session.passport) {
User.findById(req.session.passport.user, function(err, user){
if (err){ console.log(err);
req.flash('error-message', err);
req.flash('error', err.message+'<br>Would you like to <a href="/bug">report this error</a>?'); }
if (err){ throwErr(req,err); }
if (!user){ next(); }
res.render('index.html', {
user: user,
error: req.flash('error')[0],
@ -59,58 +65,49 @@ module.exports = function(app){
}
}).post(function(req,res){
Request.findOne({email:req.body.email}, function(err, request) {
if (err) { console.log(err);
req.flash('error-message', err);
req.flash('error', err.message+'<br>Would you like to <a href="/bug">report this error</a>?');
res.redirect('/');
} else if (!err && request == null) { // Send new request
if (err){ throwErr(req,err); }
if (request){ // Already requested with this email
req.flash('request-error', 'Invite already requested! ');
res.redirect('/#get');
} else { // Send new request
request = new Request({
name: req.body.name,
email: req.body.email,
beg: req.body.why,
requestedTime: Date.now()
}); request.save(function(err) {
if (err) { console.log(err);
req.flash('error-message', err);
req.flash('error', err.message+'<br>Would you like to <a href="/bug">report this error</a>?');
res.redirect('/');
} else {
mail.mailgun.messages().send({
from: 'Tracman Requests <requests@tracman.org>',
to: 'Keith Irwin <tracman@keithirwin.us>',
subject: 'New Tracman Invite request',
html: '<p>'+req.body.name+' requested a Tracman invite. </p><p>'+req.body.why+'</p><p><a href="http://tracman.org/admin/requests">See all invites</a></p>',
text: '\n'+req.body.name+' requested a Tracman invite. \n\n'+req.body.why+'\n\nhttp://tracman.org/admin/requests'
}, function(err,body){
if (err){ console.log(err);
req.flash('error-message', err);
req.flash('error', err.message+'<br>Would you like to <a href="/bug">report this error</a>?');
}
req.flash('request-success', 'Invite requested! ');
res.redirect('/#get');
});
}
if (err){ throwErr(req,err); }
mail.mailgun.messages().send({
from: 'Tracman Requests <requests@tracman.org>',
to: 'Keith Irwin <tracman@keithirwin.us>',
subject: 'New Tracman Invite request',
html: '<p>'+req.body.name+' requested a Tracman invite. </p><p>'+req.body.why+'</p><p><a href="http://tracman.org/admin/requests">See all invites</a></p>',
text: '\n'+req.body.name+' requested a Tracman invite. \n\n'+req.body.why+'\n\nhttp://tracman.org/admin/requests'
}, function(err,body){
if (err){ throwErr(req,err); }
else { req.flash('request-success', 'Invite requested! '); }
res.redirect('/#get');
});
});
} else { // Already requested with this email
req.flash('request-error', 'Invite alreay requested! ');
res.redirect('/#get');
}
});
});
app.route('/dashboard')
.all(ensureAuthenticated, function(req,res,next){
.all(ensureAuth, function(req,res,next){
next();
}).get(function(req,res){
User.findById(req.session.passport.user, function(err, user){
if (err){ console.log(err);
req.flash('error-message',err);
req.flash('error', err.message+'<br>Would you like to <a href="/bug">report this error</a>?');}
res.render('dashboard.html', {
if (err){ throwErr(req,err); }
if (!user){ next(); }
else if (req.session.returnTo && req.query.rd) {
res.redirect(req.session.returnTo);
delete req.session.returnTo;
} else { res.render('dashboard.html', {
user: user,
success: req.flash('success')[0],
error: req.flash('error')[0]
});
}); }
});
}).post(function(req,res){
User.findByIdAndUpdate(req.session.passport.user, {$set:{
@ -125,53 +122,46 @@ module.exports = function(app){
showStreetview: (req.body.showStreet)?true:false
}
}}, function(err, user){
if (err){ console.log(err);
req.flash('error-message',err);
req.flash('error', err.message+'<br>Would you like to <a href="/bug">report this error</a>?');
} else { req.flash('success', 'Settings updated. '); }
if (err) { throwErr(req,err); }
else { req.flash('success', 'Settings updated. '); }
res.redirect('/dashboard');
});
});
app.get('/validate', function(req,res){
if (req.query.slug) { // validate unique slug
User.findOne({slug:req.query.slug}, function(err, existingUser){
User.findOne({slug:slug(req.query.slug)}, function(err, existingUser){
if (existingUser && existingUser.id!==req.session.passport.user) { res.sendStatus(400); }
else { res.sendStatus(200); }
});
}
});
app.get('/trac', function(req,res,next){
app.get('/trac', ensureAuth, function(req,res,next){
User.findById(req.session.passport.user, function(err, user){
if (err) { console.log(err);
req.flash('error-message',err);
req.flash('error', err.message+'<br>Would you like to <a href="/bug">report this error</a>?'); }
if (user) { res.redirect('/trac/'+user.slug); }
else { next(); }
if (err){ throwErr(req,err); }
if (!user){ next(); }
else { res.redirect('/trac/'+user.slug+((req.url.indexOf('?')<0)?'':('?'+req.url.split('?')[1]))); }
});
});
app.get('/trac/:slug', function(req,res,next){
User.findOne({slug:req.params.slug}, function(err, tracuser) {
if (err) { console.log(err);
req.flash('error-message',err);
req.flash('error', err.message+'<br>Would you like to <a href="/bug">report this error</a>?'); }
if (err){ throwErr(req,err); }
if (!tracuser){ next(); }
else {
res.render('trac.html', {
api: secret.mapAPI,
user: req.user,
tracuser: tracuser,
noHeader: req.query.noheader
});
}
else { res.render('trac.html',{
api: secret.mapAPI,
user: req.user,
tracuser: tracuser,
noFooter: '1',
noHeader: (req.query.noheader)?req.query.noheader.match(/\d/)[0]:'',
disp: (req.query.disp)?req.query.disp.match(/\d/)[0]:'' // 0=map, 1=streetview, 2=both
}); }
});
});
app.get('/trac/id/:id', function(req,res){
User.findById(req.params.id, function(err, user){
if (err) { console.log(err);
req.flash('error-message',err);
req.flash('error', err.message+'<br>Would you like to <a href="/bug">report this error</a>?'); }
res.redirect('/trac/'+user.slug);
if (err){ throwErr(req,err); }
if (!user){ next(); }
else { res.redirect('/trac/'+user.slug+((req.url.indexOf('?')<0)?'':('?'+req.url.split('?')[1]))); }
});
});
app.get('/invited/:invite', function(req,res,next){
@ -180,8 +170,8 @@ module.exports = function(app){
if (existingUser) { res.redirect('/login'); }
else {
Request.findById(req.params.invite, function(err, request) { // Check for granted invite
if (err) { console.log('routes.js:125 ERROR: '+err); }
if (!request.granted) { next(); }
if (err) { throwErr(req,err); }
if (!request) { next(); }
else {
user = new User({ // Create new user
requestId: request._id,
@ -197,19 +187,19 @@ module.exports = function(app){
showStreetview: true
}
}); user.save(function(err) {
if (err) { console.log('routes.js:141 ERROR: '+err); }
if (err) { throwErr(req,err); }
User.findOne({requestId:request._id}, function(err, user) {
if (err) { console.log('routes.js:143 ERROR: '+err); }
if (err) { throwErr(req,err); }
if (user) {
request.userId = user._id;
request.save(function(err, raw){
if (err) { console.log('routes.js:147 ERROR: '+err); }
if (err){ throwErr(req,err); }
});
req.logIn(user, function(err) {
if (err) { console.log('routes.js:150: logIn() ERROR: '+err); }
if (err) { throwErr(req,err); }
user.lastLogin = Date.now();
user.save(function(err, raw) {
if (err) { console.log('routes.js:153 ERROR: '+err); }
if (err) { throwErr(req,err); }
res.redirect('/login');
});
});
@ -222,30 +212,27 @@ module.exports = function(app){
});
});
app.get('/android', ensureAuthenticated, function(req,res){
app.get('/android', ensureAuth, function(req,res){
res.redirect('https://play.google.com/store/apps/details?id=us.keithirwin.tracman');
});
app.get('/license', function(req,res){
res.render('license.html', {user:req.user});
});
app.route('/pro')
.all(ensureAuthenticated, function(req,res,next){
.all(ensureAuth, function(req,res,next){
next();
}).get(function(req,res){
User.findById(req.session.passport.user, function(err, user){
if (err){ console.log(err);
req.flash('error-message',err);
req.flash('error', err.message+'<br>Would you like to <a href="/bug">report this error</a>?'); }
res.render('pro.html', {user:user});
if (err){ throwErr(req,err); }
if (!user){ next(); }
else { res.render('pro.html', {user:user}); }
});
}).post(function(req,res){
User.findByIdAndUpdate(req.session.passport.user,
{$set:{ isPro:true }},
function(err, user){
if (err) { console.log(err);
req.flash('error-message', err);
req.flash('error', err.message+'<br>Would you like to <a href="/bug">report this error</a>?');
} else { req.flash('success', 'You have been signed up for pro. '); }
if (err){ throwErr(req,err); }
else { req.flash('success','You have been signed up for pro. '); }
res.redirect('/dashboard');
}
);
@ -260,15 +247,13 @@ module.exports = function(app){
email: (req.body.email)?req.body.email:req.user.email,
suggestion: req.body.suggestion
}, function (err, raw) {
if (err) { console.log(err);
req.flash('error-message',err);
req.flash('error', err.message+'<br>Would you like to <a href="/bug">report this error</a>?');
} else { req.flash('success', 'Thanks for the suggestion! '); }
if (err){ throwErr(req,err); }
else { req.flash('success','Thanks for the suggestion! '); }
res.redirect('/dashboard');
});
});
app.route('/bug')
.all(ensureAuthenticated, function(req,res,next){
.all(ensureAuth, function(req,res,next){
next();
}).get(function(req,res){
res.render('bug.html', {
@ -284,27 +269,24 @@ module.exports = function(app){
recreation: req.body.recreation,
bug: req.body.bug
}, function (err, raw) {
if (err) { console.log(err);
req.flash('error-message', err);
req.flash('error', err.message+'<br>Would you like to <a href="/bug">report this error</a>?');
} else { req.flash('success', 'Thanks for the report! '); }
if (err){ throwErr(req,err); }
else { req.flash('success','Thanks for the report! '); }
res.redirect('/dashboard');
});
});
// ADMIN
app.route('/admin/requests')
.all([ensureAuthenticated, ensureAdmin], function(req,res,next){
.all([ensureAuth, ensureAdmin], function(req,res,next){
next();
}).get(function(req,res){
User.findById(req.session.passport.user, function(err, user){
if (err){ console.log(err);
req.flash('error', err.message); }
if (err){ req.flash('error', err.message); }
Request.find({}, function(err, requests){
if (err) { console.log(err);
req.flash('error', err.message); }
if (err) { req.flash('error', err.message); }
res.render('admin/requests.html', {
user: user,
noFooter: '1',
requests: requests,
success:req.flash('success')[0],
error:req.flash('error')[0]
@ -313,31 +295,27 @@ module.exports = function(app){
});
}).post(function(req,res){
Request.findById(req.body.invite, function(err, request){
if (err){ console.log(err);
req.flash('error', err.message); }
if (err){ req.flash('error', err.message); }
mail.sendInvite(request, function (err, raw) {
if (err) { console.log(err);
req.flash('error', err.message); }
if (err) { req.flash('error', err.message); }
request.granted = Date.now();
request.save(function(err) {
if (err) { console.log(err);
req.flash('error', err.message); }
if (err) { req.flash('error', err.message); }
});
req.flash('success', 'Invitation sent to <i>'+request.name+'</i>.');
res.redirect('/admin/requests');
});
});
});
app.get('/admin/users', [ensureAuthenticated, ensureAdmin], function(req,res){
app.get('/admin/users', [ensureAuth, ensureAdmin], function(req,res){
User.findById(req.session.passport.user, function(err, user){
if (err){ console.log(err);
req.flash('error', err.message); }
if (err){ req.flash('error', err.message); }
User.find({}, function(err, users){
if (err) { console.log(err);
req.flash('error', err.message); }
if (err) { req.flash('error', err.message); }
res.render('admin/users.html', {
user: user,
users: users,
noFooter: '1',
success:req.flash('success')[0],
error:req.flash('error')[0]
});
@ -360,12 +338,12 @@ module.exports = function(app){
app.get('/auth/google/callback', passport.authenticate('google', {
failureRedirect: '/',
failureFlash: true,
successRedirect: '/dashboard',
successRedirect: '/dashboard?rd=1',
successFlash: true
} ));
app.get('/auth/google/idtoken', passport.authenticate('google-id-token'), function (req,res) {
if (!req.user) {res.sendStatus(401);}
else {res.send(req.user);}
if (!req.user) { res.sendStatus(401); }
else { res.send(req.user); }
} );
}

View File

@ -23,14 +23,17 @@
"slug": "^0.9.1",
"socket.io": "^1.4.4"
},
"devDependencies": {},
"devDependencies": {
"chai": "^3.5.0",
"chai-http": "^2.0.1"
},
"scripts": {
"test": "test.js",
"start": "node server.js"
},
"repository": {
"type": "git",
"url": "git+https://github.com/keith24/tracman-server.git"
"url": "git+https://github.com/tracman-org/server.git"
},
"keywords": [
"tracking",
@ -41,7 +44,7 @@
"license": "MIT",
"README": "README.md",
"bugs": {
"url": "https://github.com/keith24/tracman-server/issues"
"url": "https://tracman.org/bug"
},
"homepage": "http://tracman.org/"
"homepage": "https://tracman.org/"
}

View File

@ -25,6 +25,7 @@ app.use(session({
saveUninitialized: true,
resave: true
}));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({
extended: true
}));
@ -47,10 +48,12 @@ var handle404 = function(err,req,res,next) {
var handle500 = function(err,req,res,next) {
res.render('error.html', {code:500});
};
app.use(crash.handle404(handle404));
app.use(crash.handle500(handle500));
crash.trapRoute(app);
crash.handle(app, handle404, handle500);
if (secret.url.substring(0,16)!='http://localhost') {
app.use(crash.handle404(handle404));
app.use(crash.handle500(handle500));
crash.trapRoute(app);
crash.handle(app, handle404, handle500);
}
// Check for tracking users
function checkForUsers(room) {
@ -68,6 +71,7 @@ function checkForUsers(room) {
}
}
// Sockets
io.on('connection', function(socket) {
socket.on('room', function(room) {
@ -75,10 +79,7 @@ io.on('connection', function(socket) {
if (room.slice(0,4)!='app-'){
User.findById({_id:room}, function(err, user) {
if (err) { console.log(err); }
if (user) {
io.to(room).emit('trac', user.last);
io.to('app-'+room).emit('activate', 'true');
}
if (user) { io.to('app-'+room).emit('activate','true'); }
});
} else {
checkForUsers(room.slice(4));
@ -122,8 +123,8 @@ passport.deserializeUser(function(id, done) {
});
// SERVE
http.listen(secret.httpPort, function(){
console.log('Listening for http on port '+secret.httpPort.toString());
http.listen(62054, function(){
console.log('Listening for http on port 62054');
checkForUsers();
});

View File

@ -1,5 +1,4 @@
/* Resets, Clears & Defaults */
*, *:after, *:before {
box-sizing: border-box;
}
@ -76,20 +75,15 @@ h1, h2, h3, p {
z-index: 6;
}
h1,h2,h3,h4 { font-weight: 600; }
h1 {
font-size: 40px;
line-height: 46px;
font-weight: 600;
}
font-size: 48px;
line-height: 46px; }
h2 {
font-size: 28px;
line-height: 36px;
font-weight: 600;
}
h3 {
font-size: 20px;
font-weight: 600;
}
font-size: 40px;
line-height: 36px; }
h3 { font-size: 28px; }
h4 { font-size: 20px; }
.red { color: #fb6e3d; }

View File

@ -174,8 +174,8 @@
position: relative;
z-index: 10;
}
.disclaimer a, disclaimer:hover {
color:inherit;
.disclaimer a, .disclaimer a:hover {
color:#fb6e3d;
}
.get {

Binary file not shown.

Before

Width:  |  Height:  |  Size: 552 KiB

After

Width:  |  Height:  |  Size: 552 KiB

35
test.js Normal file
View File

@ -0,0 +1,35 @@
var chai = require('chai'),
chaiHttp = require('chai-http'),
server = require('./server'),
should = chai.should();
chai.use(chaiHttp);
describe('Routes', function() {
it('Displays homepage', function(done){
chai.request(server)
.get('/')
.end(function(err,res){
res.should.have.status(200);
done();
});
});
it('Displays robots.txt', function(done){
chai.request(server)
.get('/robots.txt')
.end(function(err,res){
res.should.have.status(200);
res.should.be.text;
done();
});
});
it('Displays a tracpage', function(done){
chai.request(server)
.get('/trac/keith')
.end(function(err,res){
res.should.have.status(200);
done();
});
});
});

View File

@ -1,12 +1,13 @@
{% extends 'templates/base.html' %}
{% block title %}Tracman | Invite Requests{% endblock %}
{% block main %}
{% include 'templates/header.html' %}
{% block head %}
<style>
.container { max-width:90%; }
</style>
{% endblock %}
{% block main %}
<section class='dark'>
<div class='container'>
<h1>Requests</h1>

View File

@ -1,12 +1,13 @@
{% extends 'templates/base.html' %}
{% block title %}Tracman | Users{% endblock %}
{% block main %}
{% include 'templates/header.html' %}
{% block head %}
<style>
.container { max-width:90%; }
</style>
{% endblock %}
{% block main %}
<section class='dark'>
<div class='container'>
<h1>Users</h1>

View File

@ -1,71 +1,64 @@
{% extends 'templates/base.html' %}
{% block title %}Tracman | Bug Report{% endblock %}
{% block title %}{{ super() }} | Bug Report{% endblock %}
{% block main %}
{% include 'templates/header.html' %}
<section class='dark'>
<div class='container'>
<h1>Submit a Bug Report</h1>
<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>
<p>You can use this form to submit a bug report. 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">
<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 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 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 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 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 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>
<!--
col-xs-4 col-xs-offset-1 col-lg-3 col-lg-offset-2
col-xs-4 col-xs-offset-1 col-lg-3 col-lg-offset-1
-->
</div>
</section>
{% include 'templates/footer.html' %}
<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

@ -1,28 +1,34 @@
{% extends 'templates/base.html' %}
{% block title %}Tracman | Dashboard{% endblock %}
{% block title %}{{ super() }} | Dashboard{% endblock %}
{% block head %}
{{ super() }}
<style>
.google-play {
width:150px;
border: #fbc93d solid 1px;
border-radius:10px; }
</style>
{% endblock %}
{% block main %}
{% include 'templates/header.html' %}
<style>
.google-play {
width:150px;
border: #fbc93d solid 1px;
border-radius:10px; }
</style>
<section class='dark'>
<div class='container'>
<h1>Welcome{% if user.name %}, {{ user.name }}{% endif %}!</h1>
<p>To view your location, use this link: <a href="/trac/{{ user.slug }}">http://tracman.org/trac/{{ user.slug }}</a></p>
<p>You can also embed a map into your website with this code. Be sure to set the width and height attributes to suit your circumstance. </p>
<pre>&lt;iframe src=&quot;https://tracman.org/trac/{{ user.slug }}?noheader=1&quot; width=&quot;90%&quot; style=&quot;height:90vh;&quot;&gt;&lt;/iframe&gt;</pre>
</div>
<br>
<div class='container'>
<h2>App</h2>
<p>Click the button below to download the app from the google play store, if you haven't already. </p>
<p><a href="https://play.google.com/store/apps/details?id=us.keithirwin.tracman&utm_source=global_co&utm_medium=prtnr&utm_content=Mar2515&utm_campaign=PartBadge&pcampaignid=MKT-AC-global-none-all-co-pr-py-PartBadges-Oct1515-1"><img class='google-play' alt="Get it on Google Play" src="https://play.google.com/intl/en_us/badges/images/apps/en-play-badge.png" /></a></p>
<p>Without the app running, your location won't update. But you can also set your location to this device's geolocation by clicking the button below. </p>
<p><button id='manual-set' class='btn' style="display:block; margin:auto;" onclick="setLocation()"><i class="fa fa-map-marker"></i>&emsp;Update location manually</button></p>
</div>
<br>
<div class='container'>
<h2>Settings</h2>
<script src="/static/js/validator.min.js"></script>
<form id='settings-form' class='col-lg-10 col-lg-offset-1 form-horizontal' data-toggle="validator" role="form" method="post">
@ -130,11 +136,10 @@
{% 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>
</div>
</section>
{% include 'templates/footer.html' %}
<script src="https://cdn.socket.io/socket.io-1.2.0.js"></script>
<script>
var socket = io.connect();
@ -151,10 +156,11 @@
spd: (pos.coords.speed||0)
});
alert('Location updated! ');
location.reload();
}, function(err){
alert('ERROR: '+err);
}, { enableHighAccuracy:true });
}
} else { alert('Unable to set location. '); }
}
</script>
{% endblock %}

View File

@ -1,14 +1,10 @@
{% extends 'templates/base.html' %}
{% block title %}Tracman | {{ code }} Error{% endblock %}
{% block title %}{{ super() }} | {{ code }} Error{% endblock %}
{% block main %}
{% include 'templates/header.html' %}
<section class='dark'>
<div class='container'>
<img style="width:100%;" src="https://http.cat/{{ code }}.jpg" />
</div>
</section>
{% include 'templates/footer.html' %}
<section class='dark'>
<div class='container'>
<img style="width:100%;" src="https://http.cat/{{ code }}.jpg" />
</div>
</section>
{% endblock %}

View File

@ -1,15 +1,17 @@
{% extends 'templates/base.html' %}
{% block main %}
{% block head %}
{{ super() }}
<link href="/static/css/index.css" rel="stylesheet">
<script src="/static/js/index.js"></script>
{% endblock %}
{% include 'templates/header.html' %}
<section class='splash dark' id='splash' name='splash'>
{% block main %}
<script src="/static/js/index.js"></script>
<section class='splash dark' id='splash'>
<div class='container'>
<h1>Tracman</h1>
<h2>Let friends track your GPS location in realtime</h2>
<h3>Let friends track your GPS location in realtime</h3>
<a class='btn' href="#" data-scrollto="overview">More info<i class='fa fa-angle-down'></i></a>
{% if not user %}
<a class='btn' href="#" data-scrollto="get">Request invite<i class='fa fa-angle-down'></i></a>
@ -21,46 +23,46 @@
</div>
</section>
<section class='overview dark' id='overview' name='overview'>
<section class='overview dark' id='overview'>
<div class='container'>
<div>
<i class='fa fa-mobile'></i>
<h2>Easy-to-use</h2>
<h3>Easy-to-use</h3>
<p>Download the android app and log in. Then send your friends a link with a map showing your live location. </p>
</div>
<div>
<i class='fa fa-bolt'></i>
<h2>Realtime</h2>
<h3>Realtime</h3>
<p>Your location updates every second for all the world to see. </p>
</div>
<div>
<i class='fa fa-usd'></i>
<h2>Free</h2>
<h3>Free</h3>
<p>It's free, but you can <a href="https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=hypergeek14%40gmail%2ecom&lc=US&item_name=Tracman&currency_code=USD&bn=PP%2dDonationsBF%3abtn_donateCC_LG%2egif%3aNonHosted">donate</a> if you want to help with server expenses. </p>
</div>
</div>
</section>
<section class='feature app dark' id='app' name='app'>
<section class='feature app dark' id='app'>
<div class='container'>
<img src="/static/img/style/phone.png" alt="Mobile phone">
<div>
<h1>The App</h1>
<h2>The App</h2>
<p>Tracman uses an android app to recieve GPS location of your device. Sorry, there's no iPhone version yet. </p>
<ul>
<li>
<i class='fa fa-toggle-on'></i>
<h3>On/off switch</h3>
<h4>On/off switch</h4>
<p>If you need to go undercover, just turn tracman off with the flip of a switch. </p>
</li>
<li>
<i class='fa fa-cog'></i>
<h3>Settings</h3>
<h4>Settings</h4>
<p>Change your settings to show a less accurate location, if you want an air of mystery. </p>
</li>
<li>
<i class='fa fa-battery-3'></i>
<h3>Saves energy</h3>
<h4>Saves energy</h4>
<p>If nobody's tracking you, tracman won't needlessly drain your battery. </p>
</li>
</ul>
@ -68,26 +70,26 @@
</div>
</section>
<section class='feature tracpage dark' id='tracpage' name='tracpage'>
<section class='feature tracpage dark' id='tracpage'>
<div class='container'>
<img src="/static/img/style/laptop.png" alt="Laptop">
<div>
<h1>The Map</h1>
<h2>The Map</h2>
<p>You'll get a simple webpage with a map to send to friends. <a href="/trac/keith">Click here for a demo</a>. </p>
<ul>
<li>
<i class='fa fa-hand-o-right'></i>
<h3>Easy</h3>
<h4>Easy</h4>
<p>Just send a link to whomever you want. Bam, now they know exactly where you are. </p>
</li>
<li>
<i class='fa fa-map-marker'></i>
<h3>Precise</h3>
<h4>Precise</h4>
<p>Map updates in realtime using the fancy-pants websockets protocol. </p>
</li>
<li>
<i class='fa fa-cogs'></i>
<h3>Customizable</h3>
<h4>Customizable</h4>
<p>You can change some things. Not a lot yet, but I am always adding features. </p>
</li>
</ul>
@ -95,10 +97,10 @@
</div>
</section>
<section class='disclaimer light' id='disclaimer' name='disclaimer'>
<section class='disclaimer light' id='disclaimer'>
<div class='container'>
<h1>Warning! </h1>
<h2>I assume no responsibility for anything whatsoever. </h2>
<h2>Warning! </h2>
<h3>I assume no responsibility for anything whatsoever. </h3>
<p>If you haven't realized it already, there are a lot of reasons why publishing your location online could be a bad idea. </p>
<ul>
<li>You get caught cheating</li>
@ -111,14 +113,14 @@
</section>
{% if not user %}
<section class='get light' id='get' name='get'>
<section class='get light' id='get'>
<div class='container'>
<h1>Hook me up!</h1>
<h2>Right now, Tracman is invite-only. You can beg me for access here. </h2>
<form id='invite-form' role="form" method="post">
<h2>Hook me up!</h2>
<h3>Right now, Tracman is invite-only. You can beg me for access here. </h3>
<form id='invite-form' method="post">
<label class='input'><span>Name</span><input type="text" name="name" required></label>
<label class='input'><span>Email address</span><input type="email" name="email" required></label>
<label class='message'><span>Why you deserve beta access</span><textarea id='why' name="why" required></textarea></label>
<label class='message'><span>Why you deserve beta access (optional)</span><textarea id='why' name="why"></textarea></label>
<label class='checkbox'><input type="checkbox" name="disclaimer" required><span>I've read the <a href="#" data-scrollto="disclaimer">scary warning</a>. </span></label>
<label class='submit'>
{% if inviteSuccess.length > 0 %}
@ -133,7 +135,5 @@
</div>
</section>
{% endif %}
{% include 'templates/footer.html' %}
{% endblock %}

View File

@ -1,33 +1,31 @@
{% extends 'templates/base.html' %}
{% block title %}Tracman | License{% endblock %}
{% block title %}{{ super() }} | License{% endblock %}
{% block main %}
{% include 'templates/header.html' %}
<section class='dark'>
<div class='container'>
<h2>The MIT License (MIT)</h2>
<h3>Copyright &copy; 2016 Keith Irwin</h3>
<section class='dark'>
<div class='container'>
<h2>The MIT License (MIT)</h2>
<h3>Copyright &copy; 2016 Keith Irwin</h3>
<p>Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions: </p>
<p>Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions: </p>
<p>The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software. </p>
<p>The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software. </p>
<p>THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE. </p>
</div>
</section>
{% include 'templates/footer.html' %}
<p>THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE. </p>
</div>
</section>
{% endblock %}

View File

@ -1,46 +1,43 @@
{% extends 'templates/base.html' %}
{% block title %}Tracman | Pro{% endblock %}
{% block title %}{{ super() }} | Pro{% endblock %}
{% block main %}
{% include 'templates/header.html' %}
<section class='dark'>
<div class='container'>
<h1>Tracman Pro</h1>
<h3>A word from the developer</h3>
<section class='dark'>
<div class='container'>
<h1>Tracman Pro</h1>
<h3>A word from the developer</h3>
<p>Hi Folks, </p>
<p>Hi Folks, </p>
<p>Glad you're enjoying my website and app. I made the whole thing, from front to backend,
and I'm really proud of it! However, I'm a long-haul trucker by day and coding is just a hobby.
I don't make any money off this website, and I pay the server fees out of my own pocket. Do you
pity me enough to donate some money by <a href="https://www.paypal.com/us/cgi-bin/webscr?cmd=_flow&SESSION=56toCNZRvXj-_J6kC_5D258zMwjyU7hLvxKFQXsIG5_nzVlAhEw2VLFf7K0&dispatch=5885d80a13c0db1f8e263663d3faee8defcd6970d4fd9d661117ac2649af92bb">paypal</a>
or <a href="bitcoin:1GXbuM398Y2tYwSaQhNQHXWF1AN6GeRgQh?label=tracman">bitcoin</a>? </p>
<p>Glad you're enjoying my website and app. I made the whole thing, from front to backend,
and I'm really proud of it! However, I'm a long-haul trucker by day and coding is just a hobby.
I don't make any money off this website, and I pay the server fees out of my own pocket. Do you
pity me enough to donate some money by <a href="https://www.paypal.com/us/cgi-bin/webscr?cmd=_flow&SESSION=56toCNZRvXj-_J6kC_5D258zMwjyU7hLvxKFQXsIG5_nzVlAhEw2VLFf7K0&dispatch=5885d80a13c0db1f8e263663d3faee8defcd6970d4fd9d661117ac2649af92bb">paypal</a>
or <a href="bitcoin:1GXbuM398Y2tYwSaQhNQHXWF1AN6GeRgQh?label=tracman">bitcoin</a>? </p>
<p>To make a little money off this service, I'm going to be offering a pro version with more
features. It'll be cheap, probably $1 or $2 per month. However, while Tracman is in beta,
you can beta test the pro version too. Be sure to inform me about any <a href="/bug">bugs</a>
you encounter or <a href="/suggestion">suggestions</a> you have. And keep in mind that at some
point, when we launch out of beta, Tracman Pro will <em>not</em> be free and <strong>you will
lose your pro membership</strong> unless start paying for it.
<p>To make a little money off this service, I'm going to be offering a pro version with more
features. It'll be cheap, probably $1 or $2 per month. However, while Tracman is in beta,
you can beta test the pro version too. Be sure to inform me about any <a href="/bug">bugs</a>
you encounter or <a href="/suggestion">suggestions</a> you have. And keep in mind that at some
point, when we launch out of beta, Tracman Pro will <em>not</em> be free and <strong>you will
lose your pro membership</strong> unless start paying for it.
<p>That said, just click the button below to test out the pro features. Keep in mind, they are
as <a href="/#disclaimer">unstable</a> as the rest of this product.
<p>That said, just click the button below to test out the pro features. Keep in mind, they are
as <a href="/#disclaimer">unstable</a> as the rest of this product.
<p>Cheers, <br>
<a href="https://keithirwin.us/">Keith Irwin</a></p>
<p>Cheers, <br>
<a href="https://keithirwin.us/">Keith Irwin</a></p>
<form class='row flexbox' action="#" method="POST">
{% if user.isPro %}
<div class='alert alert-success'><i class="fa fa-check-circle"></i> You are already pro! </div>
{% else %}
<button type="submit" class='btn yellow'>GO PRO</button>
{% endif %}
<a class='btn' href="/dashboard">go home</a>
</form>
<form class='row flexbox' action="" method="POST">
{% if user.isPro %}
<div class='alert alert-success'><i class="fa fa-check-circle"></i> You are already pro! </div>
{% else %}
<button type="submit" class='btn yellow'>GO PRO</button>
{% endif %}
<a class='btn' href="/dashboard">go home</a>
</form>
</div>
</section>
{% include 'templates/footer.html' %}
</div>
</section>
{% endblock %}

View File

@ -1,52 +1,48 @@
{% extends 'templates/base.html' %}
{% block title %}Tracman | Suggestion{% endblock %}
{% block title %}{{ super() }} | Suggestion{% endblock %}
{% block main %}
{% include 'templates/header.html' %}
<section class='dark'>
<div class='container'>
<h1>Suggest a Feature</h1>
<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>
<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">
<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 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 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 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 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>
{% include 'templates/footer.html' %}
</div>
</section>
{% endblock %}

View File

@ -1,6 +1,7 @@
<!DOCTYPE html>
<html>
<head>
{% block head %}
<title>{% block title %}Tracman{% endblock %}</title>
<meta http-equiv="Content-type" content="text/html; charset=utf-8">
@ -13,7 +14,7 @@
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
<link rel="shortcut icon" sizes="16x16 & 32x32 & 48x48" type="image/x-icon" href="/static/img/icon/by/16-32-48.ico">
<link rel="shortcut icon" sizes="16x16 32x32 48x48" type="image/x-icon" href="/static/img/icon/by/16-32-48.ico">
<link rel="icon apple-touch-icon" sizes="32x32" type="image/png" href="/static/img/icon/by/32.png">
<link rel="icon apple-touch-icon" sizes="57x57" type="image/png" href="/static/img/icon/by/57.png">
<link rel="icon apple-touch-icon" sizes="72x72" type="image/png" href="/static/img/icon/by/72.png">
@ -30,6 +31,9 @@
<script src="https://code.jquery.com/jquery-1.11.3.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/js/bootstrap.min.js" integrity="sha384-0mSbJDEHialfmuBBQP6A4Qrprq5OVfW37PRR3j5ELqxss1yVqOtnepnHVP9aJ7xS" crossorigin="anonymous"></script>
{% endblock %}
{% if not noHeader %}<link href="/static/css/header.css" rel="stylesheet">{% endif %}
{% if not noFooter %}<link href="/static/css/footer.css" rel="stylesheet">{% endif %}
</head>
<body>
@ -39,8 +43,10 @@
<a href="#" class='close' data-dismiss="alert" aria-label="close"><i class='fa fa-times'></i></a>
</div>
</noscript>
{% if not noHeader %}{% include 'templates/header.html' %}{% endif %}
{% block main %}Loading... {% endblock %}
{% if not noFooter %}{% include 'templates/footer.html' %}{% endif %}
<script>
(function(t,r,a,c,m,o,n){t['GoogleAnalyticsObject']=m;t[m]=t[m]||function(){

View File

@ -1,17 +1,16 @@
<link href="/static/css/footer.css" rel="stylesheet">
<footer class='footer'>
<div class='left'>
<p>Website and app by <a href="https://keithirwin.us/">Keith Irwin</a>.
<br>Design by <a href="http://boag.online/blog/maglev-free-responsive-website-template" target="_blank">Fraser Boag</a>. </p>
<br>Design by <a href="http://boag.online/blog/maglev-free-responsive-website-template">Fraser Boag</a>. </p>
</div>
<div class='right'>
Share:
<a href="https://twitter.com/home?status=Show%20your%20location%20to%20friends%20in%20realtime%20at%20http://tracman.org/" target="_blank"><i class="fa fa-twitter"></i></a>
<a href="https://www.facebook.com/sharer/sharer.php?u=http://tracman.org/" target="_blank"><i class="fa fa-facebook"></i></a>
<a href="https://www.reddit.com/submit?title=Show%20your%20location%20to%20friends%20in%20realtime%20at%20&url=http://tracman.org/" target="_blank"><i class="fa fa-reddit-alien"></i></a>
<br>Donate:
<a href="https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=hypergeek14%40gmail%2ecom&lc=US&item_name=Tracman&currency_code=USD&bn=PP%2dDonationsBF%3abtn_donateCC_LG%2egif%3aNonHosted"><i class="fa fa-paypal"></i></a>
<a href="https://www.facebook.com/sharer/sharer.php?u=https://tracman.org/" target="_blank"><i class="fa fa-facebook"></i></a>
<a href="https://twitter.com/home?status=Show%20your%20location%20to%20friends%20in%20realtime%20at%20https://tracman.org/" target="_blank"><i class="fa fa-twitter"></i></a>
<a href="https://www.reddit.com/submit?title=Show%20your%20location%20to%20friends%20in%20realtime%20at%20&url=https://tracman.org/" target="_blank"><i class="fa fa-reddit-alien"></i></a>
<br>Contribute:
<a href="https://github.com/Tracman-org/Server"><i class="fa fa-github"></i></a>
<a href="https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=hypergeek14%40gmail%2ecom&lc=US&item_name=Tracman&currency_code=USD&bn=PP%2dDonationsBF%3abtn_donateCC_LG%2egif%3aNonHosted" target="_blank"><i class="fa fa-paypal"></i></a>
<a href="bitcoin:1GXbuM398Y2tYwSaQhNQHXWF1AN6GeRgQh?label=tracman"><i class="fa fa-btc"></i></a>
</div>
</footer>

View File

@ -1,8 +1,7 @@
<link href="/static/css/header.css" rel="stylesheet">
<script src="/static/js/header.js"></script>
<header>
<a href="/"><h1 class='logo'><img src="/static/img/style/logo-28.png" class='icon'>Tracman</h1></a>
<a href="/"><span class='logo'><img class='icon' src="/static/img/style/logo-28.png" alt="+">Tracman</span></a>
<div class='hamburger hamburger--slider' aria-label="Menu" aria-controls="navigation">
<div class='hamburger-box'>
<div class='hamburger-inner'></div>

View File

@ -1,51 +1,63 @@
{% extends 'templates/base.html' %}
{% block title %}Tracman | {{ tracuser.name }}{% endblock %}
{% block title %}{{ super() }} | {{ tracuser.name }}{% endblock %}
{% block main %}
<link href="/static/css/trac.css" rel="stylesheet">
{% block head %}
{{ super() }}
<link href="/static/css/trac.css" rel="stylesheet">
<style>
.wrap { top:{% if not noHeader %}58{% else %}0{% endif %}px;}
{% if tracuser.settings.showStreetview %}
#map, #pano {display:inline-block;}
img#panoImg { width:100%; height:100%; }
{% if tracuser.settings.showStreetview and disp!='0' and disp!='1' %}
/* show both */
@media (orientation: landscape) {
#map, #pano {
width:50%;
height:99%;
#map, #pano {
display:inline-block;
width:50%;
height:99%;
}
#pano { float:right; }
}
#pano {float:right;}
}
@media (orientation: portrait) {
#map, #pano {
@media (orientation: portrait) {
#map, #pano {
width:100%;
height:50%;
}
#pano { bottom:0; }
}
{% elif tracuser.settings.showStreetview and disp=='1' %}
/* show streetview */
#pano {
width:100%;
height:50%;
}
#pano {bottom:0}
}
height:100%;}
#map {display:none;}
{% else %}
#map {
width:100%;
height:100%;}
#pano {display:none;}
/* show map */
#map {
width:100%;
height:100%;}
#pano {display:none;}
{% endif %}
</style>
{% endblock %}
{% if not noHeader %}
{% include 'templates/header.html' %}
{% endif %}
{% block main %}
<div class='wrap'>
{% if not tracuser.last.time %}
<div class='centered alert alert-warning'>
<strong>No Location Found</strong>
<br>This user hasn't updated their location yet!
<br>If this is your page, maybe you want to <a href="/android">download the app</a>.
<b>No Location Found</b>
{% if user.id == tracuser.id %}
<br>You can <a href="#" onclick="setLocation()">click here to set use this device's location</a>.
<br>Maybe you also want to <a href="/android">download the android app</a>.
{% else %}
<br>This user hasn't updated their location yet!
{% endif %}
</div>
{% else %}
<div id='map'><i class='loading fa fa-refresh fa-spin'></i></div>
{% if tracuser.settings.showStreetview %}
<div id='pano'><i class='loading fa fa-refresh fa-spin'></i></div>
{% if tracuser.settings.showStreetview and not noStreetview.length %}
<div id='pano'><img id='panoImg' src="https://maps.googleapis.com/maps/api/streetview?size=800x800&location={{ tracuser.last.lat }},{{ tracuser.last.lon }}&fov=90&heading={{ tracuser.last.dir|default(0) }}&key={{ api }}" alt="Street view image"></div>
{% endif %}
{% endif %}
@ -58,7 +70,25 @@
var tracuserid = {{ tracuser._id | dump | safe }},
settings = JSON.parse('{{ tracuser.settings | dump | safe }}'),
last = JSON.parse('{{ tracuser.last | dump | safe }}'),
noHeader = '{{ noHeader | dump | safe }}';
noHeader = {{ noHeader | dump | safe }},
disp = {{ disp | dump | safe }};
// Set location manually
function setLocation() {
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(function(pos){
socket.emit('app', {
usr: '{{ user.id }}',
lat: pos.coords.latitude,
lon: pos.coords.longitude,
spd: (pos.coords.speed||0)
});
alert('Location updated! ');
}, function(err){
alert('ERROR: '+err);
}, { enableHighAccuracy:true });
} else { alert('Unable to set location. '); }
}
var getAltitude = function(location, elevator, cb){
elevator = elevator || new google.maps.ElevationService;
@ -71,140 +101,119 @@
});
}
var map, marker, pano, dir, lat, lon, spd, alt, newLocation, elevator;
var map, marker, elevator;
function initMap() {
map = new google.maps.Map(document.getElementById('map'),{
zoom: settings.defaultZoom,
streetViewControl: false,
zoomControlOptions: {position: google.maps.ControlPosition.LEFT_TOP},
mapTypeId: (settings.defaultMap=='road')?google.maps.MapTypeId.ROADMAP:google.maps.MapTypeId.HYBRID
});
marker = new google.maps.Marker({
map: map,
draggable: false
});
if (settings.showStreetview) {
pano = new google.maps.StreetViewPanorama( document.getElementById('pano'), {
// Create map
if (disp!='1' || !settings.showStreetview) {
map = new google.maps.Map( document.getElementById('map'), {
center: new google.maps.LatLng( last.lat, last.lon ),
panControl: false,
zoomControl: false,
addressControl: false,
linksControl: false
draggable: false,
zoom: settings.defaultZoom,
streetViewControl: false,
zoomControlOptions: {position: google.maps.ControlPosition.LEFT_TOP},
mapTypeId: (settings.defaultMap=='road')?google.maps.MapTypeId.ROADMAP:google.maps.MapTypeId.HYBRID
});
marker = new google.maps.Marker({
position: { lat:last.lat, lng:last.lon },
title: {{ tracuser.name | dump | safe }},
map: map,
draggable: false
});
// Create iFrame logo
if (noHeader.length) {
var logoDiv = document.createElement('div');
logoDiv.className = 'map-logo';
logoDiv.innerHTML = '<a href="https://tracman.org/">'+
'<img src="https://tracman.org/static/img/style/logo-28.png" alt="[]">'+
'Tracman</a>';
map.controls[google.maps.ControlPosition.BOTTOM_LEFT].push(logoDiv);
}
// Create update time block
var timeDiv = document.createElement('div');
timeDiv.className = 'tim';
if (last.time) {
timeDiv.innerHTML = 'location updated '+new Date(last.time).toLocaleString();
}
map.controls[google.maps.ControlPosition.RIGHT_BOTTOM].push(timeDiv);
// Create speed block
if (settings.showSpeed) {
var speedSign = document.createElement('div'),
speedLabel = document.createElement('div'),
speedText = document.createElement('div'),
speedUnit = document.createElement('div');
speedLabel.className = 'spd-label';
speedText.className = 'spd';
speedUnit.className = 'spd-unit';
speedSign.className = 'spd-sign';
speedText.innerHTML = (settings.units=='imperial')?(parseFloat(last.spd)*2.23694).toFixed():last.spd.toFixed();
speedLabel.innerHTML = 'SPEED';
speedUnit.innerHTML = (settings.units=='imperial')?'m.p.h.':'k.p.h.';
speedSign.appendChild(speedLabel);
speedSign.appendChild(speedText);
speedSign.appendChild(speedUnit);
map.controls[google.maps.ControlPosition.TOP_RIGHT].push(speedSign);
}
// Create altitude block
if (settings.showAlt) {
var elevator = new google.maps.ElevationService;
var altitudeSign = document.createElement('div'),
altitudeLabel = document.createElement('div'),
altitudeText = document.createElement('div'),
altitudeUnit = document.createElement('div');
altitudeLabel.className = 'alt-label';
altitudeText.className = 'alt';
altitudeUnit.className = 'alt-unit';
altitudeSign.className = 'alt-sign';
altitudeText.innerHTML = '';
altitudeLabel.innerHTML = 'ALTITUDE';
getAltitude(new google.maps.LatLng(last.lat,last.lon), elevator, function(alt) {
if (alt) { altitudeText.innerHTML = (settings.units=='imperial')?(alt*3.28084).toFixed():alt.toFixed(); }
});
altitudeUnit.innerHTML = (settings.units=='imperial')?'feet above sea level':'meters above sea level';
altitudeSign.appendChild(altitudeLabel);
altitudeSign.appendChild(altitudeText);
altitudeSign.appendChild(altitudeUnit);
map.controls[google.maps.ControlPosition.TOP_RIGHT].push(altitudeSign);
}
}
// Create iFrame logo
if (noHeader) {
var logoDiv = document.createElement('div');
logoDiv.className = 'map-logo';
logoDiv.innerHTML = '<a href="https://tracman.org/">'+
'<img src="https://tracman.org/static/img/style/logo-28.png" alt="[]">'+
'Tracman</a>';
map.controls[google.maps.ControlPosition.BOTTOM_LEFT].push(logoDiv);
}
// Create update time block
var timeDiv = document.createElement('div');
timeDiv.className = 'tim';
if (last.time) {
timeDiv.innerHTML = 'location updated '+new Date(last.time).toLocaleString();
}
map.controls[google.maps.ControlPosition.RIGHT_BOTTOM].push(timeDiv);
// Create speed block
if (settings.showSpeed) {
var speedSign = document.createElement('div'),
speedLabel = document.createElement('div'),
speedText = document.createElement('div'),
speedUnit = document.createElement('div');
speedLabel.className = 'spd-label';
speedText.className = 'spd';
speedUnit.className = 'spd-unit';
speedSign.className = 'spd-sign';
speedText.innerHTML = '';
speedLabel.innerHTML = 'SPEED';
if (last.spd) {
speedText.innerHTML = (settings.units=='imperial')?
(parseFloat(last.spd)*2.23694).toFixed():last.spd;
// Create streetview
if (settings.showStreetview && disp!='0') {
document.getElementById('panoImg').src='https://maps.googleapis.com/maps/api/streetview?size='+$('#pano').outerWidth()+'x'+$('#pano').outerHeight()+'&location='+last.lat+','+last.lon+'&fov=90&heading='+(last.dir||0)+'&key={{ api }}';
}
if (settings.units=='imperial') {
speedUnit.innerHTML = 'm.p.h.';
} else {
speedUnit.innerHTML = 'k.p.h.';}
speedSign.appendChild(speedLabel);
speedSign.appendChild(speedText);
speedSign.appendChild(speedUnit);
map.controls[google.maps.ControlPosition.TOP_RIGHT].push(speedSign);
}
// Create altitude block
if (settings.showAlt) {
elevator = new google.maps.ElevationService;
var altitudeSign = document.createElement('div'),
altitudeLabel = document.createElement('div'),
altitudeText = document.createElement('div'),
altitudeUnit = document.createElement('div');
altitudeLabel.className = 'alt-label';
altitudeText.className = 'alt';
altitudeUnit.className = 'alt-unit';
altitudeSign.className = 'alt-sign';
altitudeText.innerHTML = '';
altitudeLabel.innerHTML = 'ALTITUDE';
if (last.lon && settings.showAlt) {
newLocation = new google.maps.LatLng(last.lat, last.lon);
getAltitude(newLocation, elevator, function(alt) {
if (alt) {
alt = (settings.units=='imperial')?alt*3.28084:alt;
altitudeText.innerHTML = alt.toFixed();
}
});
}
if (settings.units=='imperial') {
altitudeUnit.innerHTML = 'feet above sea level';
} else {
altitudeUnit.innerHTML = 'meters above sea level';}
altitudeSign.appendChild(altitudeLabel);
altitudeSign.appendChild(altitudeText);
altitudeSign.appendChild(altitudeUnit);
map.controls[google.maps.ControlPosition.TOP_RIGHT].push(altitudeSign);
}
}
// Sockets
socket.on('connect', function(){
socket.emit('room', tracuserid);
});
var dir, lat, lon, spd, alt, newLocation;
socket.on('trac', function(loc){
spd = (settings.units=='imperial')?parseFloat(loc.spd)*2.23694:parseFloat(loc.spd);
dir = parseFloat(loc.dir);
lat = parseFloat(loc.lat);
lon = parseFloat(loc.lon);
newLocation = new google.maps.LatLng(loc.lat, loc.lon);
$('.tim').text('location updated '+new Date(loc.time).toLocaleString());
if (settings.showSpeed) {
$('.spd').text(spd.toFixed());
}
if (settings.showAlt) {
getAltitude(newLocation, elevator, function(alt) {
if (alt) {
alt = (settings.units=='imperial')?alt*3.28084:alt;
$('.alt').text(alt.toFixed());
}
});
}
map.setCenter(newLocation);
marker.setPosition(newLocation);
if (settings.showStreetview) {
if (pano.position != newLocation) {
pano.setPosition(newLocation);
if (spd>0) {
pano.setPov({pitch:0,heading:dir});
}
newLocation = new google.maps.LatLng(loc.lat,loc.lon)
if (disp!='1' || !settings.showStreetview) {
$('.tim').text('location updated '+new Date(loc.time).toLocaleString());
if (settings.showSpeed) { $('.spd').text(spd.toFixed()); }
if (settings.showAlt) {
getAltitude(newLocation, elevator, function(alt) {
if (alt) { $('.alt').text((settings.units=='imperial')?(alt*3.28084).toFixed():alt.toFixed()); }
});
}
map.setCenter(newLocation);
marker.setPosition(newLocation);
}
if (settings.showStreetview && disp!='0') {
document.getElementById('panoImg').src='https://maps.googleapis.com/maps/api/streetview?size='+$('#pano').width()+'x'+$('#pano').height()+'&location='+loc.lat+','+loc.lon+'&fov=90&heading='+dir+'&key={{ api }}';
}
});
</script>
{% endblock %}