Added accounts to admin
parent
3a00dc8372
commit
80d1ec7b6c
|
@ -16,6 +16,10 @@ $ npm start
|
|||
|
||||
## Changelog
|
||||
|
||||
#### v0.4.1
|
||||
|
||||
*
|
||||
|
||||
#### v0.4.0
|
||||
|
||||
* Opened registration
|
||||
|
|
|
@ -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 }); }
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
});
|
||||
|
|
|
@ -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. Note that you will need a google account to continue. You will also need an android phone to update your location. </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. </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. You have read the <a href="https://tracman.org/#disclaimer">disclaimer</a>, haven't you? </p>
|
||||
<p>Regards,
|
||||
<br>Keith</p>
|
||||
</body>
|
||||
</html>
|
|
@ -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. 
|
||||
|
||||
Feel free to use this link to create an account. Note that you will need a google account to continue. You will also need an android phone to update your location. 
|
||||
|
||||
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. 
|
||||
|
||||
Regards,
|
||||
Keith
|
|
@ -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}
|
||||
});
|
||||
|
|
|
@ -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){
|
||||
|
|
|
@ -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('/');
|
||||
});
|
||||
|
||||
|
|
|
@ -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]
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -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"
|
||||
);
|
||||
});
|
||||
|
||||
|
|
|
@ -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
124
test.js
|
@ -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){
|
||||
|
||||
// });
|
||||
|
||||
});
|
126
views/admin.html
126
views/admin.html
|
@ -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>
|
||||
|
|
|
@ -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>? 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>
|
||||
</section>
|
|
@ -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>. 
|
||||
You can share your map with these buttons: 
|
||||
<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. Be sure to set the width and height attributes to suit your circumstance. </p>
|
||||
<pre><iframe src="https://tracman.org/map/{{user.slug}}?noheader=1" width="90%" style="height:90vh"></iframe></pre>
|
||||
</section>
|
|
@ -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. You can also track this device's location by clicking “Start tracking”. Your location will update as long as you keep this window open. For accuracy, try it on your smartphone, but be careful, because it will drain the battery quickly. </p>
|
||||
<p class='flexbox'>
|
||||
<button id='manual-set' class='btn' style="min-width:40%" onclick="setLocation()"><i class="fa fa-map-marker"></i> Set location</button>
|
||||
<button id='tracking' class='btn' style="min-width:40%" onclick="trackLocation()"><i class="fa fa-crosshairs"></i> Start tracking</button>
|
||||
</p>
|
||||
<h3>Android</h3>
|
||||
<p>The android app lets you update your location in the background, and will conserve battery life. Note that it's <a href="https://github.com/Tracman-org/Android/issues" target="_blank">kind of buggy</a> at the moment. </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>
|
|
@ -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,
|
||||
|
|
|
@ -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 %}
|
||||
|
|
Loading…
Reference in New Issue