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 | |||
$lang = array( | |||
return array( | |||
"captures" => "يلتقط", | |||
"elev" => "الإرتفاع", | |||
"images" => "الصور", |
@@ -1,5 +1,5 @@ | |||
<?php | |||
$lang = array( | |||
return array( | |||
"captures" => "Erfasst", | |||
"elev" => "Erhebung", | |||
"images" => "Bilder", |
@@ -1,5 +1,5 @@ | |||
<?php | |||
$lang = array( | |||
return array( | |||
"captures" => "Captures", | |||
"elev" => "Elevation", | |||
"images" => "Images", |
@@ -1,5 +1,5 @@ | |||
<?php | |||
$lang = array( | |||
return array( | |||
"captures" => "Capturas", | |||
"elev" => "Elevación", | |||
"images" => "Imagenes", |
@@ -1,5 +1,5 @@ | |||
<?php | |||
$lang = array( | |||
return array( | |||
"captures" => "Hvatanja", | |||
"elev" => "Visina", | |||
"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> |