Refactor the MVC model to be more PHP-ish and include the twig templating library. This base commit is substantially better than the oprevious and provides a solid foundation for faster iterations of development and inclusion of new content.pull/123/head
@@ -0,0 +1 @@ | |||||
vendor |
@@ -0,0 +1,16 @@ | |||||
<?php | |||||
namespace App; | |||||
class Config { | |||||
# base directory for sqlite database | |||||
const DB_DIR = '/home/pi/raspberry-noaa/'; | |||||
# see files in App/Lang directory for available translations | |||||
const LANG = 'en'; | |||||
# use https://www.php.net/manual/en/timezones.php | |||||
const TIMEZONE = 'America/New_York'; | |||||
} | |||||
?> |
@@ -0,0 +1,13 @@ | |||||
<?php | |||||
namespace App\Controllers; | |||||
use Lib\View; | |||||
class CapturesController extends \Lib\Controller { | |||||
public function indexAction($args) { | |||||
View::renderTemplate('Captures/index.html', $args); | |||||
} | |||||
} | |||||
?> |
@@ -0,0 +1,13 @@ | |||||
<?php | |||||
namespace App\Controllers; | |||||
use Lib\View; | |||||
class PassesController extends \Lib\Controller { | |||||
public function indexAction($args) { | |||||
View::renderTemplate('Passes/index.html', $args); | |||||
} | |||||
} | |||||
?> |
@@ -1,5 +1,5 @@ | |||||
<?php | <?php | ||||
$lang = array( | |||||
return array( | |||||
"captures" => "يلتقط", | "captures" => "يلتقط", | ||||
"elev" => "الإرتفاع", | "elev" => "الإرتفاع", | ||||
"images" => "الصور", | "images" => "الصور", |
@@ -1,5 +1,5 @@ | |||||
<?php | <?php | ||||
$lang = array( | |||||
return array( | |||||
"captures" => "Erfasst", | "captures" => "Erfasst", | ||||
"elev" => "Erhebung", | "elev" => "Erhebung", | ||||
"images" => "Bilder", | "images" => "Bilder", |
@@ -1,5 +1,5 @@ | |||||
<?php | <?php | ||||
$lang = array( | |||||
return array( | |||||
"captures" => "Captures", | "captures" => "Captures", | ||||
"elev" => "Elevation", | "elev" => "Elevation", | ||||
"images" => "Images", | "images" => "Images", |
@@ -1,5 +1,5 @@ | |||||
<?php | <?php | ||||
$lang = array( | |||||
return array( | |||||
"captures" => "Capturas", | "captures" => "Capturas", | ||||
"elev" => "Elevación", | "elev" => "Elevación", | ||||
"images" => "Imagenes", | "images" => "Imagenes", |
@@ -1,5 +1,5 @@ | |||||
<?php | <?php | ||||
$lang = array( | |||||
return array( | |||||
"captures" => "Hvatanja", | "captures" => "Hvatanja", | ||||
"elev" => "Visina", | "elev" => "Visina", | ||||
"images" => "Slike", | "images" => "Slike", |
@@ -0,0 +1,18 @@ | |||||
{% extends "base.html" %} | |||||
{% block body %} | |||||
<link rel="stylesheet" type="text/css" href="assets/css/captures.css"> | |||||
<nav aria-label="page" id="pagination" class="mb-0"> | |||||
{% include('Captures/pagination.html') %} | |||||
</nav> | |||||
<div class="page-count-summary mb-0 mx-2 my-1"> | |||||
{{ "#{lang['page']} #{cur_page} #{lang['of']} #{page_count}" }} | |||||
</div> | |||||
<nav aria-label="page" id="pagination" class="d-md-none mb-0"> | |||||
{% include('Captures/pagination.html') %} | |||||
</nav> | |||||
{% endblock %} |
@@ -0,0 +1,17 @@ | |||||
<nav aria-label="page" id="pagination" class="mb-0"> | |||||
<ul class="pagination pagination-sm justify-content-center mb-0 mx-2"> | |||||
<li class="page-item{% if cur_page <= 1 %} disabled {% endif %}"> | |||||
<a class="page-link" href="{{ "?page=#{cur_page-1}" }}" aria-label="{{ lang['prev'] }}"> | |||||
<span aria-hiden="true">«</span> | |||||
<span>{{ lang['prev'] }}</span> | |||||
</a> | |||||
</li> | |||||
<li class="page-item{% if cur_page >= page_count %} disabled {% endif %}"> | |||||
<a class="page-link" href="{{ "?page=#{cur_page+1}" }}" aria-label="{{ lang['next'] }}"> | |||||
<span>{{ lang['next'] }}</span> | |||||
<span aria-hiden="true">»</span> | |||||
</a> | |||||
</li> | |||||
</ul> | |||||
</nav> |
@@ -0,0 +1,19 @@ | |||||
{% extends "base.html" %} | |||||
{% block body %} | |||||
<link rel="stylesheet" type="text/css" href="assets/css/pass_list.css"> | |||||
<table class="table table-bordered table-sm table-striped" id="passes"> | |||||
<thead class="thead-dark"> | |||||
<tr class="text-center"> | |||||
<th scope="col">{{ lang['satellite'] }}</th> | |||||
<th scope="col">{{ lang['pass_start'] }}</th> | |||||
<th scope="col">{{ lang['pass_end'] }}</th> | |||||
<th scope="col">{{ lang['max_elev'] }}</th> | |||||
</tr> | |||||
</thead> | |||||
<tbody> | |||||
</tbody> | |||||
</table> | |||||
{% endblock %} |
@@ -0,0 +1,53 @@ | |||||
<!DOCTYPE html> | |||||
<html lang="en"> | |||||
<head> | |||||
<meta charset="UTF-8"> | |||||
<meta name="viewport" content="width=device-width, initial-scale=1.0"> | |||||
<meta http-equiv="X-UA-Compatible" content="ie=edge"> | |||||
<link rel="stylesheet" type="text/css" href="assets/css/header.css"> | |||||
<link rel="stylesheet" type="text/css" href="assets/css/footer.css"> | |||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.6.0/dist/css/bootstrap.min.css" | |||||
integrity="sha384-B0vP5xmATw1+K9KRQjQERJvTumQW0nPEzvF6L/Z6nronJ3oUOFUFpCjEUQouq2+l" crossorigin="anonymous"> | |||||
<title>Raspberry NOAA V2</title> | |||||
<link rel="shortcut icon" href="assets/web_img/favicon.ico" type="image/x-icon"/> | |||||
</head> | |||||
<body> | |||||
<header class="mb-3"> | |||||
<div class="navbar navbar-expand navbar-dark bg-dark"> | |||||
<ul class="navbar-nav mr-auto"> | |||||
<li class="nav-item {% if page == 'passes' %} active {% endif %}"> | |||||
<a class="nav-link" href="passes">{{ lang['passes'] }}</a> | |||||
</li> | |||||
<li class="nav-item {% if page == 'captures' or page == 'capture' %} active {% endif%}"> | |||||
<a class="nav-link" href="captures">{{ lang['captures'] }}</a> | |||||
</li> | |||||
</ul> | |||||
<span class="navbar-text timezone"> | |||||
<em> | |||||
{{ constant('App\\Config::TIMEZONE') }}<br> | |||||
(UTC{{ 'now'|date('P') }}) | |||||
</em> | |||||
</span> | |||||
</div> | |||||
</header> | |||||
<div class="container"> | |||||
{% block body %} | |||||
{% endblock %} | |||||
</div> | |||||
<footer class="footer text-center"> | |||||
<div class="contaienr"> | |||||
<a href="https://github.com/reynico/raspberry-noaa"><img class="img-footer" src="assets/web_img/logo-small.png"></a> | |||||
</div> | |||||
</footer> | |||||
<script src="https://code.jquery.com/jquery-3.5.1.slim.min.js" | |||||
integrity="sha384-DfXdz2htPH0lsSSs5nCTpuj/zy4C+OGpamoFVy38MVBnE+IbbVYUew+OrCXaRkfj" crossorigin="anonymous"></script> | |||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@4.6.0/dist/js/bootstrap.bundle.min.js" | |||||
integrity="sha384-Piv4xVNRyMGpqkS2by6br4gNJ7DXjqk09RmUpJ8jgGtD7zP9yug3goQfGII0yAns" crossorigin="anonymous"></script> | |||||
</body> | |||||
</html> |
@@ -0,0 +1,33 @@ | |||||
<?php | |||||
namespace Lib; | |||||
abstract class Controller { | |||||
public function __construct($name) { | |||||
$this->name = $name; | |||||
} | |||||
# mapping to provide a before and after functionality | |||||
public function __call($name, $args) { | |||||
$method = $name . 'Action'; | |||||
$path = explode('\\', get_called_class()); | |||||
if (method_exists($this, $method)) { | |||||
if ($this->before() !== false) { | |||||
# add the page name for navigation control | |||||
$args = array_merge($args, array(array('page' => $this->name))); | |||||
call_user_func_array([$this, $method], $args); | |||||
$this->after(); | |||||
} | |||||
} else { | |||||
echo '404 - method ' . $method . ' not found<br>'; | |||||
} | |||||
} | |||||
protected function before() { } | |||||
protected function after() { } | |||||
} | |||||
?> |
@@ -0,0 +1,56 @@ | |||||
<?php | |||||
namespace Lib; | |||||
class Router { | |||||
private $controller = null; | |||||
private $action = null; | |||||
private $params = array(); | |||||
# default constructor and check for validity of request | |||||
public function __construct() { | |||||
$this->convertUrl(); | |||||
$this->handleRequest(); | |||||
} | |||||
# split URL into controller, action, and params components | |||||
public function convertUrl() { | |||||
if (isset($_SERVER['REQUEST_URI'])) { | |||||
# remove leading/trailing slashes, and exclude query params | |||||
$uri_parts = explode('?', $_SERVER['REQUEST_URI'], 2); | |||||
$url = rtrim($uri_parts[0], '/'); | |||||
$url = ltrim($url, '/'); | |||||
# filter for malicious input | |||||
$url = filter_var($url, FILTER_SANITIZE_URL); | |||||
# separate path components and store the | |||||
# the controller, action, and any parameters | |||||
$url = explode('/', $url); | |||||
$this->controller = (isset($url[0]) and $url[0] != '') ? $url[0] : 'passes'; | |||||
$this->action = (isset($url[1]) and $url[1] != '') ? $url[1] : 'index'; | |||||
$this->params = (isset($uri_parts[1]) and $uri_parts[1] != '') ? $uri_parts[1] : null; | |||||
} | |||||
} | |||||
# based on request path, attempt to route to correct location | |||||
public function handleRequest() { | |||||
# attempt to build and call controller action | |||||
$controller_name = ucfirst($this->controller) . 'Controller'; | |||||
$controller_file = __DIR__ . '/../App/Controllers/' . $controller_name . '.php'; | |||||
if (file_exists($controller_file)) { | |||||
# construct instance of controller | |||||
include_once($controller_file); | |||||
$full_controller_name = "App\\Controllers\\" . $controller_name; | |||||
$this->controller = new $full_controller_name($this->controller); | |||||
# TODO: Pass parameters | |||||
$this->controller->{$this->action}(); | |||||
} else { | |||||
echo '404 - could not find controller<br>'; | |||||
} | |||||
} | |||||
} | |||||
?> |
@@ -0,0 +1,25 @@ | |||||
<?php | |||||
namespace Lib; | |||||
use App\Config; | |||||
class View { | |||||
# render a template using twig | |||||
public static function renderTemplate($template, $args = []) { | |||||
static $twig = null; | |||||
# include i18n language file for global inclusion | |||||
$lang = include(__DIR__ . '/../App/Lang/' . Config::LANG . '.php'); | |||||
if ($twig === null) { | |||||
$loader = new \Twig\Loader\FilesystemLoader(dirname(__DIR__) . '/App/Views'); | |||||
$twig = new \Twig\Environment($loader); | |||||
$twig->addGlobal('lang', $lang); | |||||
} | |||||
echo $twig->render($template, $args); | |||||
} | |||||
} | |||||
?> |
@@ -1,7 +0,0 @@ | |||||
<?php | |||||
# "Capture" showing list of all images for a particular capture | |||||
include_once('views/header.php'); | |||||
$pass_id = isset($_GET['id']) ? intval($_GET['id']) : 1; | |||||
require('controllers/capture_controller.php'); | |||||
include_once('views/footer.php') | |||||
?> |
@@ -1,7 +0,0 @@ | |||||
<?php | |||||
# "Captures" showing grid of all captured images | |||||
include_once('views/header.php'); | |||||
$page = isset($_GET['page']) ? intval($_GET['page']) : 1; | |||||
require('controllers/captures_controller.php'); | |||||
include_once('views/footer.php') | |||||
?> |
@@ -0,0 +1,11 @@ | |||||
{ | |||||
"require": { | |||||
"twig/twig": "~3.0" | |||||
}, | |||||
"autoload": { | |||||
"psr-4": { | |||||
"Lib\\": "Lib/", | |||||
"App\\": "App/" | |||||
} | |||||
} | |||||
} |
@@ -0,0 +1,205 @@ | |||||
{ | |||||
"_readme": [ | |||||
"This file locks the dependencies of your project to a known state", | |||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", | |||||
"This file is @generated automatically" | |||||
], | |||||
"content-hash": "d8b0017452a0ac0413ba7a9ee3d5d3e8", | |||||
"packages": [ | |||||
{ | |||||
"name": "symfony/polyfill-ctype", | |||||
"version": "v1.22.0", | |||||
"source": { | |||||
"type": "git", | |||||
"url": "https://github.com/symfony/polyfill-ctype.git", | |||||
"reference": "c6c942b1ac76c82448322025e084cadc56048b4e" | |||||
}, | |||||
"dist": { | |||||
"type": "zip", | |||||
"url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/c6c942b1ac76c82448322025e084cadc56048b4e", | |||||
"reference": "c6c942b1ac76c82448322025e084cadc56048b4e", | |||||
"shasum": "" | |||||
}, | |||||
"require": { | |||||
"php": ">=7.1" | |||||
}, | |||||
"suggest": { | |||||
"ext-ctype": "For best performance" | |||||
}, | |||||
"type": "library", | |||||
"extra": { | |||||
"branch-alias": { | |||||
"dev-main": "1.22-dev" | |||||
}, | |||||
"thanks": { | |||||
"name": "symfony/polyfill", | |||||
"url": "https://github.com/symfony/polyfill" | |||||
} | |||||
}, | |||||
"autoload": { | |||||
"psr-4": { | |||||
"Symfony\\Polyfill\\Ctype\\": "" | |||||
}, | |||||
"files": [ | |||||
"bootstrap.php" | |||||
] | |||||
}, | |||||
"notification-url": "https://packagist.org/downloads/", | |||||
"license": [ | |||||
"MIT" | |||||
], | |||||
"authors": [ | |||||
{ | |||||
"name": "Gert de Pagter", | |||||
"email": "BackEndTea@gmail.com" | |||||
}, | |||||
{ | |||||
"name": "Symfony Community", | |||||
"homepage": "https://symfony.com/contributors" | |||||
} | |||||
], | |||||
"description": "Symfony polyfill for ctype functions", | |||||
"homepage": "https://symfony.com", | |||||
"keywords": [ | |||||
"compatibility", | |||||
"ctype", | |||||
"polyfill", | |||||
"portable" | |||||
], | |||||
"time": "2021-01-07T16:49:33+00:00" | |||||
}, | |||||
{ | |||||
"name": "symfony/polyfill-mbstring", | |||||
"version": "v1.22.0", | |||||
"source": { | |||||
"type": "git", | |||||
"url": "https://github.com/symfony/polyfill-mbstring.git", | |||||
"reference": "f377a3dd1fde44d37b9831d68dc8dea3ffd28e13" | |||||
}, | |||||
"dist": { | |||||
"type": "zip", | |||||
"url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/f377a3dd1fde44d37b9831d68dc8dea3ffd28e13", | |||||
"reference": "f377a3dd1fde44d37b9831d68dc8dea3ffd28e13", | |||||
"shasum": "" | |||||
}, | |||||
"require": { | |||||
"php": ">=7.1" | |||||
}, | |||||
"suggest": { | |||||
"ext-mbstring": "For best performance" | |||||
}, | |||||
"type": "library", | |||||
"extra": { | |||||
"branch-alias": { | |||||
"dev-main": "1.22-dev" | |||||
}, | |||||
"thanks": { | |||||
"name": "symfony/polyfill", | |||||
"url": "https://github.com/symfony/polyfill" | |||||
} | |||||
}, | |||||
"autoload": { | |||||
"psr-4": { | |||||
"Symfony\\Polyfill\\Mbstring\\": "" | |||||
}, | |||||
"files": [ | |||||
"bootstrap.php" | |||||
] | |||||
}, | |||||
"notification-url": "https://packagist.org/downloads/", | |||||
"license": [ | |||||
"MIT" | |||||
], | |||||
"authors": [ | |||||
{ | |||||
"name": "Nicolas Grekas", | |||||
"email": "p@tchwork.com" | |||||
}, | |||||
{ | |||||
"name": "Symfony Community", | |||||
"homepage": "https://symfony.com/contributors" | |||||
} | |||||
], | |||||
"description": "Symfony polyfill for the Mbstring extension", | |||||
"homepage": "https://symfony.com", | |||||
"keywords": [ | |||||
"compatibility", | |||||
"mbstring", | |||||
"polyfill", | |||||
"portable", | |||||
"shim" | |||||
], | |||||
"time": "2021-01-07T16:49:33+00:00" | |||||
}, | |||||
{ | |||||
"name": "twig/twig", | |||||
"version": "v3.2.1", | |||||
"source": { | |||||
"type": "git", | |||||
"url": "https://github.com/twigphp/Twig.git", | |||||
"reference": "f795ca686d38530045859b0350b5352f7d63447d" | |||||
}, | |||||
"dist": { | |||||
"type": "zip", | |||||
"url": "https://api.github.com/repos/twigphp/Twig/zipball/f795ca686d38530045859b0350b5352f7d63447d", | |||||
"reference": "f795ca686d38530045859b0350b5352f7d63447d", | |||||
"shasum": "" | |||||
}, | |||||
"require": { | |||||
"php": ">=7.2.5", | |||||
"symfony/polyfill-ctype": "^1.8", | |||||
"symfony/polyfill-mbstring": "^1.3" | |||||
}, | |||||
"require-dev": { | |||||
"psr/container": "^1.0", | |||||
"symfony/phpunit-bridge": "^4.4.9|^5.0.9" | |||||
}, | |||||
"type": "library", | |||||
"extra": { | |||||
"branch-alias": { | |||||
"dev-master": "3.2-dev" | |||||
} | |||||
}, | |||||
"autoload": { | |||||
"psr-4": { | |||||
"Twig\\": "src/" | |||||
} | |||||
}, | |||||
"notification-url": "https://packagist.org/downloads/", | |||||
"license": [ | |||||
"BSD-3-Clause" | |||||
], | |||||
"authors": [ | |||||
{ | |||||
"name": "Fabien Potencier", | |||||
"email": "fabien@symfony.com", | |||||
"homepage": "http://fabien.potencier.org", | |||||
"role": "Lead Developer" | |||||
}, | |||||
{ | |||||
"name": "Twig Team", | |||||
"role": "Contributors" | |||||
}, | |||||
{ | |||||
"name": "Armin Ronacher", | |||||
"email": "armin.ronacher@active-4.com", | |||||
"role": "Project Founder" | |||||
} | |||||
], | |||||
"description": "Twig, the flexible, fast, and secure template language for PHP", | |||||
"homepage": "https://twig.symfony.com", | |||||
"keywords": [ | |||||
"templating" | |||||
], | |||||
"time": "2021-01-05T15:40:36+00:00" | |||||
} | |||||
], | |||||
"packages-dev": [], | |||||
"aliases": [], | |||||
"minimum-stability": "stable", | |||||
"stability-flags": [], | |||||
"prefer-stable": false, | |||||
"prefer-lowest": false, | |||||
"platform": [], | |||||
"platform-dev": [] | |||||
} |
@@ -1,7 +0,0 @@ | |||||
<?php | |||||
return (object) array( | |||||
'db_dir' => '/home/pi/raspberry-noaa/', # base directory for sqlite database | |||||
'lang' => 'en', # see files in i18n/ directory for available translations | |||||
'timezone' => 'America/New_York' # use https://www.php.net/manual/en/timezones.php | |||||
); | |||||
?> |
@@ -1,9 +0,0 @@ | |||||
<?php | |||||
$configs = include('config.php'); | |||||
require('models/db_conn.php'); | |||||
$db_conn = new Conn($configs->db_dir); | |||||
if ($pass_id < 1) $pass_id = 1; | |||||
$enhancements = $db_conn->getEnhancements($pass_id); | |||||
$path = $db_conn->getImagePath($pass_id); | |||||
require('views/capture.php'); | |||||
?> |
@@ -1,15 +0,0 @@ | |||||
<?php | |||||
$img_per_page = 18; | |||||
$configs = include('config.php'); | |||||
require('models/db_conn.php'); | |||||
$db_conn = new Conn($configs->db_dir); | |||||
$page_count = $db_conn->totalPages($img_per_page); | |||||
# adjust for under/over paging | |||||
if ($page < 1) $page = 1; | |||||
if ($page > $page_count) $page = $page_count; | |||||
$images = $db_conn->getImages($page, $img_per_page); | |||||
require('views/all_captures.php'); | |||||
?> |
@@ -1,7 +0,0 @@ | |||||
<?php | |||||
$configs = include('config.php'); | |||||
require('models/db_conn.php'); | |||||
$db_conn = new Conn($configs->db_dir); | |||||
$passes = $db_conn->getPasses(); | |||||
require('views/pass_list.php'); | |||||
?> |
@@ -1,7 +0,0 @@ | |||||
<?php | |||||
# "Passes" showing table of all scheduled passes (and landing page) | |||||
include_once('views/header.php'); | |||||
$page = isset($_GET['page']) ? intval($_GET['page']) : 1; | |||||
require('controllers/pass_controller.php'); | |||||
include_once('views/footer.php') | |||||
?> |
@@ -1,110 +0,0 @@ | |||||
<?php | |||||
class Conn { | |||||
private $con; | |||||
# default constructor | |||||
public function __construct(string $db_dir) { | |||||
$this->con = new SQLite3($db_dir . 'panel.db'); | |||||
} | |||||
# get scheduled pass list information | |||||
public function getPasses() { | |||||
$today = strtotime(date('Y-m-d', time())); | |||||
$query = $this->con->query("SELECT sat_name, | |||||
is_active, | |||||
pass_start, | |||||
pass_end, | |||||
max_elev | |||||
FROM predict_passes | |||||
WHERE (pass_start > $today) | |||||
ORDER BY pass_start ASC;"); | |||||
$passes = []; | |||||
$i = 0; | |||||
while ($row = $query->fetchArray()) { | |||||
$passes[$i] = $row; | |||||
$i++; | |||||
} | |||||
return $passes; | |||||
} | |||||
# get total number of pages to display images given the | |||||
# passed number of images per page | |||||
public function totalPages($img_per_page) { | |||||
$decoded_passes = $this->con->querySingle("SELECT count() | |||||
FROM decoded_passes;"); | |||||
return ceil($decoded_passes/$img_per_page); | |||||
} | |||||
# get a list of images for the given page and total number | |||||
# of configured images per page | |||||
public function getImages($page, $img_per_page) { | |||||
$query = $this->con->prepare("SELECT decoded_passes.id, | |||||
predict_passes.pass_start, | |||||
file_path, | |||||
sat_type, | |||||
predict_passes.sat_name, | |||||
predict_passes.max_elev | |||||
FROM decoded_passes | |||||
INNER JOIN predict_passes | |||||
ON predict_passes.pass_start = decoded_passes.pass_start | |||||
ORDER BY decoded_passes.pass_start DESC LIMIT ? OFFSET ?;"); | |||||
$query->bindValue(1, $img_per_page); | |||||
$query->bindValue(2, $img_per_page * ($page-1)); | |||||
$result = $query->execute(); | |||||
$images = []; | |||||
$i = 0; | |||||
while ($row = $result->fetchArray()) { | |||||
$images[$i] = $row; | |||||
$i++; | |||||
} | |||||
return $images; | |||||
} | |||||
# get the enhancements for the particular capture | |||||
public function getEnhancements($id) { | |||||
$query = $this->con->prepare('SELECT daylight_pass, | |||||
sat_type, | |||||
img_count | |||||
FROM decoded_passes | |||||
WHERE id = ?;'); | |||||
$query->bindValue(1, $id); | |||||
$result = $query->execute(); | |||||
$pass = $result->fetchArray(); | |||||
# build enhancement paths based on satellite type | |||||
switch($pass['sat_type']) { | |||||
case 0: // Meteor-M2 | |||||
$enhancements = ['-122-rectified.jpg']; | |||||
break; | |||||
case 1: // NOAA | |||||
if ($pass['daylight_pass'] == 1) { | |||||
$enhancements = ['-ZA.jpg','-MCIR.jpg','-MCIR-precip.jpg','-MSA.jpg','-MSA-precip.jpg','-HVC.jpg','-HVC-precip.jpg','-HVCT.jpg','-HVCT-precip.jpg']; | |||||
} else { | |||||
$enhancements = ['-ZA.jpg','-MCIR.jpg','-MCIR-precip.jpg']; | |||||
} | |||||
break; | |||||
case 2: // ISS | |||||
for ($x = 0; $x <= $pass['img_count']-1; $x++) { | |||||
$enhancements[] = "-$x.png"; | |||||
} | |||||
break; | |||||
} | |||||
return $enhancements; | |||||
} | |||||
# get the image path for the specific image | |||||
public function getImagePath($id) { | |||||
$query = $this->con->prepare('SELECT file_path | |||||
FROM decoded_passes | |||||
WHERE id = ?;'); | |||||
$query->bindValue(1, $id); | |||||
$result = $query->execute(); | |||||
$image = $result->fetchArray(); | |||||
return $image['file_path']; | |||||
} | |||||
} | |||||
?> |
@@ -0,0 +1,18 @@ | |||||
<?php | |||||
# composer auto-loading | |||||
require dirname(__DIR__) . '/vendor/autoload.php'; | |||||
use App\Config; | |||||
# error handling | |||||
error_reporting(E_ALL); | |||||
ini_set('display_errors', 1); | |||||
ini_set('display_startup_errors', 1); | |||||
include(__DIR__ . '/../Lib/Router.php'); | |||||
# handle route dispatching | |||||
$router = new Lib\Router(); | |||||
?> |
@@ -1,60 +0,0 @@ | |||||
<link rel="stylesheet" type="text/css" href="css/captures.css"> | |||||
<nav aria-label="page" id="pagination" class="mb-0"> | |||||
<?php include('views/pagination.php'); ?> | |||||
</nav> | |||||
<div class="page-count-summary mb-0 mx-2 my-1"> | |||||
<?php echo $lang['page'] . " " . $page . " " . $lang['of'] . " " . $page_count; ?> | |||||
</div> | |||||
<?php | |||||
$col_count=0; | |||||
$i = 0; | |||||
$img_count = count($images); | |||||
foreach ($images as $image) { | |||||
if ($col_count % 3 == 0) { | |||||
echo "<div class=\"card-group capture-image-cards\">"; | |||||
} | |||||
// automatically append filename conventions | |||||
switch($image['sat_type']) { | |||||
case 0: // Meteor-M2 | |||||
$ending = "-122-rectified.jpg"; | |||||
break; | |||||
case 1: // NOAA | |||||
$ending = "-MCIR.jpg"; | |||||
break; | |||||
case 2: // ISS | |||||
$ending = "-0.png"; | |||||
break; | |||||
} | |||||
# build image path | |||||
$img_path = "/images/thumb/" . $image['file_path'] . $ending; | |||||
// output image and details, with link to respective enhancement images | |||||
echo "<div class=\"card bg-light m-2 p-2 image-card\">"; | |||||
echo " <a href=\"capture.php?id=" . $image['id'] . "\"><img class=\"card-img-top\" src=\"" . $img_path . "\" alt=\"img\"></a>"; | |||||
echo " <div class=\"card-body\">"; | |||||
echo " <h5 class=\"card-title\">" . $image['sat_name'] . "</h5>"; | |||||
echo " <p class=\"card-text\">"; | |||||
echo " <strong>" . $lang['elev'] . ":</strong> " . $image['max_elev'] . "°<br>"; | |||||
echo " <strong>" . $lang['pass_start'] . ":</strong> " . date('m/d/Y H:i:s', $image['pass_start']); | |||||
echo " </p>"; | |||||
echo " </div>"; | |||||
echo "</div>"; | |||||
$i++; | |||||
$col_count++; | |||||
if ($col_count % 3 == 0 or $i >= $img_count) { | |||||
echo "</div>"; | |||||
} | |||||
} | |||||
?> | |||||
<nav aria-label="page" id="pagination" class="d-md-none mb-0"> | |||||
<?php include('views/pagination.php'); ?> | |||||
</nav> |
@@ -1,39 +0,0 @@ | |||||
<link rel="stylesheet" type="text/css" href="css/captures.css"> | |||||
<?php | |||||
$col_count=0; | |||||
$i = 0; | |||||
$img_count = count($enhancements); | |||||
foreach ($enhancements as $enhancement) { | |||||
if ($col_count % 3 == 0) { | |||||
echo "<div class=\"card-group capture-image-cards\">"; | |||||
} | |||||
# build image path and enhancement text | |||||
$img_path = "/images/" . $path . $enhancement; | |||||
$thumb_path = "/images/thumb/" . $path . $enhancement; | |||||
$enhancement_text = "Unknown"; | |||||
preg_match("/-(.*).jpg/", $enhancement, $m); | |||||
if (isset($m[1])) { | |||||
$enhancement_text = $m[1]; | |||||
} | |||||
// output image and details, with link to respective enhancement images | |||||
echo "<div class=\"card bg-light m-2 p-2 image-card\">"; | |||||
echo " <a href=\"" . $img_path . "\"><img class=\"card-img-top\" src=\"" . $thumb_path . "\" alt=\"img\"></a>"; | |||||
echo " <div class=\"card-body\">"; | |||||
echo " <p class=\"card-text\">"; | |||||
echo " <strong>Enhancement: </strong>" . $enhancement_text; | |||||
echo " </p>"; | |||||
echo " </div>"; | |||||
echo "</div>"; | |||||
$i++; | |||||
$col_count++; | |||||
if ($col_count % 3 == 0 or $i >= $img_count) { | |||||
echo "</div>"; | |||||
} | |||||
} | |||||
?> |
@@ -1,14 +0,0 @@ | |||||
</div> | |||||
<footer class="footer text-center"> | |||||
<div class="contaienr"> | |||||
<a href="https://github.com/reynico/raspberry-noaa"><img class="img-footer" src="assets/web_img/logo-small.png"></a> | |||||
</div> | |||||
</footer> | |||||
<script src="https://code.jquery.com/jquery-3.5.1.slim.min.js" | |||||
integrity="sha384-DfXdz2htPH0lsSSs5nCTpuj/zy4C+OGpamoFVy38MVBnE+IbbVYUew+OrCXaRkfj" crossorigin="anonymous"></script> | |||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@4.6.0/dist/js/bootstrap.bundle.min.js" | |||||
integrity="sha384-Piv4xVNRyMGpqkS2by6br4gNJ7DXjqk09RmUpJ8jgGtD7zP9yug3goQfGII0yAns" crossorigin="anonymous"></script> | |||||
</body> | |||||
</html> |
@@ -1,47 +0,0 @@ | |||||
<?php | |||||
ini_set('display_errors', 1); | |||||
ini_set('display_startup_errors', 1); | |||||
error_reporting(E_ALL); | |||||
$page = basename($_SERVER['PHP_SELF']); | |||||
$configs = include('config.php'); | |||||
date_default_timezone_set($configs->timezone); | |||||
$lang = $configs->lang; | |||||
include_once('i18n/' . $lang . '.php'); | |||||
?> | |||||
<!DOCTYPE html> | |||||
<html lang="en"> | |||||
<head> | |||||
<meta charset="UTF-8"> | |||||
<meta name="viewport" content="width=device-width, initial-scale=1.0"> | |||||
<meta http-equiv="X-UA-Compatible" content="ie=edge"> | |||||
<link rel="stylesheet" type="text/css" href="css/header.css"> | |||||
<link rel="stylesheet" type="text/css" href="css/footer.css"> | |||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.6.0/dist/css/bootstrap.min.css" | |||||
integrity="sha384-B0vP5xmATw1+K9KRQjQERJvTumQW0nPEzvF6L/Z6nronJ3oUOFUFpCjEUQouq2+l" crossorigin="anonymous"> | |||||
<title>Raspberry NOAA V2</title> | |||||
<link rel="shortcut icon" href="assets/web_img/favicon.ico" type="image/x-icon"/> | |||||
</head> | |||||
<body> | |||||
<header class="mb-3"> | |||||
<div class="navbar navbar-expand navbar-dark bg-dark"> | |||||
<ul class="navbar-nav mr-auto"> | |||||
<li class="nav-item <?php if($page == 'index.php'){ echo 'active'; }?>"> | |||||
<a class="nav-link" href="index.php"><?php echo $lang['passes']; ?></a> | |||||
</li> | |||||
<li class="nav-item <?php if($page == 'captures.php' or $page == 'capture.php'){ echo 'active'; }?>"> | |||||
<a class="nav-link" href="captures.php"><?php echo $lang['captures']; ?></a> | |||||
</li> | |||||
</ul> | |||||
<span class="navbar-text timezone"> | |||||
<em> | |||||
<?php echo $configs->timezone; ?><br> | |||||
(UTC<?php echo date('P'); ?>) | |||||
</em> | |||||
</span> | |||||
</div> | |||||
</header> | |||||
<div class="container"> |
@@ -1,17 +0,0 @@ | |||||
<nav aria-label="page" id="pagination" class="mb-0"> | |||||
<ul class="pagination pagination-sm justify-content-center mb-0 mx-2"> | |||||
<li class="page-item<?php if ($page <= 1) { echo " disabled"; } ?>"> | |||||
<a class="page-link" href="<?php echo "?page=" . ($page-1); ?>" aria-label="<?php echo $lang['prev']; ?>"> | |||||
<span aria-hiden="true">«</span> | |||||
<span><?php echo $lang['prev']; ?></span> | |||||
</a> | |||||
</li> | |||||
<li class="page-item<?php if ($page >= $page_count) { echo " disabled"; } ?>"> | |||||
<a class="page-link" href="<?php echo "?page=" . ($page+1); ?>" aria-label="<?php echo $lang['next']; ?>"> | |||||
<span><?php echo $lang['next']; ?></span> | |||||
<span aria-hiden="true">»</span> | |||||
</a> | |||||
</li> | |||||
</ul> | |||||
</nav> |
@@ -1,41 +0,0 @@ | |||||
<link rel="stylesheet" type="text/css" href="css/pass_list.css"> | |||||
<table class="table table-bordered table-sm table-striped" id="passes"> | |||||
<thead class="thead-dark"> | |||||
<tr class="text-center"> | |||||
<th scope="col"><?php echo $lang['satellite']; ?></th> | |||||
<th scope="col"><?php echo $lang['pass_start']; ?></th> | |||||
<th scope="col"><?php echo $lang['pass_end']; ?></th> | |||||
<th scope="col"><?php echo $lang['max_elev']; ?></th> | |||||
</tr> | |||||
</thead> | |||||
<tbody> | |||||
<?php | |||||
$now = date('H:i:s', time()); | |||||
# account for no passes currently scheduled | |||||
if (count($passes) <= 0) { | |||||
echo "<tr><td colspan=\"4\" class=\"no-passes\">0 " . $lang['passes'] . "</td></tr>"; | |||||
} else { | |||||
foreach ($passes as $pass) { | |||||
$pass_start = date('H:i:s', $pass['pass_start']); | |||||
$pass_end = date('H:i:s', $pass['pass_end']); | |||||
# gray out anything that has already run or did not run because there | |||||
# was another overlapping capture but is now in the past | |||||
if ($pass['is_active'] == false or $pass_end < $now) { | |||||
echo "<tr class='inactive'>"; | |||||
} else { | |||||
echo "<tr>"; | |||||
} | |||||
echo "<td scope=\"row\">". $pass['sat_name'] ."</td>"; | |||||
echo "<td scope=\"row\" class=\"text-center\">" . $pass_start ."</td>"; | |||||
echo "<td scope=\"row\" class=\"text-center\">" . $pass_end . "</td>"; | |||||
echo "<td scope=\"row\" class=\"text-center\">" . $pass['max_elev'] ."°</td>"; | |||||
echo "</tr>"; | |||||
} | |||||
} | |||||
?> | |||||
</tbody> | |||||
</table> |