Added accounts to admin

master
Keith Irwin 2016-08-10 05:51:49 +00:00
parent 3a00dc8372
commit 80d1ec7b6c
No known key found for this signature in database
GPG Key ID: 77A9E9D5A51A7431
17 changed files with 177 additions and 384 deletions

View File

@ -16,6 +16,10 @@ $ npm start
## Changelog
#### v0.4.1
*
#### v0.4.0
* Opened registration

View File

@ -1,4 +1,5 @@
var passport = require('passport'),
slug = require('slug'),
crypto = require('crypto'),
secret = require('./secrets.js'),
User = require('./models/user.js'),
@ -29,11 +30,21 @@ passport.use(new GoogleStrategy({
// User not found
else /* create user */ {
var user, successMessage, failMessage, cbc=2;
var user = new User();
user.googleID = profile.id;
user.email = profile.emails[0];
user.lastLogin = Date.now();
// Get slug
user.name = profile.displayName;
user.email = profile.emails[0].value;
user.slug = slug(profile.displayName).toLowerCase();
user.created = Date.now();
user.lastLogin = Date.now();
// user.settings = { units:'standard', defaultMap:'road', defaultZoom:11, showSpeed:false, showTemp:false, showAlt:false, showStreetview:false },
// user.last = { lat:0, lon:0, dir:0, alt:0, spd:0 },
// user.isPro = false;
// user.isAdmin = false;
var cbc = 2;
var successMessage, failMessage
// Generate slug
(function checkSlug(s,cb) {
//console.log('checking ',s);
User.findOne({slug:s}, function(err, existingUser){
@ -46,12 +57,13 @@ passport.use(new GoogleStrategy({
checkSlug(s,cb);
} else { cb(s); }
});
})(slug(profile.name).toLowerCase(), function(newSlug){
})(user.slug, function(newSlug){
user.slug = newSlug;
if (cbc>1) /* waiting on other calls */ { cbc--; }
else { done(null, user, { success:successMessage, failure:failMessage }); }
});
// Get sk32
// Generate sk32
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');}
@ -59,14 +71,15 @@ passport.use(new GoogleStrategy({
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>?';
console.log('Error saving new user '+err);
var failMessage = 'Something went wrong creating your account. 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>. ' }
if (cbc>1) /* waiting on other calls */ { cbc--; }
else { done(null, user, { success:successMessage, failure:failMessage }); }
});
}
});
}
});

View File

@ -1,24 +0,0 @@
<html>
<head>
<style>
.invite { text-align:center; }
img { float:left;
padding:5px;
margin-right: 5px; }
h1 { font-size:48px; }
p { font-family:sans-serif; }
</style>
</head>
<body>
<img src="https://tracman.org/static/img/icon/by/48.png"><h1>Tracman</h1>
<p>Dear {{name}}, </p>
<p>After carefully reviewing your credentials over a glass of malt liquor, it has been determined that you are qualified to use <a href="https://tracman.org/">Tracman</a> during the super-exclusive, invite-only beta stage. </p>
<p>Feel free to use this link to create an account.&ensp;Note that you will need a google account to continue.&ensp;You will also need an android phone to update your location.&ensp;</p>
<p class='invite'><a href="https://tracman.org/invited/{{id}}">http://tracman.org/invited/{{id}}</a></p>
<p>You will be asked to sign into google and authorize the Tracman app.&ensp;</p>
<p>Please keep in mind that this is experimental software, and I am not responsible for it actually working properly, or anything else for that matter.&ensp;You have read the <a href="https://tracman.org/#disclaimer">disclaimer</a>, haven't you?&ensp;</p>
<p>Regards,
<br>Keith</p>
</body>
</html>

View File

@ -1,14 +0,0 @@
Dear {{name}},
After carefully reviewing your credentials over a glass of malt liquor, it has been determined that you are qualified to use Tracman (http://tracman.org/) during the super-exclusive, invite-only beta stage.&ensp;
Feel free to use this link to create an account.&ensp;Note that you will need a google account to continue.&ensp;You will also need an android phone to update your location.&ensp;
https://tracman.org/invited/{{id}}
You will be asked to sign into google and authorize the Tracman app.
Please keep in mind that this is experimental software, and I am not responsible for it actually working properly, or anything else for that matter.&ensp;
Regards,
Keith

View File

@ -21,11 +21,11 @@ module.exports = mongoose.model('User', {
},
last: {
time: Date,
lat: Number,
lon: Number,
dir: Number,
alt: Number,
spd: Number
lat: {type:Number, default:0},
lon: {type:Number, default:0},
dir: {type:Number, default:0},
alt: {type:Number, default:0},
spd: {type:Number, default:0}
},
sk32: {type:String, required:true, unique:true}
});

View File

@ -40,41 +40,9 @@ router.route('/')
});
router.route('/requests')
.all(mw.ensureAdmin, function(req,res,next){
if (err) {
req.flash('error',err);
req.flash('error-message',err);
}
}).post(function(req,res){
if (req.body.invite) {
Request.findById(req.body.invite, function(err,request){
if (err){ req.flash('error', err.message); }
mail.sendInvite(request, function (err, raw) {
if (err) { req.flash('error', err.message); }
request.granted = Date.now();
request.save(function(err) {
if (err) { req.flash('error', err.message); }
});
req.flash('success', 'Invitation sent to <i>'+request.name+'</i>.');
res.redirect('/admin#requests');
});
});
} else if (req.body.delete) {
Request.findOneAndRemove({'_id':req.body.delete}, function(err,request){
if (err){ req.flash('error', err.message); }
else { req.flash('success', 'Request deleted.'); }
res.redirect('/admin#requests');
});
} else { console.log('ERROR! POST without action sent. '); next(); }
});
router.route('/users')
.all(mw.ensureAdmin, function(req,res,next){
if (err) {
req.flash('error',err);
req.flash('error-message',err);
}
next();
}).post(function(req,res){
if (req.body.delete) {
User.findOneAndRemove({'_id':req.body.delete}, function(err,user){

View File

@ -5,7 +5,7 @@ router.get('/login', function(req,res){
res.redirect('/auth/google');
});
router.get('/logout', function(req,res){
req.logout();
req.logout(); // Needs to clear cookies?
res.redirect('/');
});

View File

@ -9,7 +9,7 @@ router.route('/')
.get(function(req,res,next){
// Logged in
if (req.session.passport) {
if (req.session.passport&&req.session.passport.user) {
// Get user
User.findById(req.session.passport.user, function(err, user){
if (err){ mw.throwErr(req,err); }
@ -32,9 +32,7 @@ router.route('/')
else {
res.render('index.html', {
error: req.flash('error')[0],
success: req.flash('success')[0],
inviteSuccess: req.flash('request-success')[0],
inviteError: req.flash('request-error')[0]
success: req.flash('success')[0]
});
}

View File

@ -6,8 +6,7 @@ var router = require('express').Router(),
router.get('/robots.txt', function(req,res){
res.type('text/plain');
res.send("User-agent: *\n"+
"Disallow: /map\n"+
"Disallow: /invited"
"Disallow: /map\n"
);
});

View File

@ -1,6 +1,6 @@
{
"name": "tracman",
"version": "0.4.0",
"version": "0.4.1",
"description": "Tracks user's GPS location",
"main": "server.js",
"dependencies": {
@ -27,11 +27,17 @@
"devDependencies": {
"chai": "^3.5.0",
"chai-http": "^2.0.1",
"karma": "^1.1.0",
"karma-chai": "^0.1.0",
"karma-chrome-launcher": "^1.0.1",
"karma-firefox-launcher": "^1.0.0",
"karma-mocha": "^1.1.1",
"mocha": "^2.5.3",
"supertest": "^1.2.0"
},
"scripts": {
"test": "mocha test.js",
"karma": "./node_modules/karma/bin/karma start ./karma.conf.js",
"start": "node server.js"
},
"repository": {

124
test.js
View File

@ -2,10 +2,12 @@ var chai = require('chai'),
chaiHttp = require('chai-http'),
request = require('supertest'),
server = require('./server'),
should = chai.should();
should = chai.should(),
expect = chai.expect();
chai.use(chaiHttp);
describe('Index', function() {
// I think this restarts the server after each try?
// var server;
// beforeEach(function() {
// server = require('./server');
@ -27,65 +29,121 @@ describe('Index', function() {
.end(function(err,res){ done(); });
});
it('Displays example map', function(done){
it('Displays demo map', function(done){
request(server).get('/map/keith')
.expect(200)
.end(function(err,res){ done(); });
});
// it('Can\'t set location on example map', function(done){
// //TODO: Check websocketssecurity
// done();
// });
it('Sends invite request', function(done){
request(server).post('/')
.send({
"name":"Mocha Test",
"email":"mocha@example.com",
"why":"Because I really really want it. "
})
.expect(200)
.end(function(err, res) {
if (err){ done(err); }
else { done(); }
});
});
});
describe('Auth', function() {
//TODO: it 'Gets invited, creates an account'
it('Creates an account', function(done){
request(server).get('/login')
.expect(200)
.end(function(err,res){
//TODO: google authentication
it('Logs out', function(done){
request(server).get('/logout')
.expect(200)
.end(function(err,res){
it('Logs in', function(done){
request(server).get('/logout')
.expect(200)
.end(function(err,res){
cbc=2;
var deletesAccount = function(done){
it('Deletes own account', function(){
//TODO: Delete account via GUI
});
}
it('Shows own map', function(done){
request(server).get('/map')
.expect(200)
//TODO: Expect no js errors
.end(function(err,res){
if (cbc<2){ deletesAccount(); }
else { cbc--; }
done();
});
});
it('Has the correct account info', function(done){
//TODO: Check account info
if (cbc<2){ deletesAccount(); }
else { cbc--; }
done();
});
done();
});
});
done();
});
});
done();
});
});
//TODO: it 'Logs out'
//TODO: it('Has the correct account info', function(done){
// });
//TODO: it 'Logs in'
//TODO: it('Logs out', function(done){
// });
//TODO: it 'Shows own map'
//TODO: it('Logs in', function(done){
// });
//TODO: it('Shows own map', function(done){
// });
//TODO: it('Deletes account', function(done){
// });
});
describe('Map controls', function() {
//TODO: it 'Sets location'
//TODO: it('Sets location', function(done){
// });
//TODO: it 'Clears location'
//TODO: it('Clears location', function(done){
// });
//TODO: it 'Starts tracking'
//TODO: it('Starts tracking', function(done){
// });
//TODO: it 'Stops tracking'
//TODO: it('Stops tracking', function(done){
// });
});
describe('Map popups', function() {
//TODO: it 'Opens Share popup'
//TODO: it('Opens Share popup', function(done){
// });
//TODO: it 'Closes Share popup'
//TODO: it('Closes Share popup', function(done){
// });
//TODO: it 'Opens Settings popup'
//TODO: it('Opens Settings popup', function(done){
// });
//TODO: it 'Closes Settings popup'
//TODO: it('Closes Settings popup', function(done){
// });
});

View File

@ -3,7 +3,7 @@
{% block head %}
{{ super() }}
<link rel="stylesheet" type="text/css" href="/static/js/jquery-ui-tabs/jquery-ui.min.css">
<!--<link rel="stylesheet" type="text/css" href="/static/js/jquery-ui-tabs/jquery-ui.min.css">-->
<style>
.container { max-width:90%; }
</style>
@ -12,11 +12,6 @@
{% block main %}
<section class='dark'>
<div class='container' id='tabs'>
<ul class='nav nav-tabs'>
<!--TODO: Why is bootstrap not formatting .nav-tabs -->
<li><a href="#users">Users</a></li>
<li><a href="#requests">Requests</a></li>
</ul>
<div id='users'>
<h1>Users</h1>
@ -27,6 +22,7 @@
<th>Joined</th>
<th>Last login</th>
<th>Moved</th>
<th>Accounts</th>
<th>Edit</th>
</tr></thead>
<tbody>
@ -37,7 +33,12 @@
<td id='{{usr.id}}-created'></td>
<td id='{{usr.id}}-logged'></td>
<td id='{{usr.id}}-moved'></td>
<td id='{{usr.id}}-edit'><form action="/users" method="POST">
<td id='{{usr.id}}-accounts'>
{% if usr.googleID %}
<a href="https://plus.google.com/{{usr.googleID}}/">Google</a>
{% endif %}
</td>
<td id='{{usr.id}}-edit'><form action="/admin/users" method="POST">
<button type="submit" class='btn btn-block btn-danger' name="delete" value="{{usr.id}}">DELETE</button>
</form></td>
</tr>
@ -46,85 +47,46 @@
</table>
</div>
<div id='requests'>
<h1>Requests</h1>
<table id='requests-table' class='table table-hover'>
<thead><tr>
<th>Name</th>
<th>Email</th>
<th>Message</th>
<th>Requested</th>
<th>Invited</th>
<th>User</th>
</tr></thead>
<tbody>
{% for request in requests %}
<tr class="table-{% if request.userId %}success{% elif request.granted %}info{% else %}danger{% endif %}">
<td>{{request.name}}</td>
<td>{{request.email}}</td>
<td>{{ request.beg | replace("\r\n", "<br>") | safe }}</td>
<td id='{{request.id}}-requested'></td>
<td id='{{request.id}}-edit'>
<form action="/requests" method="POST">
{% if not request.granted %}
<button type="submit" class='btn btn-block btn-success' name="invite" value="{{request.id}}">INVITE</button>
{% endif %}
<button type="submit" class='btn btn-block btn-danger' name="delete" value="{{request.id}}">DELETE</button>
</form>
</td>
<td>
{% if request.userId %}
<a href="/map/id/{{request.userId}}">{{request.userId}}</a>
{% endif %}
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
</section>
<script src="/static/js/moment.min.js"></script>
<script src="/static/js/jquery-ui-tabs/jquery-ui.min.js"></script>
<script type="text/javascript">
/* TABS */ {
// /* TABS */ {
// Check for location.hash capability (IE9+)
if (!'onhashchange' in window) {
if (!confirm("location.hash won't work in IE<9. If you don't know how to fix this, click cancel. ")){
window.open("https://whatbrowser.org/");
}
}
// // Check for location.hash capability (IE9+)
// if (!'onhashchange' in window) {
// if (!confirm("location.hash won't work in IE<9. If you don't know how to fix this, click cancel. ")){
// window.open("https://whatbrowser.org/");
// }
// }
// Match jQuery's .ui-tabs-active with bootstrap's .active
function setActive() {
$('.nav-tabs > .active').removeClass('active');
$('.ui-tabs-active').addClass('active');
}
// // Match jQuery's .ui-tabs-active with bootstrap's .active
// function setActive() {
// $('.nav-tabs > .active').removeClass('active');
// $('.ui-tabs-active').addClass('active');
// }
// Set tab on hash change
$(window).on('hashchange', function (){
$('#tabs > ul > li > a').each(function (index, a) {
if ($(a).attr('href') == location.hash) {
$('#tabs').tabs('option', 'active', index);
setActive();
}
});
});
// // Set tab on hash change
// $(window).on('hashchange', function (){
// $('#tabs > ul > li > a').each(function (index, a) {
// if ($(a).attr('href') == location.hash) {
// $('#tabs').tabs('option', 'active', index);
// setActive();
// }
// });
// });
// Setup tabs
$('#tabs').tabs({
active: (location.hash=='#requests')?1:0,
beforeActivate: function(event,ui){
location.hash = '#'+ui.newPanel.attr('id');
setActive();
}
});
}
// // Setup tabs
// $('#tabs').tabs({
// active: (location.hash=='#requests')?1:0,
// beforeActivate: function(event,ui){
// location.hash = '#'+ui.newPanel.attr('id');
// setActive();
// }
// });
// }
/* DATE/TIME FORMATS */ {
@ -151,18 +113,6 @@
{% endif %}
{% endfor %}
// Requests
{% for request in requests %}
$('#{{request.id}}-requested').text(
moment("{{request.requestedTime}}", "ddd MMM DD YYYY HH:mm:ss [GMT]ZZ").fromNow()
);
{% if request.granted %}
$('#{{request.id}}-edit').text(
moment("{{request.granted}}", "ddd MMM DD YYYY HH:mm:ss [GMT]ZZ").fromNow()
);
{% endif %}
{% endfor %}
}
</script>

View File

@ -1,110 +0,0 @@
<section class='settings dark 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">
<div id='name'class='form-group' title="This appears in your page's title. ">
<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" data-error="Invalid input"><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 id='slug'class='form-group' title="This is the URL which shows your location. Be careful whom you share it with! ">
<label class='control-label col-sm-2 col-lg-3' for="slug">URL</label>
<div class='input-group col-xs-12 col-sm-10 col-lg-9'>
<span class='input-group-addon'>tracman.org/map/</span>
<input class='form-control' type="text" name="slug" value="{{user.slug}}" required data-remote="/validate"
maxlength="160" data-remote-error="That URL is already taken. " data-error="Invalid input"><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 id='units' class='form-group col-xs-12' title="Select standard units for feet and miles/hour. Select metric units if you are a commie. ">
<label class='control-label col-sm-4 col-lg-3' for="units">Units</label>
<div class='input-group col-sm-8 col-lg-9'>
<div class='radio-inline'><label>
<input type="radio" name="units" value="standard" {% if user.settings.units == 'standard' %}checked{% endif %}>
Standard
</label></div>
<div class='radio-inline'><label>
<input type="radio" name="units" value="metric" {% if user.settings.units == 'metric' %}checked{% endif %}>
Metric
</label></div>
</div>
</div>
<div id='defaultMap' class='form-group col-xs-12' title="Shows whether to show a satellite image or standard google road map as the default on your page. Visitors will have the option to change this. Note that satellite images load slower. ">
<label class='control-label col-sm-4 col-lg-3' for="map">Default map</label>
<div class='input-group col-sm-8 col-lg-9'>
<div class='radio-inline'><label>
<input type="radio" name="map" value="road" {% if user.settings.defaultMap == 'road' %}checked{% endif %}>
Road
</label></div>
<div class='radio-inline'><label>
<input type="radio" name="map" value="sat" {% if user.settings.defaultMap == 'sat' %}checked{% endif %}>
Satellite
</label></div>
</div>
</div>
<div id='defaultZoom' class='form-group col-xs-12' title="Shows the initial map zoom level on your page. A higher number means more zoom. Note that the size of the viewing window will also have an effect on how much of the map a visitor can see. ">
<label class='control-label col-xs-6 col-sm-4 col-lg-3' for="map">Default zoom</label>
<div class='input-group col-xs-6 col-sm-8 col-lg-9'>
<select class='c-select' name="zoom">
<option {% if user.settings.defaultZoom==1 %}selected {% endif %}value="1">1 World</option>
<option {% if user.settings.defaultZoom==2 %}selected {% endif %}value="2">2</option>
<option {% if user.settings.defaultZoom==3 %}selected {% endif %}value="3">3</option>
<option {% if user.settings.defaultZoom==4 %}selected {% endif %}value="4">4</option>
<option {% if user.settings.defaultZoom==5 %}selected {% endif %}value="5">5 Landmass</option>
<option {% if user.settings.defaultZoom==6 %}selected {% endif %}value="6">6</option>
<option {% if user.settings.defaultZoom==7 %}selected {% endif %}value="7">7</option>
<option {% if user.settings.defaultZoom==8 %}selected {% endif %}value="8">8</option>
<option {% if user.settings.defaultZoom==9 %}selected {% endif %}value="9">9</option>
<option {% if user.settings.defaultZoom==10 %}selected {% endif %}value="10">10 City</option>
<option {% if user.settings.defaultZoom==11 %}selected {% endif %}value="11">11</option>
<option {% if user.settings.defaultZoom==12 %}selected {% endif %}value="12">12</option>
<option {% if user.settings.defaultZoom==13 %}selected {% endif %}value="13">13</option>
<option {% if user.settings.defaultZoom==14 %}selected {% endif %}value="14">14</option>
<option {% if user.settings.defaultZoom==15 %}selected {% endif %}value="15">15 Streets</option>
<option {% if user.settings.defaultZoom==16 %}selected {% endif %}value="16">16</option>
<option {% if user.settings.defaultZoom==17 %}selected {% endif %}value="17">17</option>
<option {% if user.settings.defaultZoom==18 %}selected {% endif %}value="18">18</option>
<option {% if user.settings.defaultZoom==19 %}selected {% endif %}value="19">19</option>
<option {% if user.settings.defaultZoom==20 %}selected {% endif %}value="20">20 Buildings</option>
</select>
</div>
</div>
<div id='showSpeed' class='form-group col-xs-12' title="{% if not user.isPro %}PRO ONLY! {% endif %}Shows a spedometer on the map.">
<label class='control-label col-xs-6 col-sm-4 col-lg-3' for="showSpeed">Show speed{% if not user.isPro %} <span class='red'>(PRO)</span>{% endif %}</label>
<div class='input-group col-xs-6 col-sm-8 col-lg-9'>
<input class='form-control' name="showSpeed" type="checkbox" {% if not user.isPro %}disabled {% elif user.settings.showSpeed %}checked{% else %}{% endif %}><br>
</div>
</div>
<div id='showAltitude' class='form-group col-xs-12' title="{% if not user.isPro %}PRO ONLY! {% endif %}Shows the current elevation on the map. ">
<label class='control-label col-xs-6 col-sm-4 col-lg-3' for="showAlt">Show altitude{% if not user.isPro %} <span class='red'>(PRO)</span>{% endif %}</label>
<div class='input-group col-xs-6 col-sm-8 col-lg-9'>
<input class='form-control' name="showAlt" type="checkbox" {% if not user.isPro %}disabled {% elif user.settings.showAlt %}checked{% else %}{% endif %}><br>
</div>
</div>
<div id='showStreet' class='form-group col-xs-12' title="{% if not user.isPro %}PRO ONLY! {% endif %}Shows a Google street view image from your current location, oriented in the direction of travel. This feature is EXPERIMENTAL. ">
<label class='control-label col-xs-6 col-sm-4 col-lg-3' for="showStreet">Show street view{% if not user.isPro %} <span class='red'>(PRO)</span><br>{% endif %}</label>
<div class='input-group col-xs-6 col-sm-8 col-lg-9'>
<input class='form-control' name="showStreet" type="checkbox" {% if not user.isPro %}disabled{% elif user.settings.showStreetview %}checked{% else %}{% endif %}><br>
</div>
</div>
<div id='submit' class='form-group col-xs-12 flexbox' style="padding:0 0 60px">
<input class='btn yellow' style="min-width:50%;" type="submit" value="Save">
</div>
</form>
{% if not user.isPro %}<p style="clear:both">Want to try <a href="/pro">Tracman Pro</a>?&ensp;It's free during beta testing.&ensp;</p>{% endif %}
<p style="clear:both">Would you like to submit a <a href="/suggestion">suggestion</a> or <a href="/bug">bug report</a>?&ensp;</p>
</section>

View File

@ -1,34 +0,0 @@
<style>
.sharebuttons .fa {
text-align: center;
width: 32px;
height: 32px;
border-radius: 50%;
padding-top: 8px;
background: rgba(255,255,255,.2);
-moz-box-shadow: 2px 2px 4px #000;
-webkit-box-shadow: 2px 2px 4px #000;
box-shadow: 2px 2px 4px #000;
}.sharebuttons .fa:hover {
background: rgba(255,255,255,.4);
}.sharebuttons .fa:active {
-moz-box-shadow: 0;
-webkit-box-shadow: 0;
box-shadow: 0;
}
</style>
<section class='share dark container'>
<h1>Share</h1>
<p class='sharebuttons'>
To view your location, use this link:
<a href="/map/{{user.slug}}">https://tracman.org/map/{{user.slug}}</a>.&ensp;
You can share your map with these buttons:&emsp;
<a href="https://twitter.com/home?status=A%20map%20of%20my%20realtime%20location:%20https://tracman.org/map/{{user.slug}}" target="_blank"><i class="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="fa fa-facebook"></i></a>
<a href="https://www.reddit.com/submit?title=A%20map%20of%20my%20realtime%20location&url=https://tracman.org/map/{{user.slug}}" target="_blank"><i class="fa fa-reddit-alien"></i></a>
<a href="https://www.linkedin.com/shareArticle?mini=true&url=https://tracman.org/map/{{user.slug}}&title=A%20map%20of%20my%20realtime%20location" target="_blank"><i class="fa fa-linkedin"></i></a>
</p>
<p>You can also embed a map into your website with this code.&ensp;Be sure to set the width and height attributes to suit your circumstance.&ensp;</p>
<pre>&lt;iframe src=&quot;https://tracman.org/map/{{user.slug}}?noheader=1&quot; width=&quot;90%&quot; style=&quot;height:90vh&quot;&gt;&lt;/iframe&gt;</pre>
</section>

View File

@ -1,21 +0,0 @@
<style>
.google-play {
width: 150px;
border: #fbc93d solid 1px;
border-radius: 10px;
}
</style>
<section class='track dark'>
<div class='container'>
<h2>Set location</h2>
<p>You can set your location to this device's geolocation by clicking the button below.&ensp;You can also track this device's location by clicking &ldquo;Start tracking&rdquo;.&ensp;Your location will update as long as you keep this window open.&ensp;For accuracy, try it on your smartphone, but be careful, because it will drain the battery quickly.&ensp;</p>
<p class='flexbox'>
<button id='manual-set' class='btn' style="min-width:40%" onclick="setLocation()"><i class="fa fa-map-marker"></i>&emsp;Set location</button>
<button id='tracking' class='btn' style="min-width:40%" onclick="trackLocation()"><i class="fa fa-crosshairs"></i>&emsp;Start tracking</button>
</p>
<h3>Android</h3>
<p>The android app lets you update your location in the background, and will conserve battery life.&ensp;Note that it's <a href="https://github.com/Tracman-org/Android/issues" target="_blank">kind of buggy</a> at the moment.&ensp;</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>
</div>
</section>

View File

@ -327,7 +327,7 @@
// Show/hide map if location is set/unset
function toggleMaps(loc) {
if (loc.lat=='0'||loc.lon=='0') {
if (loc.lat===0&&loc.lon===0) {
$('#map').hide();
$('#pano').hide();
$('#notset').show();
@ -338,14 +338,14 @@
}
}
// execute on page load
$(function() { if (last.time) {
$(function() {
toggleMaps(last);
} });
});
// Google maps API callback
function gmapsCb() {
// Create map
if (disp!='1' || !settings.showStreetview) {
if (disp!='1'||!settings.showStreetview) {
map = new google.maps.Map( mapElem, {
center: new google.maps.LatLng( last.lat, last.lon ),
panControl: false,

View File

@ -18,7 +18,7 @@
{% else %}
<li><a href="/#overview">About</a></li>
<li><a href="/map/keith">Demo</a></li>
<li><a href="/#get">Request Invite</a></li>
<li><a href="/#join">Join</a></li>
<li><a href="/login">Login</a></li>
{% endif %}
</ul>
@ -27,7 +27,7 @@
{% if error %}
<div class='header alert alert-danger alert-dismissible'>
<strong><i class="fa fa-exclamation-circle"></i> ERROR:</strong> {{ error | safe }}
<strong><i class="fa fa-exclamation-circle"></i> ERROR:</strong> {{error|safe}}
<a href="#" class='close' data-dismiss="alert" aria-label="close"><i class='fa fa-times'></i></a>
</div>
{% elif success %}