Merge pull request #15 from Programvareverkstedet/doorsensor

Uploaded door sensor
This commit is contained in:
Peder Bergebakken Sundt 2021-09-08 22:23:37 +02:00 committed by GitHub
commit 8fd03c9824
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 170 additions and 132 deletions

13
dist/pvv.sql vendored
View File

@ -38,15 +38,12 @@ CREATE TABLE "motd" (
INSERT INTO motd (title, content) INSERT INTO motd (title, content)
VALUES ("MOTD ./dev.sh", "du kan endre motd i admin panelet"); VALUES ("MOTD ./dev.sh", "du kan endre motd i admin panelet");
CREATE TABLE "doors" ( CREATE TABLE "door" (
"name" TEXT PRIMARY KEY, "time" INTEGER PRIMARY KEY,
"open" BOOLEAN, "open" BOOLEAN
"description" TEXT
); );
INSERT INTO doors(name, open, description) VALUES INSERT INTO door (time, open)
("koserommet", FALSE, "Døra inn til koserommet på stripa"), VALUES (0, FALSE);
("terminalrommet", FALSE, "Døra inn til terminalrommet på stripa");
INSERT INTO users (uname, groups) INSERT INTO users (uname, groups)

11
dist/pvv_mysql.sql vendored
View File

@ -40,11 +40,8 @@ INSERT INTO motd (title, content)
VALUES ("MOTD ./dev.sh", "du kan endre motd i admin panelet"); VALUES ("MOTD ./dev.sh", "du kan endre motd i admin panelet");
*/ */
CREATE TABLE doors ( CREATE TABLE door (
`name` VARCHAR(20) PRIMARY KEY, `time` INTEGER PRIMARY KEY,
`open` BOOLEAN, `open` BOOLEAN
`description` TEXT
); );
INSERT INTO doors(name, open, description) VALUES INSERT INTO door(time, open) VALUES (0, FALSE);
("koserommet", FALSE, "Døra inn til koserommet på stripa"),
("terminalrommet", FALSE, "Døra inn til terminalrommet på stripa");

View File

@ -3,3 +3,4 @@ $dbDsn = 'sqlite:'.__DIR__.DIRECTORY_SEPARATOR.'pvv.sqlite';
$dbUser = null; $dbUser = null;
$dbPass = null; $dbPass = null;
$doorSensorSecret = "OGJiZTdjZDctMmFkNy00ZjZjLTk3OGItOTA3NzU3ZDM2Yjlm";

74
src/pvv/side/door.php Normal file
View File

@ -0,0 +1,74 @@
<?php
namespace pvv\side;
use \PDO;
class Door{
private $pdo;
public function __construct(PDO $pdo){
$this->pdo = $pdo;
}
public function getAll() {
$query = 'SELECT time, open FROM door ORDER BY time DESC';
$statement = $this->pdo->prepare($query);
$statement->execute();
$doorEvents = [];
foreach($statement->fetchAll() as $row){
$doorEvents[] = [
'time' => (int)$row['time'],
'open' => (bool)$row['open']
];
}
return $doorEvents;
}
public function getEntriesAfter($startTime) {
$query = 'SELECT time, open FROM door WHERE time > :startTime ORDER BY time DESC';
$statement = $this->pdo->prepare($query);
$statement->bindParam(':startTime', $startTime, PDO::PARAM_STR);
$statement->execute();
$doorEvents = [];
foreach($statement->fetchAll() as $row){
$doorEvents[] = [
'time' => (int)$row['time'],
'open' => (bool)$row['open']
];
}
return $doorEvents;
}
public function getCurrent() {
$query = 'SELECT time, open FROM door ORDER BY time DESC LIMIT 1';
$statement = $this->pdo->prepare($query);
$statement->execute();
$row = $statement->fetch();
return [
'time' => (int)$row['time'],
'open' => (bool)$row['open']
];
}
private function removeOld() {
$firstValidTime = time() - 60*60*24*7; //One week before now
$query = 'DELETE FROM door WHERE time < :firstValid';
$statement = $this->pdo->prepare($query);
$statement->bindParam(':firstValid', $firstValidTime, PDO::PARAM_STR);
$statement->execute();
}
public function createEvent($time, $open) {
$query = 'INSERT INTO door(time, open) VALUES (:time, :open)';
$statement = $this->pdo->prepare($query);
$statement->bindParam(':time', $time, PDO::PARAM_STR);
$statement->bindParam(':open', $open, PDO::PARAM_STR);
$statement->execute();
$this->removeOld();
}
}

View File

@ -1,79 +0,0 @@
<?php
namespace pvv\side;
use \PDO;
class Doors{
private $pdo;
public function __construct(PDO $pdo){
$this->pdo = $pdo;
}
public function getAll() {
$query = 'SELECT name, open, description FROM doors ORDER BY open DESC, name ASC';
$statement = $this->pdo->prepare($query);
$statement->execute();
$doors = [];
foreach($statement->fetchAll() as $row){
$doors[] = [
'name' => $row['name'],
'open' => (int)$row['open'],
'description' => $row['description'],
];
}
return $doors;
}
public function getByName($name){
$query = 'SELECT name, open, description FROM doors WHERE name=:name';
$statement = $this->pdo->prepare($query);
$statement->bindParam(':name', $name, PDO::PARAM_STR);
$statement->execute();
$row = $statement->fetch();
if (!$row) {
return false;
}
return [
'name' => $row['name'],
'open' => (int)$row['open'],
'description' => $row['description'],
];
}
public function setDoorState($name, $open) {
$query = 'UPDATE doors SET open=:open WHERE name=:name';
$statement = $this->pdo->prepare($query);
$statement->bindParam(':name', $name, PDO::PARAM_STR);
$statement->bindParam(':open', $open, PDO::PARAM_INT);
$statement->execute();
}
public function createDoor($name, $description) {
$query = 'INSERT INTO doors(name, open, description) VALUES (:name, TRUE, :desc)';
$statement = $this->pdo->prepare($query);
$statement->bindParam(':name', $name, PDO::PARAM_STR);
$statement->bindParam(':desc', $description, PDO::PARAM_STR);
$statement->execute();
}
public function updateDoorDescription($name, $description) {
$query = 'UPDATE doors SET descriptin=:desc WHERE name=:name';
$statement = $this->pdo->prepare($query);
$statement->bindParam(':name', $name, PDO::PARAM_STR);
$statement->bindParam(':desc', $description, PDO::PARAM_STR);
$statement->execute();
}
public function deleteDoor($name) {
$query = 'DELETE FROM doors WHERE name = :name;';
$statement = $this->pdo->prepare($query);
$statement->bindParam(':name', $name, PDO::PARAM_STR);
$statement->execute();
}
}

View File

@ -153,6 +153,16 @@ nav #usermenu li:first-child:hover {
background: transparent; background: transparent;
} }
#doorIndicator {
border-radius: 5px;
padding: 8px 8px;
margin: 4px 4px;
}
#doorIndicator > p > abbr[title] { text-decoration: none; border-bottom: none; cursor: inherit; }
.doorIndicator_OPEN { border: 2px solid green; }
.doorIndicator_CLOSED { border: 2px dotted red; }
.doorStateMobileOnly { display: none; }
@media(max-width: 800px){ @media(max-width: 800px){
nav #menu, nav #menu li.active, nav #menu_toggle, nav #login { nav #menu, nav #menu li.active, nav #menu_toggle, nav #login {
position: absolute; position: absolute;
@ -226,6 +236,9 @@ nav #usermenu li:first-child:hover {
margin-left: 1em !important; margin-left: 1em !important;
margin-right: 1em !important; margin-right: 1em !important;
} }
.doorStateMobileOnly {
display: inline;
}
} }
body { body {
@ -346,3 +359,4 @@ article p {
textarea.boxinput { textarea.boxinput {
resize: vertical; resize: vertical;
} }

View File

@ -1,49 +1,73 @@
<?php <?php
require_once dirname(dirname(__DIR__)) . implode(DIRECTORY_SEPARATOR, ['', 'inc', 'include.php']); require_once dirname(dirname(__DIR__)) . implode(DIRECTORY_SEPARATOR, ['', 'inc', 'include.php']);
$doors = new \pvv\side\Doors($pdo);
$out = null;
header('Content-Type: application/json'); header('Content-Type: application/json');
if ($_SERVER['REQUEST_METHOD'] === 'GET') { $door = new \pvv\side\Door($pdo);
if (isset($_GET["name"])) {
$out = $doors->getByName($_GET["name"]); if($_SERVER['REQUEST_METHOD'] === 'POST') {
if (!$out) { if (isset($_SERVER["HTTP_AUTHORIZATION"])) {
echo '{"error": true, "reason": "not found"}'; list($type, $data) = explode(" ", $_SERVER["HTTP_AUTHORIZATION"], 2);
http_response_code(404); if (strcasecmp($type, "Bearer") == 0) {
exit(); if (hash_equals($data, $doorSensorSecret)) {
handleSetState();
} else {
echo '{"status": "error", "message": "Invalid authentication key"}';
die();
}
} else {
echo '{"status": "error", "message": "Invalid authentication method"}';
die();
} }
} else {
echo '{"status": "error", "message": "Missing authentication"}';
die();
} }
else { } elseif ($_SERVER['REQUEST_METHOD'] === 'GET') {
$out = $doors->getAll();
} if (isset($_GET["period"])) {
} $period = (string)htmlspecialchars($_GET["period"]);
elseif ($_SERVER['REQUEST_METHOD'] === 'POST') { if ($period == "day") {
if (isset($_POST["name"]) and isset($_POST["open"]) ) { $startTime = time() - (60*60*24);
$out = $doors->setDoorState($_POST["name"], (strtolower($_POST["open"])==="true")?1:0); } else if ($period == "week") {
$startTime = time() - (60*60*24*7);
$out = $doors->getByName($_POST["name"]); } else {
if (!$out) { echo '{"status": "error", "message": "Invalid period"}';
echo '{"error": true, "reason": "not found"}'; die();
http_response_code(404);
exit();
} }
}
else { $lines = $door->getEntriesAfter($startTime);
echo '{"error": true, "reason": "missing either \"name\" or \"open\" argument"}'; echo json_encode([
http_response_code(404); 'status' => "OK",
exit(); 'entries' => $lines
]);
} else {
//Only last entry
$line = (object)$door->getCurrent();
echo json_encode([
'status' => "OK",
'time' => $line->time,
'open' => $line->open
]);
} }
} }
function utf8ize($d) {
if (is_array($d)) {
foreach ($d as $k => $v) {
$d[$k] = utf8ize($v);
}
} else if (is_string ($d)) {
return utf8_encode($d);
}
return $d;
}
echo json_encode(utf8ize($out)); function handleSetState() {
global $door;
$jsonobj = file_get_contents('php://input');
$event = json_decode($jsonobj);
if ((!isset($event->time)) || (!is_numeric($event->time))) {
echo '{"status": "error", "message": "Invalid timestamp"}';
die();
}
if ((!isset($event->isDoorOpen)) || (!is_bool($event->isDoorOpen))) {
echo '{"status": "error", "message": "Invalid door state"}';
die();
}
$door->createEvent((int)($event->time), (bool)($event->isDoorOpen));
echo '{"status": "OK"}';
}

View File

@ -7,6 +7,12 @@ $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$motdfetcher = new \pvv\side\MOTD($pdo); $motdfetcher = new \pvv\side\MOTD($pdo);
$motd = $motdfetcher->getMOTD(); $motd = $motdfetcher->getMOTD();
$door = new \pvv\side\Door($pdo);
$doorEntry = (object)($door->getCurrent());
$isDoorOpen = $doorEntry->open;
if (date("Y-m-d") == date("Y-m-d", $doorEntry->time)) { $doorTime = date("H:i", $doorEntry->time);
} else { $doorTime = date("H:i d/m", $doorEntry->time);}
?> ?>
<!DOCTYPE html> <!DOCTYPE html>
<html lang="no"> <html lang="no">
@ -63,6 +69,10 @@ $motd = $motdfetcher->getMOTD();
<a class="btn" href="om/"><li>Om PVV</li></a> <a class="btn" href="om/"><li>Om PVV</li></a>
<a class="btn focus" href="paamelding/"><li>Bli medlem!</li></a> <a class="btn focus" href="paamelding/"><li>Bli medlem!</li></a>
<a class="btn" href="https://use.mazemap.com/#config=ntnu&v=1&zlevel=2&center=10.406281,63.417093&zoom=19.5&campuses=ntnu&campusid=1&sharepoitype=poi&sharepoi=38159&utm_medium=longurl">Veibeskrivelse</li></a> <a class="btn" href="https://use.mazemap.com/#config=ntnu&v=1&zlevel=2&center=10.406281,63.417093&zoom=19.5&campuses=ntnu&campusid=1&sharepoitype=poi&sharepoi=38159&utm_medium=longurl">Veibeskrivelse</li></a>
<div id="doorIndicator" class="<?php echo($isDoorOpen ? "doorIndicator_OPEN" : "doorIndicator_CLOSED"); ?>">
<p class="doorStateText"><abbr title="Oppdatert <?php echo($doorTime) ?>">Døren er <b><?php echo($isDoorOpen ? "" : "ikke") ?> åpen</b>.</abbr></p>
<p class="doorStateTime doorStateMobileOnly">(Oppdatert <?php echo($doorTime) ?>)</p>
</div>
</ul> </ul>
</div> </div>
</header> </header>