Browse Source

first draft of a public shared link view

* API method to create a new time-limited shared link
* API method for retrieving the current location given a shared link token
* map view that refreshes the current location every 5 seconds
pull/34/head
Aaron Parecki 5 years ago
parent
commit
6a0eb8909c
No known key found for this signature in database GPG Key ID: 276C2817346D6056
10 changed files with 227 additions and 4 deletions
  1. +27
    -0
      compass/app/Http/Controllers/Api.php
  2. +48
    -0
      compass/app/Http/Controllers/Share.php
  3. +4
    -0
      compass/app/Http/routes.php
  4. +33
    -0
      compass/database/migrations/2019_05_12_123107_shares.php
  5. +0
    -4
      compass/public/assets/map.js
  6. +12
    -0
      compass/public/assets/share-map.css
  7. +60
    -0
      compass/public/assets/share.js
  8. +25
    -0
      compass/resources/views/layouts/share.blade.php
  9. +9
    -0
      compass/resources/views/share-expired.blade.php
  10. +9
    -0
      compass/resources/views/share.blade.php

+ 27
- 0
compass/app/Http/Controllers/Api.php View File

@ -412,4 +412,31 @@ class Api extends BaseController
}
}
public function share(Request $request) {
$token = $request->input('token');
if(!$token)
return response(json_encode(['error' => 'no token provided']))->header('Content-Type', 'application/json');
$db = DB::table('databases')->where('write_token','=',$token)->first();
if(!$db)
return response(json_encode(['error' => 'invalid token']))->header('Content-Type', 'application/json');
$expires_at = time() + $request->input('duration');
$share_token = str_random(15);
$share_id = DB::table('shares')->insertGetId([
'database_id' => $db->id,
'created_at' => date('Y-m-d H:i:s'),
'expires_at' => date('Y-m-d H:i:s', $expires_at),
'token' => $share_token,
]);
$share_url = env('BASE_URL').'s/'.$share_token;
return response(json_encode([
'url' => $share_url
]), 201)->header('Content-Type', 'application/json')
->header('Location', $share_url);
}
}

+ 48
- 0
compass/app/Http/Controllers/Share.php View File

@ -0,0 +1,48 @@
<?php
namespace App\Http\Controllers;
use Laravel\Lumen\Routing\Controller as BaseController;
use Illuminate\Http\Request;
use DB;
class Share extends BaseController
{
private function _databaseFromToken($token) {
$share = DB::table('shares')
->where('token', $token)
->where('expires_at', '>', time())
->first();
if(!$share) return false;
$database = DB::table('databases')->where('id', $share->database_id)->first();
return $database;
}
public function view(Request $request, $token) {
$database = $this->_databaseFromToken($token);
if(!$database) {
return view('share-expired');
}
return view('share', [
'database' => $database,
'share_token' => $token,
]);
}
public function current_location(Request $request) {
$database = $this->_databaseFromToken($request->input('token'));
$response = [
'data' => json_decode($database->last_location),
];
return response(json_encode($response))->header('Content-Type', 'application/json');
}
}

+ 4
- 0
compass/app/Http/routes.php View File

@ -2,6 +2,9 @@
$app->get('/', 'Controller@index');
$app->get('/s/{token:[A-Za-z0-9]+}', 'Share@view');
$app->get('/share/current.json', 'Share@current_location');
$app->post('/auth/start', 'IndieAuth@start');
$app->get('/auth/callback', 'IndieAuth@callback');
$app->get('/auth/github', 'IndieAuth@github');
@ -22,3 +25,4 @@ $app->get('/api/find-from-localtime', 'LocalTime@find');
$app->get('/api/input', 'Api@account');
$app->post('/api/input', 'Api@input');
$app->post('/api/trip-complete', 'Api@trip_complete');
$app->post('/api/share', 'Api@share');

+ 33
- 0
compass/database/migrations/2019_05_12_123107_shares.php View File

@ -0,0 +1,33 @@
<?php
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class Shares extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('shares', function (Blueprint $table) {
$table->increments('id');
$table->unsignedInteger('database_id');
$table->datetime('expires_at')->nullable();
$table->string('token', 30);
$table->datetime('created_at');
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::drop('shares');
}
}

+ 0
- 4
compass/public/assets/map.js View File

@ -32,10 +32,6 @@ var startMarker;
var endMarker;
var timers = [];
function pointFromGeoJSON(geo) {
return L.latLng(geo[1], geo[0])
}
function resetAnimation() {
if(animatedMarker) {
map.removeLayer(animatedMarker);

+ 12
- 0
compass/public/assets/share-map.css View File

@ -0,0 +1,12 @@
html, body {
height: 100%;
}
#map {
height: 100%;
}
/* Move the map zoom controls away from the Compass logo */
.leaflet-top .leaflet-control-zoom {
margin-top: 60px;
margin-left: 26px;
}

+ 60
- 0
compass/public/assets/share.js View File

@ -0,0 +1,60 @@
var map = L.map('map', { zoomControl: false }).setView([45.516, -122.660], 14, null, null, 24);
L.tileLayer('https://api.tiles.mapbox.com/v4/{id}/{z}/{x}/{y}.png?access_token={accessToken}', {
attribution: 'Map data &copy; <a href="https://www.openstreetmap.org/">OpenStreetMap</a> contributors, <a href="https://creativecommons.org/licenses/by-sa/2.0/">CC-BY-SA</a>, Imagery © <a href="https://www.mapbox.com/">Mapbox</a>',
maxZoom: 18,
id: 'mapbox.streets',
accessToken: 'pk.eyJ1IjoiYWFyb25wayIsImEiOiI1T0tpNjdzIn0.OQjXyI3xSt8Dj8na3l90Sg'
}).addTo(map);
new L.Control.Zoom({ position: 'topleft' }).addTo(map);
var geojsonLineOptions = {
color: "#0033ff",
weight: 4,
opacity: 0.5
};
var startIcon = L.icon({
iconUrl: '/assets/map-pin-start.png',
iconSize: [18,28],
iconAnchor: [9,28]
});
// Load the current location and show on the map
var currentLocationMarker;
function getCurrentLocation() {
$.getJSON("/share/current.json?token="+$("#share_token").val(), function(data){
if(data.data) {
moveMarkerToPosition(data.data);
map.setView(currentLocationMarker.getLatLng());
}
setTimeout(getCurrentLocation, 5000);
});
}
getCurrentLocation();
function moveMarkerToPosition(feature) {
if(feature && feature.geometry) {
var coord = pointFromGeoJSON(feature.geometry.coordinates);
if(coord) {
if(!currentLocationMarker) {
currentLocationMarker = L.marker(coord).addTo(map);
} else {
currentLocationMarker.setLatLng(coord);
}
}
}
}
function pointFromGeoJSON(geo) {
return L.latLng(geo[1], geo[0])
}

+ 25
- 0
compass/resources/views/layouts/share.blade.php View File

@ -0,0 +1,25 @@
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>Compass</title>
<link rel="stylesheet" href="/assets/semantic/semantic.min.css">
<link rel="stylesheet" href="/assets/font-awesome-4.4.0/css/font-awesome.min.css">
<link rel="stylesheet" href="/assets/styles.css">
<meta name="viewport" content="width=device-width, initial-scale=1">
<script src="/assets/jquery-1.11.3.min.js"></script>
<link rel="stylesheet" href="/assets/leaflet-0.7.3/leaflet.css" />
<link rel="stylesheet" href="/assets/share-map.css">
</head>
<body>
@yield('content')
<script src="/assets/leaflet-0.7.3/leaflet.js"></script>
<script src="/assets/leaflet-0.7.3/esri-leaflet.js"></script>
<script src="/assets/semantic/semantic.min.js"></script>
<script src="/assets/semantic/components/dropdown.min.js"></script>
<script src="/assets/extensions.js"></script>
<script src="/assets/share.js"></script>
</body>
</html>

+ 9
- 0
compass/resources/views/share-expired.blade.php View File

@ -0,0 +1,9 @@
@extends('layouts.master')
@section('content')
<div style="text-align: center; margin-top: 3em;">
This shared link has expired.
</div>
@endsection

+ 9
- 0
compass/resources/views/share.blade.php View File

@ -0,0 +1,9 @@
@extends('layouts.share')
@section('content')
<div id="map"></div>
<input type="hidden" id="share_token" value="{{ $share_token }}">
@endsection

Loading…
Cancel
Save