Merge pull request #15 from Programvareverkstedet/doorsensor
Uploaded door sensor
This commit is contained in:
commit
8fd03c9824
|
@ -38,15 +38,12 @@ CREATE TABLE "motd" (
|
|||
INSERT INTO motd (title, content)
|
||||
VALUES ("MOTD ./dev.sh", "du kan endre motd i admin panelet");
|
||||
|
||||
CREATE TABLE "doors" (
|
||||
"name" TEXT PRIMARY KEY,
|
||||
"open" BOOLEAN,
|
||||
"description" TEXT
|
||||
CREATE TABLE "door" (
|
||||
"time" INTEGER PRIMARY KEY,
|
||||
"open" BOOLEAN
|
||||
);
|
||||
INSERT INTO doors(name, open, description) VALUES
|
||||
("koserommet", FALSE, "Døra inn til koserommet på stripa"),
|
||||
("terminalrommet", FALSE, "Døra inn til terminalrommet på stripa");
|
||||
|
||||
INSERT INTO door (time, open)
|
||||
VALUES (0, FALSE);
|
||||
|
||||
|
||||
INSERT INTO users (uname, groups)
|
||||
|
|
|
@ -40,11 +40,8 @@ INSERT INTO motd (title, content)
|
|||
VALUES ("MOTD ./dev.sh", "du kan endre motd i admin panelet");
|
||||
*/
|
||||
|
||||
CREATE TABLE doors (
|
||||
`name` VARCHAR(20) PRIMARY KEY,
|
||||
`open` BOOLEAN,
|
||||
`description` TEXT
|
||||
CREATE TABLE door (
|
||||
`time` INTEGER PRIMARY KEY,
|
||||
`open` BOOLEAN
|
||||
);
|
||||
INSERT INTO doors(name, open, description) VALUES
|
||||
("koserommet", FALSE, "Døra inn til koserommet på stripa"),
|
||||
("terminalrommet", FALSE, "Døra inn til terminalrommet på stripa");
|
||||
INSERT INTO door(time, open) VALUES (0, FALSE);
|
|
@ -3,3 +3,4 @@ $dbDsn = 'sqlite:'.__DIR__.DIRECTORY_SEPARATOR.'pvv.sqlite';
|
|||
$dbUser = null;
|
||||
$dbPass = null;
|
||||
|
||||
$doorSensorSecret = "OGJiZTdjZDctMmFkNy00ZjZjLTk3OGItOTA3NzU3ZDM2Yjlm";
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -153,6 +153,16 @@ nav #usermenu li:first-child:hover {
|
|||
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){
|
||||
nav #menu, nav #menu li.active, nav #menu_toggle, nav #login {
|
||||
position: absolute;
|
||||
|
@ -226,6 +236,9 @@ nav #usermenu li:first-child:hover {
|
|||
margin-left: 1em !important;
|
||||
margin-right: 1em !important;
|
||||
}
|
||||
.doorStateMobileOnly {
|
||||
display: inline;
|
||||
}
|
||||
}
|
||||
|
||||
body {
|
||||
|
@ -346,3 +359,4 @@ article p {
|
|||
textarea.boxinput {
|
||||
resize: vertical;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,49 +1,73 @@
|
|||
<?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');
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'GET') {
|
||||
if (isset($_GET["name"])) {
|
||||
$out = $doors->getByName($_GET["name"]);
|
||||
if (!$out) {
|
||||
echo '{"error": true, "reason": "not found"}';
|
||||
http_response_code(404);
|
||||
exit();
|
||||
$door = new \pvv\side\Door($pdo);
|
||||
|
||||
if($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
if (isset($_SERVER["HTTP_AUTHORIZATION"])) {
|
||||
list($type, $data) = explode(" ", $_SERVER["HTTP_AUTHORIZATION"], 2);
|
||||
if (strcasecmp($type, "Bearer") == 0) {
|
||||
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 {
|
||||
$out = $doors->getAll();
|
||||
}
|
||||
}
|
||||
elseif ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
if (isset($_POST["name"]) and isset($_POST["open"]) ) {
|
||||
$out = $doors->setDoorState($_POST["name"], (strtolower($_POST["open"])==="true")?1:0);
|
||||
|
||||
$out = $doors->getByName($_POST["name"]);
|
||||
if (!$out) {
|
||||
echo '{"error": true, "reason": "not found"}';
|
||||
http_response_code(404);
|
||||
exit();
|
||||
} elseif ($_SERVER['REQUEST_METHOD'] === 'GET') {
|
||||
|
||||
if (isset($_GET["period"])) {
|
||||
$period = (string)htmlspecialchars($_GET["period"]);
|
||||
if ($period == "day") {
|
||||
$startTime = time() - (60*60*24);
|
||||
} else if ($period == "week") {
|
||||
$startTime = time() - (60*60*24*7);
|
||||
} else {
|
||||
echo '{"status": "error", "message": "Invalid period"}';
|
||||
die();
|
||||
}
|
||||
}
|
||||
else {
|
||||
echo '{"error": true, "reason": "missing either \"name\" or \"open\" argument"}';
|
||||
http_response_code(404);
|
||||
exit();
|
||||
|
||||
$lines = $door->getEntriesAfter($startTime);
|
||||
echo json_encode([
|
||||
'status' => "OK",
|
||||
'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"}';
|
||||
}
|
|
@ -7,6 +7,12 @@ $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
|
|||
|
||||
$motdfetcher = new \pvv\side\MOTD($pdo);
|
||||
$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>
|
||||
<html lang="no">
|
||||
|
@ -63,6 +69,10 @@ $motd = $motdfetcher->getMOTD();
|
|||
<a class="btn" href="om/"><li>Om PVV</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¢er=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>
|
||||
</div>
|
||||
</header>
|
||||
|
|
Reference in New Issue