From 090b9f7a7b812a1d77671910babe9049b8248eab Mon Sep 17 00:00:00 2001 From: JonatanRek Date: Sat, 16 May 2020 17:18:27 +0200 Subject: [PATCH] CleanUp After Docker Try --- www/.htaccess => .htaccess | 1 + ...DITOR_ TEST.php => New_JS_EDITOR_ TEST.php | 0 www/api.php => api.php | 0 app/Bootstrap.php | 93 +++++++ app/Routes.php | 31 +++ app/api/AuthApi.php | 25 ++ app/api/DevicesApi.php | 17 ++ app/api/ExampleApi.php | 24 ++ app/api/GoogleHomeApi.php | 46 ++++ {www/app => app}/api/RoomsApi.php | 0 app/controllers/ExampleController.php | 14 + app/controllers/automationController.php | 77 ++++++ app/controllers/loginController.php | 51 ++++ app/controllers/settingController.php | 29 ++ app/models/AuthManager.php | 45 +++ app/models/AutomationManager.php | 175 ++++++++++++ app/models/ChartJS.php | 194 +++++++++++++ app/models/ChartJS_Line.php | 21 ++ app/models/ChartManager.php | 129 +++++++++ app/models/DashboardManager.php | 41 +++ app/models/DeviceManager.php | 96 +++++++ app/models/FallbackManager.php | 44 +++ {www/library => app/models}/Form.php | 0 app/models/GoogleHome.php | 260 ++++++++++++++++++ app/models/LanguageManager.php | 60 ++++ app/models/LogManager.php | 57 ++++ app/models/NetworkManager.php | 18 ++ app/models/NotificationManager.php | 107 +++++++ {www/library => app/models}/Partial.php | 0 app/models/RecordManager.php | 106 +++++++ app/models/RoomManager.php | 31 +++ app/models/SceneManager.php | 41 +++ app/models/UserManager.php | 210 ++++++++++++++ app/models/Utilities.php | 144 ++++++++++ app/models/managers/AuthManager.php | 45 +++ app/models/managers/AutomationManager.php | 175 ++++++++++++ app/models/managers/ChartManager.php | 129 +++++++++ app/models/managers/DashboardManager.php | 41 +++ app/models/managers/DeviceManager.php | 96 +++++++ app/models/managers/FallbackManager.php | 44 +++ app/models/managers/LanguageManager.php | 60 ++++ app/models/managers/LogManager.php | 57 ++++ app/models/managers/NetworkManager.php | 18 ++ app/models/managers/NotificationManager.php | 107 +++++++ app/models/managers/RecordManager.php | 106 +++++++ app/models/managers/RoomManager.php | 36 +++ app/models/managers/SceneManager.php | 41 +++ app/models/managers/SubDeviceManager.php | 97 +++++++ app/models/managers/UserManager.php | 210 ++++++++++++++ app/models/managers/Utilities.php | 144 ++++++++++ app/models/types/GoogleHomeDeviceTypes.php | 107 +++++++ app/models/types/WidgetTypes.php | 45 +++ app/views/Ajax.php | 223 +++++++++++++++ app/views/Automation.php | 66 +++++ app/views/Log.php | 63 +++++ app/views/Login.php | 22 ++ app/views/Logout.php | 11 + app/views/Setting.php | 62 +++++ app/views/layouts/default.phtml | 20 ++ app/views/templates/automation.phtml | 66 +++++ app/views/templates/example.phtml | 1 + .../css => app/views/templates}/loading.css | 0 app/views/templates/log.phtml | 70 +++++ app/views/templates/login.phtml | 27 ++ .../templates/part/automationButton.phtml | 70 +++++ .../templates/part/automationCreate.phtml | 69 +++++ .../part/automationCreateFinal.phtml | 44 +++ app/views/templates/part/automationEdit.phtml | 85 ++++++ app/views/templates/part/footer.phtml | 5 + app/views/templates/part/head.phtml | 26 ++ app/views/templates/part/loginForm.phtml | 20 ++ app/views/templates/part/loginOta.phtml | 13 + app/views/templates/part/menu.phtml | 35 +++ app/views/templates/part/test.phtml | 3 + app/views/templates/setting.phtml | 203 ++++++++++++++ app/views/templates/template.phtml | 11 + {www/config => config}/config_sample.php | 0 www/docker-compose.yml => docker-compose.yml | 0 {www/lang => lang}/cs.php | 0 {www/lang => lang}/en.php | 0 {www/lang => lang}/nl.php | 0 {www/lang => lang}/pl.php | 0 {www/library => library}/ApiController.php | 0 {www/library => library}/Controller.php | 0 {www/library => library}/DB.php | 0 library/Partial.php | 34 +++ {www/library => library}/Router.php | 0 {www/library => library}/Template.php | 0 {www/library => library}/View.php | 0 .../vendor/GoogleAuthenticator.php | 0 .../vendor/PHPGangsta_GoogleAuthenticator.php | 252 +++++++++++++++++ {www/logs => logs}/.gitkeep | 0 www/manifest.json => manifest.json | 0 {www/public => public}/.htaccess | 0 .../Elementum/scss/elements/_buttons.scss | 0 .../css/font-awesome.min.css | 0 public/css/loading.css | 19 ++ {www/public => public}/css/main.css | 0 {www/public => public}/css/main.css.map | 0 {www/public => public}/css/modal.css | 0 {www/public => public}/css/override.css | 0 {www/public => public}/css/pre.css | 0 {www/public => public}/fonts/FontAwesome.otf | Bin .../fonts/Metropolis-Medium.otf | Bin .../fonts/Metropolis-Regular.otf | Bin .../fonts/Metropolis-SemiBold.otf | Bin .../fonts/fontawesome-webfont.eot | Bin .../fonts/fontawesome-webfont.svg | 0 .../fonts/fontawesome-webfont.ttf | Bin .../fonts/fontawesome-webfont.woff | Bin .../fonts/fontawesome-webfont.woff2 | Bin .../public => public}/images/icon-192x192.png | Bin .../public => public}/images/icon-512x512.png | Bin {www/public => public}/index.php | 0 {www/public => public}/js/automation.js | 0 {www/public => public}/js/jquery.js | 0 {www/public => public}/js/jquery.redirect.js | 0 {www/public => public}/js/post.js | 0 {www/public => public}/js/script.js | 0 {www/public => public}/js/setting.js | 0 www/serviceWorker.js => serviceWorker.js | 0 www/update.php => update.php | 0 {www/updater => updater}/.gitkeep | 0 123 files changed, 5265 insertions(+) rename www/.htaccess => .htaccess (93%) rename www/New_JS_EDITOR_ TEST.php => New_JS_EDITOR_ TEST.php (100%) rename www/api.php => api.php (100%) create mode 100644 app/Bootstrap.php create mode 100644 app/Routes.php create mode 100644 app/api/AuthApi.php create mode 100644 app/api/DevicesApi.php create mode 100644 app/api/ExampleApi.php create mode 100644 app/api/GoogleHomeApi.php rename {www/app => app}/api/RoomsApi.php (100%) create mode 100644 app/controllers/ExampleController.php create mode 100644 app/controllers/automationController.php create mode 100644 app/controllers/loginController.php create mode 100644 app/controllers/settingController.php create mode 100644 app/models/AuthManager.php create mode 100644 app/models/AutomationManager.php create mode 100644 app/models/ChartJS.php create mode 100644 app/models/ChartJS_Line.php create mode 100644 app/models/ChartManager.php create mode 100644 app/models/DashboardManager.php create mode 100644 app/models/DeviceManager.php create mode 100644 app/models/FallbackManager.php rename {www/library => app/models}/Form.php (100%) create mode 100644 app/models/GoogleHome.php create mode 100644 app/models/LanguageManager.php create mode 100644 app/models/LogManager.php create mode 100644 app/models/NetworkManager.php create mode 100644 app/models/NotificationManager.php rename {www/library => app/models}/Partial.php (100%) create mode 100644 app/models/RecordManager.php create mode 100644 app/models/RoomManager.php create mode 100644 app/models/SceneManager.php create mode 100644 app/models/UserManager.php create mode 100644 app/models/Utilities.php create mode 100644 app/models/managers/AuthManager.php create mode 100644 app/models/managers/AutomationManager.php create mode 100644 app/models/managers/ChartManager.php create mode 100644 app/models/managers/DashboardManager.php create mode 100644 app/models/managers/DeviceManager.php create mode 100644 app/models/managers/FallbackManager.php create mode 100644 app/models/managers/LanguageManager.php create mode 100644 app/models/managers/LogManager.php create mode 100644 app/models/managers/NetworkManager.php create mode 100644 app/models/managers/NotificationManager.php create mode 100644 app/models/managers/RecordManager.php create mode 100644 app/models/managers/RoomManager.php create mode 100644 app/models/managers/SceneManager.php create mode 100644 app/models/managers/SubDeviceManager.php create mode 100644 app/models/managers/UserManager.php create mode 100644 app/models/managers/Utilities.php create mode 100644 app/models/types/GoogleHomeDeviceTypes.php create mode 100644 app/models/types/WidgetTypes.php create mode 100644 app/views/Ajax.php create mode 100644 app/views/Automation.php create mode 100644 app/views/Log.php create mode 100644 app/views/Login.php create mode 100644 app/views/Logout.php create mode 100644 app/views/Setting.php create mode 100644 app/views/layouts/default.phtml create mode 100644 app/views/templates/automation.phtml create mode 100644 app/views/templates/example.phtml rename {www/public/css => app/views/templates}/loading.css (100%) create mode 100644 app/views/templates/log.phtml create mode 100644 app/views/templates/login.phtml create mode 100644 app/views/templates/part/automationButton.phtml create mode 100644 app/views/templates/part/automationCreate.phtml create mode 100644 app/views/templates/part/automationCreateFinal.phtml create mode 100644 app/views/templates/part/automationEdit.phtml create mode 100644 app/views/templates/part/footer.phtml create mode 100644 app/views/templates/part/head.phtml create mode 100644 app/views/templates/part/loginForm.phtml create mode 100644 app/views/templates/part/loginOta.phtml create mode 100644 app/views/templates/part/menu.phtml create mode 100644 app/views/templates/part/test.phtml create mode 100644 app/views/templates/setting.phtml create mode 100644 app/views/templates/template.phtml rename {www/config => config}/config_sample.php (100%) rename www/docker-compose.yml => docker-compose.yml (100%) rename {www/lang => lang}/cs.php (100%) rename {www/lang => lang}/en.php (100%) rename {www/lang => lang}/nl.php (100%) rename {www/lang => lang}/pl.php (100%) rename {www/library => library}/ApiController.php (100%) rename {www/library => library}/Controller.php (100%) rename {www/library => library}/DB.php (100%) create mode 100644 library/Partial.php rename {www/library => library}/Router.php (100%) rename {www/library => library}/Template.php (100%) rename {www/library => library}/View.php (100%) rename www/library/vendor/PHPGangsta_GoogleAuthenticator.php => library/vendor/GoogleAuthenticator.php (100%) create mode 100644 library/vendor/PHPGangsta_GoogleAuthenticator.php rename {www/logs => logs}/.gitkeep (100%) rename www/manifest.json => manifest.json (100%) rename {www/public => public}/.htaccess (100%) rename {www/public => public}/Elementum/scss/elements/_buttons.scss (100%) rename {www/public => public}/css/font-awesome.min.css (100%) create mode 100644 public/css/loading.css rename {www/public => public}/css/main.css (100%) rename {www/public => public}/css/main.css.map (100%) rename {www/public => public}/css/modal.css (100%) rename {www/public => public}/css/override.css (100%) rename {www/public => public}/css/pre.css (100%) rename {www/public => public}/fonts/FontAwesome.otf (100%) rename {www/public => public}/fonts/Metropolis-Medium.otf (100%) rename {www/public => public}/fonts/Metropolis-Regular.otf (100%) rename {www/public => public}/fonts/Metropolis-SemiBold.otf (100%) rename {www/public => public}/fonts/fontawesome-webfont.eot (100%) rename {www/public => public}/fonts/fontawesome-webfont.svg (100%) rename {www/public => public}/fonts/fontawesome-webfont.ttf (100%) rename {www/public => public}/fonts/fontawesome-webfont.woff (100%) rename {www/public => public}/fonts/fontawesome-webfont.woff2 (100%) rename {www/public => public}/images/icon-192x192.png (100%) rename {www/public => public}/images/icon-512x512.png (100%) rename {www/public => public}/index.php (100%) rename {www/public => public}/js/automation.js (100%) rename {www/public => public}/js/jquery.js (100%) rename {www/public => public}/js/jquery.redirect.js (100%) rename {www/public => public}/js/post.js (100%) rename {www/public => public}/js/script.js (100%) rename {www/public => public}/js/setting.js (100%) rename www/serviceWorker.js => serviceWorker.js (100%) rename www/update.php => update.php (100%) rename {www/updater => updater}/.gitkeep (100%) diff --git a/www/.htaccess b/.htaccess similarity index 93% rename from www/.htaccess rename to .htaccess index 54bbdf8..71ae402 100644 --- a/www/.htaccess +++ b/.htaccess @@ -10,6 +10,7 @@ RewriteRule . - [e=HTTP_AUTHORIZATION:%1] # serve all files from public subfolder RewriteCond %{REQUEST_FILENAME} !.php +RewriteCond %{REQUEST_FILENAME} !.log RewriteCond %{REQUEST_FILENAME} \. RewriteRule (.*) ./public/$1 [L] diff --git a/www/New_JS_EDITOR_ TEST.php b/New_JS_EDITOR_ TEST.php similarity index 100% rename from www/New_JS_EDITOR_ TEST.php rename to New_JS_EDITOR_ TEST.php diff --git a/www/api.php b/api.php similarity index 100% rename from www/api.php rename to api.php diff --git a/app/Bootstrap.php b/app/Bootstrap.php new file mode 100644 index 0000000..3c41b3d --- /dev/null +++ b/app/Bootstrap.php @@ -0,0 +1,93 @@ +'; + //var_dump($directorys); + //echo ''; + + $files = new RecursiveIteratorIterator($directorys, RecursiveIteratorIterator::LEAVES_ONLY); + + $filename = $className . static::$extension; + + foreach ($files as $key => $file) { + if (strtolower($file->getFilename()) === strtolower($filename) && $file->isReadable()) { + include_once $file->getPathname(); + return; + } + } + } + + static function setRoot($rootPath){ + static::$root = $rootPath; + } +} + +spl_autoload_register("Autoloader::ClassLoader"); +Autoloader::setRoot('/var/www/dev.steelants.cz/vasek/home-update/'); + +class ErrorHandler { + static function exception($exception){ + error_log($exception); + http_response_code($exception->getCode()); + $message = [ + 'code' => $exception->getCode(), + 'message' => $exception->getMessage(), + ]; + echo json_encode($message); + + $apiLogManager = new LogManager('../logs/'. date("Y-m-d").'.log'); + $apiLogManager->write("[APACHE] ERROR\n" . json_encode($message, JSON_PRETTY_PRINT), LogRecordType::INFO); + } +} +set_exception_handler("ErrorHandler::exception"); + +$json = file_get_contents('php://input'); +$obj = json_decode($json, true); + +$apiLogManager = new LogManager('../logs/api/HA/'. date("Y-m-d").'.log'); + +$apiLogManager->write("[API] request body\n" . json_encode($obj, JSON_PRETTY_PRINT), LogRecordType::INFO); +$apiLogManager->write("[API] POST body\n" . json_encode($_POST, JSON_PRETTY_PRINT), LogRecordType::INFO); +$apiLogManager->write("[API] GET body\n" . json_encode($_GET, JSON_PRETTY_PRINT), LogRecordType::INFO); + +//Debug +error_reporting(E_ALL); +ini_set( 'display_errors','1'); + +//setup +ini_set ('session.cookie_httponly', '1'); +ini_set('session.cookie_domain', $_SERVER['HTTP_HOST']); +ini_set('session.cookie_path', str_replace("login", "", str_replace('https://' . $_SERVER['HTTP_HOST'], "", $_SERVER['REQUEST_URI']))); +ini_set('session.cookie_secure', '1'); +session_start (); +mb_internal_encoding ("UTF-8"); + +// import configs +require_once '../config/config.php'; + +// Logs +$logManager = new LogManager(); + +// Language +if (isset($_SERVER['HTTP_ACCEPT_LANGUAGE'])){ + $langTag = substr($_SERVER['HTTP_ACCEPT_LANGUAGE'], 0, 2); + $langMng = new LanguageManager($langTag); + $langMng->load(); +} + +//D B Conector +Db::connect (DBHOST, DBUSER, DBPASS, DBNAME); + +// TODO: Přesunout do Login Pohledu +$userManager = new UserManager(); + +// import routes +require_once '../app/Routes.php'; diff --git a/app/Routes.php b/app/Routes.php new file mode 100644 index 0000000..f973faa --- /dev/null +++ b/app/Routes.php @@ -0,0 +1,31 @@ +setDefault(function(){ + echo $_GET['url'].': 404'; +}); + +//Pages +$router->any('/', 'Log'); +$router->any('/login', 'Login'); +$router->any('/logout', 'Logout'); +$router->any('/automation', 'Automation'); +$router->any('/setting', 'Setting'); +$router->any('/ajax', 'Ajax'); + +$router->post('/api/login', 'AuthApi@login'); +$router->post('/api/logout', 'AuthApi@logout'); + +$router->get('/api/devices', 'DevicesApi@default'); +$router->get('/api/rooms', 'RoomsApi@default'); + +$router->get('/api/HA/auth', 'GoogleHomeApi@autorize'); +$router->any('/api/HA', 'GoogleHomeApi@response'); + +// examples +$router->any('/api/example', 'ExampleApi@example'); +$router->any('/example', 'ExampleController@index'); +$router->any('/example/subpage', 'ExampleController@subpage'); + +$router->run($_SERVER['REQUEST_METHOD'], '/'.(isset($_GET['url']) ? $_GET['url'] : '')); diff --git a/app/api/AuthApi.php b/app/api/AuthApi.php new file mode 100644 index 0000000..a9d6101 --- /dev/null +++ b/app/api/AuthApi.php @@ -0,0 +1,25 @@ +getToken($this->input->username,$this->input->password); + if (!$token) { + throw new Exception("Auth failed", 401); + } + $this->response(['token' => $token]); + } + + public function logout(){ + $authenticationBearrer = $_SERVER['HTTP_AUTHORIZATION']; + if (!(new AuthManager)->deleteToken($authenticationBearrer)) { + throw new Exception("logout Failed", 401); + } + } + + public function registration(){ + + } + + public function restartPassword(){ + + } +} diff --git a/app/api/DevicesApi.php b/app/api/DevicesApi.php new file mode 100644 index 0000000..daa8ece --- /dev/null +++ b/app/api/DevicesApi.php @@ -0,0 +1,17 @@ +requireAuth(); + $response = []; + + // TODO: process the request + + $this->response($response); + } + + public function getDevicesByRoom($roomId){ + + } +} diff --git a/app/api/ExampleApi.php b/app/api/ExampleApi.php new file mode 100644 index 0000000..0fe5727 --- /dev/null +++ b/app/api/ExampleApi.php @@ -0,0 +1,24 @@ +requireAuth(); + // if user is logged in, next lines will be processed + // otherwise script get terminated with 401 UNAUTHORIZED + + + // input data are stored in $this->input + // in this example we just copy input to response + $response = $this->input; + + + // this method returns response as json + $this->response($response); + // you can specify returned http code by second optional parameter + // default value is 200 + // $this->response($response, $httpCode); + } + +} diff --git a/app/api/GoogleHomeApi.php b/app/api/GoogleHomeApi.php new file mode 100644 index 0000000..40f67cd --- /dev/null +++ b/app/api/GoogleHomeApi.php @@ -0,0 +1,46 @@ +write("[Google Home] action.devices.SYNC", LogRecordType::INFO); + break; + + case 'action.devices.QUERY': + GoogleHome::query($obj['requestId'], $obj['inputs'][0]['payload']); + //$apiLogManager->write("[Google Home] action.devices.QUERY", LogRecordType::INFO); + break; + + case 'action.devices.EXECUTE': + GoogleHome::execute($obj['requestId'], $obj['inputs'][0]['payload']); + $apiLogManager->write("[Google Home] action.devices.EXECUTE", LogRecordType::INFO); + break; + } + } + + static function autorize(){ + $json = file_get_contents('php://input'); + $obj = json_decode($json, true); + + $apiLogManager = new LogManager('../logs/api/HA/'. date("Y-m-d").'.log'); + $apiLogManager->write("[API] request body\n" . json_encode($obj, JSON_PRETTY_PRINT), LogRecordType::INFO); + $apiLogManager->write("[API] GET body\n" . json_encode($_GET, JSON_PRETTY_PRINT), LogRecordType::INFO); + + $get = [ + "access_token"=>"2222255888", + "token_type"=>"Bearer", + "state"=>$_GET["state"], + ]; + + echo $_GET["redirect_uri"] . '#' . http_build_query($get) ; + echo 'FINISH'; + } +} diff --git a/www/app/api/RoomsApi.php b/app/api/RoomsApi.php similarity index 100% rename from www/app/api/RoomsApi.php rename to app/api/RoomsApi.php diff --git a/app/controllers/ExampleController.php b/app/controllers/ExampleController.php new file mode 100644 index 0000000..45a6d8c --- /dev/null +++ b/app/controllers/ExampleController.php @@ -0,0 +1,14 @@ +view->title = 'Example title'; + $this->view->render('example.phtml'); + } + + public function subpage(){ + echo 'subpage'; + } + +} diff --git a/app/controllers/automationController.php b/app/controllers/automationController.php new file mode 100644 index 0000000..f7ae6fd --- /dev/null +++ b/app/controllers/automationController.php @@ -0,0 +1,77 @@ + $_POST['atSelector'], + "value" => $value, + ], JSON_PRETTY_PRINT); + $onDays = $_POST['atDays']; + + //Debug + // if (DEBUGMOD == 1) { + // echo '
';
+		// 	echo $permissionsInJson;
+		// 	echo $deviceId;
+		// 	var_dump(json_decode ($permissionsInJson));
+		// 	echo '
'; + // echo 'CONTINUE'; + // die(); + // } + + AutomationManager::create($_POST['name'], $onDays, $doCode, $ifCode); + + header('Location: ' . BASEURL . strtolower(basename(__FILE__, '.php'))); + die(); + } else if (isset($_POST['modalFinal']) && $_POST['action'] == "edit") { + $doCode = json_encode($_POST['device'], JSON_PRETTY_PRINT); + + if (isset ($_POST['atDeviceValue'])) { + $subDeviceId = $_POST['atDeviceValue']; + $subDeviceValue = $_POST['atDeviceValueInt']; + $subDevice = SubDeviceManager::getSubDevice($subDeviceId); + $subDeviceMaster = SubDeviceManager::getSubDeviceMaster($subDeviceId,$subDevice['type']); + + $device = [ + 'deviceID' => $subDeviceMaster['device_id'], + 'type'=> $subDevice['type'], + 'value'=> $subDeviceValue, + ]; + } + + + $value = $_POST['atSelector']; + if (isset($_POST['atTime'])){ + $value = $_POST['atTime']; + } else if (isset($_POST['atDeviceValue'])) { + $value = $device; + } else if ($_POST['atSelector'] == 'inHome' || $_POST['atSelector'] == 'outHome') { + //TODO: opravit edit aby vkládal id původního uživatele + $value = UserManager::getUserData('user_id'); + } + + $value = (isset($_POST['atTime']) ? $_POST['atTime'] : (isset($_POST['atDeviceValue']) ? $device : $_POST['atSelector'])); + $ifCode = json_encode([ + "type" => $_POST['atSelector'], + "value" => $value, + ], JSON_PRETTY_PRINT); + $onDays = ($_POST['day'] != '' ? json_encode($_POST['day']) : ''); + + AutomationManager::create($_POST['name'], $onDays, $doCode, $ifCode, (isset ($_POST['automation_id']) ? $_POST['automation_id'] : "")); + + header('Location: ' . BASEURL . strtolower(basename(__FILE__, '.php'))); + die(); + } +} +?> diff --git a/app/controllers/loginController.php b/app/controllers/loginController.php new file mode 100644 index 0000000..de4fed6 --- /dev/null +++ b/app/controllers/loginController.php @@ -0,0 +1,51 @@ +haveOtaEnabled($userName); + if ($ota == "") { + $landingPage = $userManager->login($userName, $userPassword, $rememberMe); + header('Location: ' . BASEURL . $landingPage); + die(); + } + + $_SESSION['USERNAME'] = $userName; + $_SESSION['PASSWORD'] = $userPassword; + $_SESSION['REMEMBER'] = $rememberMe; + $_SESSION['OTA'] = $ota; +} else if ( + isset($_POST['otaCode']) && + $_POST['otaCode'] != '' +) { + + $otaCode = $_POST['otaCode']; + $otaSecret = $_POST['otaSecret']; + + $ga = new PHPGangsta_GoogleAuthenticator(); + $ota = $_SESSION['OTA']; + $userName = $_SESSION['USERNAME']; + $userPassword = $_SESSION['PASSWORD']; + $rememberMe = $_SESSION['REMEMBER']; + unset($_SESSION['OTA']); + $checkResult = $ga->verifyCode($otaSecret, $otaCode, 2); // 2 = 2*30sec clock tolerance + if ($checkResult) { + $landingPage = $userManager->login($userName, $userPassword, $rememberMe); + header('Location: ' . BASEURL . '/'); + echo 'OK'; + } else { + echo 'FAILED'; + } + //TODO: upravi a ověřit jeslti ja zabezpečené + //TODO: + die(); +} diff --git a/app/controllers/settingController.php b/app/controllers/settingController.php new file mode 100644 index 0000000..f31a8de --- /dev/null +++ b/app/controllers/settingController.php @@ -0,0 +1,29 @@ +verifyCode($otaSecret, $otaCode, 2); // 2 = 2*30sec clock tolerance + if ($checkResult) { + UserManager::setOta($otaCode, $otaSecret); + } + header('Location: ' . BASEURL . 'setting'); + die(); + } +} diff --git a/app/models/AuthManager.php b/app/models/AuthManager.php new file mode 100644 index 0000000..88c96a6 --- /dev/null +++ b/app/models/AuthManager.php @@ -0,0 +1,45 @@ +loginNew($username, $password); + + if ($userLogedIn != false){ + // Create token header as a JSON string + $header = json_encode(['typ' => 'JWT', 'alg' => 'HS256']); + // Create token payload as a JSON string + $payload = json_encode(['user_id' => $userLogedIn]); + // Encode Header to Base64Url String + $base64UrlHeader = str_replace(['+', '/', '='], ['-', '_', ''], base64_encode($header)); + // Encode Payload to Base64Url String + $base64UrlPayload = str_replace(['+', '/', '='], ['-', '_', ''], base64_encode($payload)); + // Create Signature Hash + $signature = hash_hmac('sha256', $base64UrlHeader . "." . $base64UrlPayload, 'abC123!', true); + // Encode Signature to Base64Url String + $base64UrlSignature = str_replace(['+', '/', '='], ['-', '_', ''], base64_encode($signature)); + // Create JWT + $jwt = $base64UrlHeader . "." . $base64UrlPayload . "." . $base64UrlSignature; + + return $jwt; + } + } + return false; + } + + public function deleteToken($token){ + Db::command ('DELETE FROM tokens WHERE token=?', array ($token)); + return true; + } + + public function validateToken($token){ + $tokens = Db::loadAll('SELECT * FROM tokens WHERE token = ? AND expire >= CURRENT_TIMESTAMP AND blocked = 0;', array($token)); + if (count($tokens) == 1) { + return true; + } else if (count($tokens) == 0) { + return false; + }; + return false; + } +} diff --git a/app/models/AutomationManager.php b/app/models/AutomationManager.php new file mode 100644 index 0000000..aacf6f7 --- /dev/null +++ b/app/models/AutomationManager.php @@ -0,0 +1,175 @@ + $name, + 'owner_id' => $userId, + 'on_days' => $onDays, + 'if_something' => $ifCode, + 'do_something' => $doCode, + ); + try { + if ($automationId == "") { + Db::add ('automation', $scene); + } else { + Db::edit ('automation', $scene, 'WHERE automation_id = ?', array ($automationId)); + } + } catch(PDOException $error) { + echo $error->getMessage(); + die(); + } + } + + public static function getAll(){ + return Db::loadAll ("SELECT * FROM automation"); + + } + + public static function executeAll(){ + global $logManager; + + $automations = Db::loadAll ("SELECT * FROM automation"); + $dayNameNow = strtolower (date('D', time())); + + foreach ($automations as $automation) { + $onValue = json_decode($automation['if_something'], true); + $sceneDoJson = $automation['do_something']; + $actionDays = json_decode($automation['on_days'], true); + $value = time(); + $run = false; + $restart = false; + + if ($automation['active'] == 1 && $automation['locked'] != 1){ + Db::edit('automation', array('locked' => 1), 'WHERE automation_id = ?', array($automation['automation_id'])); + if (in_array($dayNameNow, $actionDays)){ + if (in_array($onValue['type'], ['sunSet', 'sunRise', 'time','now'])) { + if ($onValue['type'] == 'sunSet') { + $value = date_sunset($value, SUNFUNCS_RET_TIMESTAMP, 50.0755381 , 14.4378005, 90); + } else if ($onValue['type'] == 'sunRise') { + $value = date_sunrise($value, SUNFUNCS_RET_TIMESTAMP, 50.0755381 , 14.4378005, 90); + } else if ($onValue['type'] == 'time') { + $onValue = explode(':',$onValue['value']); + $today = date_create('now'); + $onValue = $today->setTime($onValue[0], $onValue[1]); + $value = $today->getTimestamp(); + } + + if (time() > $value && $automation['executed'] == 0){ + $run = true; + } else if (time() < $value && $automation['executed'] == 1) { //recovery realowing of automation + $restart = true; + } + + } else if ($onValue['type'] == 'outHome') { + //TODO: Add Ovner to automation + $userHomeStatus = UserManager::getUserData('at_home', $onValue['value']); + if ($userHomeStatus == 'false' && $automation['executed'] == 0) { + $run = true; + } else if ($userHomeStatus == 'true' && $automation['executed'] == 1) { + $restart = true; + } + } else if ($onValue['type'] == 'inHome') { + //TODO: Add Ovner to automation + $userHomeStatus = UserManager::getUserData('at_home', $onValue['value']); + if ($userHomeStatus == 'true' && $automation['executed'] == 0) { + $run = true; + } else if ($userHomeStatus == 'false' && $automation['executed'] == 1) { + $restart = true; + } + } else if ($onValue['type'] == 'noOneHome') { + $users = UserManager::getUsers(); + $membersHome = 0; + foreach ($users as $key => $user) { + if ($user['at_home'] == 'true'){ + $membersHome++; + } + } + if ($membersHome == 0 && $automation['executed'] == 0) { + $run = true; + } else if ($membersHome > 0 && $automation['executed'] == 1){ + $restart = true; + } + } else if ($onValue['type'] == 'someOneHome') { + $users = UserManager::getUsers(); + $membersHome = 0; + foreach ($users as $key => $user) { + if ($user['at_home'] == 'true'){ + $membersHome++; + } + } + if ($membersHome == 0 && $automation['executed'] == 1) { + $restart = true; + } else if ($membersHome > 0 && $automation['executed'] == 0){ + $run = true; + } + } else if ($onValue['type'] == 'atDeviceValue') { + + $subDeviceId = SubDeviceManager::getSubDeviceByMaster($onValue['value']['deviceID'], $onValue['value']['type'])["subdevice_id"]; + $lastValue = RecordManager::getLastRecord($subDeviceId); + + if ($lastValue['value'] == $onValue['value']['value'] && $automation['executed'] == 0) { + $run = true; + + } else if ($lastValue['value'] != $onValue['value']['value'] && $automation['executed'] == 1){ + $restart = true; + + } + } + + //finalization + if ($run) { + $body = ''; + + $sceneDoArray = json_decode($sceneDoJson); + foreach ($sceneDoArray as $deviceId => $deviceState) { + RecordManager::create($deviceId, 'on/off', $deviceState); + } + + $subscribers = NotificationManager::getSubscription(); + $i = 0; + + $notificationMng = new NotificationManager; + $notificationData = [ + 'title' => 'Automatization', + 'body' => 'Automatization '.$automation['name']." was just executed", + 'icon' => BASEDIR . '/app/templates/images/icon-192x192.png', + ]; + + if ($notificationData != []) { + $subscribers = $notificationMng::getSubscription(); + foreach ($subscribers as $key => $subscriber) { + $logManager->write("[NOTIFICATION/AUTOOMATION] SENDING TO" . $subscriber['id'] . " "); + $notificationMng::sendSimpleNotification(SERVERKEY, $subscriber['token'], $notificationData); + } + } + + $logManager->write("[AUTOMATIONS] automation id ". $automation['automation_id'] . " was executed"); + Db::edit('automation', array('executed' => 1, 'execution_time' => date("Y-m-d H:i:s")), 'WHERE automation_id = ?', array($automation['automation_id'])); + } else if ($restart) { + $logManager->write("[AUTOMATIONS] automation id ". $automation['automation_id'] . " was restarted"); + Db::edit('automation', array('executed' => 0), 'WHERE automation_id = ?', array($automation['automation_id'])); + } + Db::edit('automation', array('locked' => 0), 'WHERE automation_id = ?', array($automation['automation_id'])); + } + } + } + } +} diff --git a/app/models/ChartJS.php b/app/models/ChartJS.php new file mode 100644 index 0000000..5b0b8bc --- /dev/null +++ b/app/models/ChartJS.php @@ -0,0 +1,194 @@ + 'rgba(220,220,220,0.2)', 'stroke' => 'rgba(220,220,220,1)', 'point' => 'rgba(220,220,220,1)', 'pointStroke' => '#fff'); + /** + * Add label(s) + * @param array $labels + * @param bool $reset + */ + public function addLabels(array $labels, $reset = false) + { + if ($reset) { + $this->_labels = array(); + } + $this->_labels = $this->_labels + $labels; + } + /** + * Add dataset + * @param $dataset + * @param $reset + */ + public function addDataset($dataset, $reset) + { + if ($reset) { + $this->_datasets = array(); + } + $this->_datasets += $dataset; + } + public function __construct($id = null, $width = '', $height = '', $otherAttributes = array()) + { + if (!$id) { + $id = uniqid('chartjs_', true); + } + $this->_id = $id; + $this->_width = $width; + $this->_height = $height; + // Always save otherAttributes as array + if ($otherAttributes && !is_array($otherAttributes)) { + $otherAttributes = array($otherAttributes); + } + $this->_attributes = $otherAttributes; + } + /** + * This method allows to echo ChartJS object and directly renders canvas (instead of using ChartJS->render()) + */ + public function __toString() + { + return $this->renderCanvas(); + } + public function renderCanvas() + { + $data = $this->_renderData(); + $options = $this->_renderOptions(); + $height = $this->_renderHeight(); + $width = $this->_renderWidth(); + $attributes = $this->_renderAttributes(); + $canvas = ''; + return $canvas; + } + /** + * Prepare canvas' attributes + * @return string + */ + protected function _renderAttributes() + { + $attributes = ''; + foreach ($this->_attributes as $attribute => $value) { + $attributes .= ' ' . $attribute . '="' . $value . '"'; + } + return $attributes; + } + /** + * Prepare width attribute for canvas + * @return string + */ + protected function _renderWidth() + { + $width = ''; + if ($this->_width) { + $width = ' width="' . $this->_width . '"'; + } + return $width; + } + /** + * Prepare height attribute for canvas + * @return string + */ + protected function _renderHeight() + { + $height = ''; + if ($this->_height) { + $height = ' height="' . $this->_height . '"'; + } + return $height; + } + /** + * Render custom options for the chart + * @return string + */ + protected function _renderOptions() + { + if (empty($this->_options)) { + return ''; + } + return ' data-options=\'' . json_encode($this->_options) . '\''; + } + /** + * Prepare data (labels and dataset) for the chart + * @return string + */ + protected function _renderData() + { + $array_data = array('labels' => array(), 'datasets' => array()); + $i = 0; + foreach ($this->_datasets as $line) { + $this->_completeColors($line['options'], $i); + $array_data['datasets'][] = $line['options'] + array('data' => $line['data']); + $i++; + } + $array_data['labels'] = $this->_labels; + return ' data-data=\'' . json_encode($array_data) . '\''; + } + /** + * Set default colors + * @param array $defaultColors + */ + public static function setDefaultColors(array $defaultColors) + { + self::$_defaultColors = $defaultColors; + } + /** + * @param array $color + */ + public static function addDefaultColor(array $color) + { + if (!empty($color['fill']) && !empty($color['stroke']) && !empty($color['point']) && !empty($color['pointStroke'])) { + self::$_defaultColors[] = $color; + } else { + trigger_error('Color is missing to add this theme (need fill, stroke, point and pointStroke) : color not added', E_USER_WARNING); + } + } + protected function _completeColors(&$options, &$i) + { + if (empty(static::$_defaultColors[$i])) { + $i = 0; + } + $colors = static::$_defaultColors[$i]; + foreach (static::$_colorsRequired as $name) { + if (empty($options[$name])) { + $shortName = str_replace('Color', '', $name); + if (empty($colors[$shortName])) { + $shortName = static::$_colorsReplacement[$shortName]; + } + $options[$name] = $colors[$shortName]; + } + } + } +} diff --git a/app/models/ChartJS_Line.php b/app/models/ChartJS_Line.php new file mode 100644 index 0000000..3fa3f5a --- /dev/null +++ b/app/models/ChartJS_Line.php @@ -0,0 +1,21 @@ + 'point', 'pointHighlightStroke' => 'pointStroke'); + /** + * Add a set of data + * @param array $data + * @param array $options + * @param null $name Name cas be use to change data / options later + */ + public function addLine($data = array(), $options = array(), $name = null) + { + if (!$name) { + $name = count($this->_datasets) + 1; + } + $this->_datasets[$name]['data'] = $data; + $this->_datasets[$name]['options'] = $options; + } +} diff --git a/app/models/ChartManager.php b/app/models/ChartManager.php new file mode 100644 index 0000000..d26757c --- /dev/null +++ b/app/models/ChartManager.php @@ -0,0 +1,129 @@ +Aktuální Hodnota: '.$data[0]['value']; + echo ""; + echo '
'; + echo '
'; + for ($valuesRow = 0; $valuesRow < count($data); $valuesRow++) { + $row = $data[$valuesRow]; + + echo '
'; + } + echo '
'; + echo '
'; + echo ''; + echo 'Poslední Update: '; + + echo ' + '; + } + + function generateChartData(int $subDeviceId, string $periode, string $groupBy) { + $chartData = []; + + $subDevice = SubDeviceManager::getSubDevice($subDeviceId); + $records = RecordManager::getAllRecordForGraph($subDeviceId, $periode, $groupBy); + + $array = array_column($records, 'value'); + $arrayTime = array_column($records, 'time'); + $output = []; + + foreach ($array as $key => $value) { + $output[$key]['y'] = $value; + if ($subDevice['type'] == 'light'){ + if ($value > 810){ + $output[$key]['y'] = 1; + } else { + $output[$key]['y'] = 0; + } + } + + $timeStamp = new DateTime($arrayTime[$key]); + $output[$key]['t'] = $timeStamp->format("Y-m-d") . 'T' . $timeStamp->format("H:i:s") . 'Z'; + } + + $data = json_encode($output); + $data = $output; + $arrayTimeStamps = array_column($records, 'time'); + foreach ($arrayTimeStamps as $key => $value) { + $arrayTimeStamps[$key] = (new DateTime($value))->format(TIMEFORMAT); + } + + $chartData['graphRange'] = RANGES[$subDevice['type']]; + $chartData['graphType'] = RANGES[$subDevice['type']]['graph']; + $chartData['graphData'] = $data; + + return $chartData; + } +} +?> diff --git a/app/models/DashboardManager.php b/app/models/DashboardManager.php new file mode 100644 index 0000000..b241a35 --- /dev/null +++ b/app/models/DashboardManager.php @@ -0,0 +1,41 @@ + UserManager::getUserData('user_id'), + 'subdevice_id' => $subDeviceId, + ); + try { + Db::add ('dashboard', $dashboardItem); + } catch(PDOException $error) { + echo $error->getMessage(); + die(); + } + } + } + + static function Remove ($subDeviceId){ + $userId = UserManager::getUserData('user_id'); + Db::command ('DELETE FROM dashboard WHERE subdevice_id=? AND user_id = ?', array ($subDeviceId, $userId)); + } +} diff --git a/app/models/DeviceManager.php b/app/models/DeviceManager.php new file mode 100644 index 0000000..53255f8 --- /dev/null +++ b/app/models/DeviceManager.php @@ -0,0 +1,96 @@ + $name, + 'token' => $token, + 'room_id' => $defaultRoom, + ); + try { + Db::add ('devices', $device); + return Db::loadOne("SELECT device_id FROM devices WHERE token = ?", array($token))['device_id']; + } catch(PDOException $error) { + echo $error->getMessage(); + die(); + } + } + + public static function edit ($deviceId, $values = []) { + try { + Db::edit ('devices', $values, 'WHERE device_id = ?', array($deviceId)); + } catch(PDOException $error) { + echo $error->getMessage(); + die(); + } + } + + public static function editByToken ($token, $values = []) { + try { + Db::edit ('devices', $values, 'WHERE token = ?', array($token)); + } catch(PDOException $error) { + echo $error->getMessage(); + die(); + } + } + + /** + * [assignRoom Přiřazení zařízení do třídy] + * @param [type] $roomId [číslo místnosti do kter se má zařízení přiřadit] + * @param [type] $deviceId [Číslo zařízení které chcete přiřadit do místnosti] + */ + public static function assignRoom ($roomId, $deviceId) { + $device = array ( + 'room_id' => $roomId, + ); + try { + Db::edit ('devices', $device, 'WHERE device_id = ?', array($deviceId)); + } catch(PDOException $error) { + echo $error->getMessage(); + die(); + } + } + + /** + * [delete Smazání zařízení] + * @param [type] $deviceId [Id zařízení ke smazání] + */ + public static function delete ($deviceId) { + Db::command ('DELETE FROM devices WHERE device_id=?', array ($deviceId)); + } + + public static function registeret ($deviceToken) { + return (count(Db::loadAll ("SELECT * FROM devices WHERE token=?", array($deviceToken))) == 1 ? true : false); + } + + public static function approved ($deviceToken) { + return (count(Db::loadAll ("SELECT * FROM devices WHERE token=? AND approved = ?", array($deviceToken, 1))) == 1 ? true : false); + } +} +?> diff --git a/app/models/FallbackManager.php b/app/models/FallbackManager.php new file mode 100644 index 0000000..cb3fb79 --- /dev/null +++ b/app/models/FallbackManager.php @@ -0,0 +1,44 @@ +deviceDefinitions = $deviceDefinition; + } + + function check(){ + //TODO: FIX IT + $allDevicesData = DeviceManager::getAllDevices(); + foreach ($allDevicesData as $deviceKey => $deviceValue) { + $allSubDevicesData = SubDeviceManager::getAllSubDevices($deviceValue['device_id']); + foreach ($allSubDevicesData as $subDeviceKey => $subDeviceValue) { + if (!isset($this->deviceDefinitions[$subDeviceValue['type']]["fallBack"])) { + continue; + } + + if (!isset($this->deviceDefinitions[$subDeviceValue['type']]["fallBackTime"])) { + continue; + } + + $lastRecord = RecordManager::getLastRecord($subDeviceValue['subdevice_id']); + if ($lastRecord["value"] == $this->deviceDefinitions[$subDeviceValue['type']]["fallBack"]) { + continue; + } + + $minutes = (time() - strtotime($lastRecord['time'])) / 60; + + if ( $minutes > $this->deviceDefinitions[$subDeviceValue['type']]["fallBackTime"]){ + RecordManager::create($deviceValue['device_id'], $subDeviceValue['type'], $this->deviceDefinitions[$subDeviceValue['type']]["fallBack"]); + } + } + } + } +} diff --git a/www/library/Form.php b/app/models/Form.php similarity index 100% rename from www/library/Form.php rename to app/models/Form.php diff --git a/app/models/GoogleHome.php b/app/models/GoogleHome.php new file mode 100644 index 0000000..8882be9 --- /dev/null +++ b/app/models/GoogleHome.php @@ -0,0 +1,260 @@ + $roomData) { + $devicesData = DeviceManager::getAllDevicesInRoom($roomData['room_id']); + foreach ($devicesData as $deviceKey => $deviceData) { + $subDevicesData = SubDeviceManager::getAllSubDevices($deviceData['device_id']); + foreach ($subDevicesData as $subDeviceKey => $subDeviceData) { + if ($subDeviceData['type'] != "on/off" && $subDeviceData['type'] != "temp_cont") continue; + + //Google Compatibile Action Type + $actionType = GoogleHomeDeviceTypes::getAction($subDeviceData['type']); + $tempDevice = [ + 'id' => (string) $subDeviceData['subdevice_id'], + 'type' => $actionType, + 'name' => [ + 'name' => $deviceData['name'], + ], + 'willReportState' => false, + 'roomHint' => $roomData['name'] + ]; + + //traids & Attributes + $devices[] = GoogleHomeDeviceTypes::getSyncObj($tempDevice, $actionType); + } + } + } + + $response = [ + 'requestId' => $requestId, + 'payload' => [ + 'agentUserId'=>'651351531531', + 'devices' => $devices, + ], + ]; + $apiLogManager = new LogManager('../logs/api/HA/'. date("Y-m-d").'.log'); + $apiLogManager->write("[API][$requestId] request response\n" . json_encode($response, JSON_PRETTY_PRINT), LogRecordType::INFO); + echo json_encode($response); + } + + static function query($requestId, $payload){ + $devices = []; + foreach ($payload['devices'] as $deviceId) { + $subDeviceData = SubDeviceManager::getSubDevice($deviceId['id']); + if ($subDeviceData['type'] != "on/off" && $subDeviceData['type'] != "temp_cont") continue; + + $state = false; + if (RecordManager::getLastRecord($deviceId['id'])['value'] == 1){ + $state = true; + } + + $online = false; + $status = 'OFFLINE'; + + if (RecordManager::getLastRecord($deviceId['id'])['execuded'] == 1){ + $online = true; + $status = 'SUCCESS'; + } else { + $executed = 0; + $waiting = 0; + foreach (RecordManager::getLastRecord($deviceId['id'], 6) as $key => $value) { + if ($value['execuded'] == 1){ + $executed++; + } else { + $waiting++; + } + } + if ($waiting < $executed){ + $status = "PENDING"; + $online = true; + } + } + + $tempDevice = [ + $deviceId['id'] => [ + 'online' => $online, + 'status'=> $status, + ] + ]; + + if ($subDeviceData['type'] == "temp_cont"){ + $tempDevice[$deviceId['id']]['thermostatMode'] = 'off'; + if (RecordManager::getLastRecord($deviceId['id'])['value'] != 0) { + $tempDevice[$deviceId['id']]['thermostatMode'] = 'heat'; + $tempDevice[$deviceId['id']]['thermostatTemperatureAmbient'] = RecordManager::getLastRecord($deviceId['id'])['value']; + $tempDevice[$deviceId['id']]['thermostatTemperatureSetpoint'] = RecordManager::getLastRecord($deviceId['id'])['value']; + } + } else { + $tempDevice[$deviceId['id']]['on'] = $state; + } + $devices = $tempDevice; + if (count($devices)> 1){ + $devices[] = $tempDevice; + } + } + + $response = [ + 'requestId' => $requestId, + 'payload' => [ + 'devices' => $devices, + ], + ]; + + $apiLogManager = new LogManager('../logs/api/HA/'. date("Y-m-d").'.log'); + $apiLogManager->write("[API][$requestId] request response\n" . json_encode($response, JSON_PRETTY_PRINT), LogRecordType::INFO); + echo json_encode($response); + } + + static function execute($requestId, $payload){ + $commands = []; + + foreach ($payload['commands'] as $key => $command) { + foreach ($command['devices'] as $key => $device) { + $executionCommand = $command['execution'][0]; + if (isset($command['execution'][$key])) { + $executionCommand = $command['execution'][$key]; + } + + $subDeviceId = $device['id']; + + switch ($executionCommand['command']) { + case 'action.devices.commands.OnOff': + $commands[] = self::executeSwitch($subDeviceId, $executionCommand); + break; + + case 'action.devices.commands.ThermostatTemperatureSetpoint': + $commands[] = self::executeTermostatValue($subDeviceId, $executionCommand); + break; + + case 'action.devices.commands.ThermostatSetMode': + $commands[] = self::executeTermostatMode($subDeviceId, $executionCommand); + break; + } + } + } + + $response = [ + 'requestId' => $requestId, + 'payload' => [ + 'commands' => $commands, + ], + ]; + $apiLogManager = new LogManager('../logs/api/HA/'. date("Y-m-d").'.log'); + $apiLogManager->write("[API][EXECUTE][$requestId]\n" . json_encode($response, JSON_PRETTY_PRINT), LogRecordType::INFO); + + echo json_encode($response); + } + + static function executeSwitch($subDeviceId, $executionCommand){ + $value = 0; + $status = 'SUCCESS'; + if ($executionCommand['params']['on']) $value = 1; + + RecordManager::createWithSubId($subDeviceId, $value); + + $executed = 0; + $waiting = 0; + foreach (RecordManager::getLastRecord($subDeviceId, 4) as $key => $value) { + if ($value['execuded'] == 1){ + $executed++; + } else { + $waiting++; + } + } + if ($waiting < $executed){ + $status = "PENDING"; + } else { + $status = "OFFLINE"; + } + + $commandTemp = [ + 'ids' => [$subDeviceId], + 'status' => $status, + 'states' => [ + 'on' => $executionCommand['params']['on'], + ], + ]; + return $commandTemp; + } + + static function executeTermostatValue($subDeviceId, $executionCommand){ + $value = 0; + $status = 'SUCCESS'; + + if (isset($executionCommand['params']['thermostatTemperatureSetpoint'])) { + $value = $executionCommand['params']['thermostatTemperatureSetpoint']; + } + + RecordManager::createWithSubId($subDeviceId, $value); + + $executed = 0; + $waiting = 0; + foreach (RecordManager::getLastRecord($subDeviceId, 4) as $key => $lastValue) { + if ($lastValue['execuded'] == 1){ + $executed++; + } else { + $waiting++; + } + } + if ($waiting < $executed){ + $status = "PENDING"; + } else { + $status = "OFFLINE"; + } + + $commandTemp = [ + 'ids' => [$subDeviceId], + 'status' => $status, + 'states' => [ + 'thermostatMode' => 'heat', + 'thermostatTemperatureSetpoint' => $value, + 'thermostatTemperatureAmbient' => $value, + //ambient z dalšího zenzoru v roomu + ], + ]; + + if ($timeout >= 5){ + $commandTemp['status'] = "OFFLINE"; + } + return $commandTemp; + } + + static function executeTermostatMode($subDeviceId, $executionCommand){ + $mode = "off"; + $value = 0; + $status = "SUCCESS"; + + if (isset($executionCommand['params']['thermostatMode']) && $executionCommand['params']['thermostatMode'] != 'off') { + $mode = $executionCommand['params']['thermostatMode']; + $value = RecordManager::getLastRecordNotNull($subDeviceId)['value']; + } + + RecordManager::createWithSubId($subDeviceId, $value); + + $executed = 0; + $waiting = 0; + foreach (RecordManager::getLastRecord($deviceId['id'], 4) as $key => $value) { + if ($value['execuded'] == 1){ + $executed++; + } else { + $waiting++; + } + } + if ($waiting < $executed){ + $status = "PENDING"; + } + + $commandTemp = [ + 'ids' => [$subDeviceId], + 'status' => $status, + 'states' => [ + 'thermostatMode' => $mode + ], + ]; + + return $commandTemp; + } +} diff --git a/app/models/LanguageManager.php b/app/models/LanguageManager.php new file mode 100644 index 0000000..507bd88 --- /dev/null +++ b/app/models/LanguageManager.php @@ -0,0 +1,60 @@ +lngCode = $lngCode; + $this->debug = $debug; + } + + function load() + { + $file = '../lang/en.php'; + if (!file_exists($file)){ + echo 'ERROR: en.php not found'; + die(); + //TODO add lng EXEPTIONS + } + $arrayFirst = include($file); + $file = '../lang/' . $this->lngCode . '.php'; + $arraySecond = []; + if (file_exists($file)){ + $arraySecond = include($file); + } + $this->lngDatabase = array_merge($arrayFirst, $arraySecond); + return true; + } + + function get(string $stringKey) + { + if ($this->debug) { + return $stringKey; + } + if (isset($this->lngDatabase[$stringKey])) { + return $this->lngDatabase[$stringKey]; + } + return $stringKey; + } + + function echo(string $stringKey) + { + if ($this->debug) { + echo $stringKey; + return; + } + if (isset($this->lngDatabase[$stringKey])) { + echo $this->lngDatabase[$stringKey]; + return; + } + echo $stringKey; + return; + } +} diff --git a/app/models/LogManager.php b/app/models/LogManager.php new file mode 100644 index 0000000..dde1c14 --- /dev/null +++ b/app/models/LogManager.php @@ -0,0 +1,57 @@ + $file) { + if (in_array($file,array(".","..", ".gitkeep", $todayFileName))) + { + continue; + } + if (filemtime($file) > $seconds) { + unlink('../logs/'.$file); + } + } + } +} + +class LogManager +{ + + private $logFile; + function __construct($fileName = "") + { + if ($fileName == ""){ + $fileName = '../logs/'. date("Y-m-d").'.log'; + } + if(!is_dir("../logs/")) + { + mkdir("../logs/"); + } + $this->logFile = fopen($fileName, "a") or die("Unable to open file!"); + } + + function write($value, $type = LogRecordType::ERROR){ + $record = "[".date("H:m:s")."][".$type."]" . $value . "\n"; + fwrite($this->logFile, $record); + } + + function __destruct(){ + if (isset($this->logFile)) { + fclose($this->logFile); + } + } +} diff --git a/app/models/NetworkManager.php b/app/models/NetworkManager.php new file mode 100644 index 0000000..247e0df --- /dev/null +++ b/app/models/NetworkManager.php @@ -0,0 +1,18 @@ + $userID, + 'token' => $token, + ); + Db::add ('notifications', $notification); + } + } + + function getSubscription () { + return Db::loadAll ("SELECT * FROM notifications"); + } + + function sendSimpleNotification(string $serverKey, string $to, array $data, bool $timeStamp = false){ + $dataTemplate = [ + 'title' => '', + 'body' => '', + 'icon' => '', + ]; + + if (array_diff_key ($dataTemplate , $data)){ + return; + } + + if ($timeStamp) { + $data['title'] = $data['title'] . date(); + } + + $notification = new Notification($serverKey); + $notification->to($to); + $notification->notification($data['title'], $data['body'], $data['icon'], ''); + $answer = $notification->send(); + $notification = null; + + return $answer; + } +} + +class Notification +{ + public $server_key = ''; + public $jsonPayload = [ + "to" => '', + "data" => [ + "notification" => [ + "body" => '', + "title" => '', + "icon" => '', + "click_action" => '', + ] + ] + ]; + + function __construct($serverKey = '') + { + $this->server_key = $serverKey; + } + + function to($to = ''){ + $this->jsonPayload["to"] = $to; + } + + function notification($title = '', $body = '', $icon = '', $action = '', bool $timeStamp = false) + { + if ($timeStamp) { + $data['title'] = $data['title'] . date(); + } + + $this->jsonPayload["data"]["notification"]["title"] = $title; + $this->jsonPayload["data"]["notification"]["body"] = $body; + $this->jsonPayload["data"]["notification"]["icon"] = $icon; + $this->jsonPayload["data"]["notification"]["click_action"] = $action; + } + + function send(){ + $data = json_encode($this->jsonPayload); + $url = 'https://fcm.googleapis.com/fcm/send'; + $headers = array( + 'Content-Type:application/json', + 'Authorization:key='.$this->server_key, + ); + + $ch = curl_init(); + curl_setopt($ch, CURLOPT_URL, $url); + curl_setopt($ch, CURLOPT_POST, true); + curl_setopt($ch, CURLOPT_HTTPHEADER, $headers); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); + curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0); + curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); + curl_setopt($ch, CURLOPT_POSTFIELDS, $data); + $result = curl_exec($ch); + if ($result === FALSE) { + die('Oops! FCM Send Error: ' . curl_error($ch)); + } + curl_close($ch); + return $result; + } +} diff --git a/www/library/Partial.php b/app/models/Partial.php similarity index 100% rename from www/library/Partial.php rename to app/models/Partial.php diff --git a/app/models/RecordManager.php b/app/models/RecordManager.php new file mode 100644 index 0000000..143b6a2 --- /dev/null +++ b/app/models/RecordManager.php @@ -0,0 +1,106 @@ + 1, + ]; + Db::edit ('records', $record, 'WHERE subdevice_id = ?', array ($subDeviceId)); + $record = array ( + 'subdevice_id' => $subDeviceId, + 'value' => $value, + ); + return Db::add ('records', $record); + } catch(PDOException $error) { + echo $error->getMessage(); + die(); + } + } + + public static function create ($deviceId, $type, $value) { + $subDeviceId = Db::loadOne('SELECT * FROM subdevices WHERE device_id = ? AND type = ?;', array($deviceId, $type))['subdevice_id']; + if ($subDeviceId == '') { + return false; + }; + try { + $record = [ + 'execuded' => 1, + ]; + Db::edit ('records', $record, 'WHERE subdevice_id = ?', array ($subDeviceId)); + $record = array ( + 'subdevice_id' => $subDeviceId, + 'value' => $value, + ); + return Db::add ('records', $record); + } catch(PDOException $error) { + echo $error->getMessage(); + die(); + } + } + + + public static function setExecuted($recordId) { + try { + Db::edit ('records', ['execuded' => 1], 'WHERE record_id = ?', array($recordId)); + } catch(PDOException $error) { + echo $error->getMessage(); + die(); + } + } + + public static function getRecordById($recordId) { + return Db::loadOne('SELECT * FROM records WHERE record_id = ?;', array($recordId)); + } + + public static function getLastInsertedRecordId() { + return Db::insertId(); + } + + public static function getLastRecord($subDeviceId, $num = 1) { + if ($num == 1) + return Db::loadOne('SELECT * FROM records WHERE subdevice_id = ? AND value != ? ORDER BY time DESC;', array($subDeviceId, 999)); + return Db::loadAll('SELECT * FROM records WHERE subdevice_id = ? AND value != ? ORDER BY time DESC LIMIT ?;', array($subDeviceId, 999, $num)); + } + + public static function getLastRecordNotNull($subDeviceId) { + return Db::loadOne('SELECT * FROM records WHERE subdevice_id = ? AND value != ? ORDER BY time DESC;', array($subDeviceId, 0)); + } + + public static function getAllRecord($subDeviceId, $timeFrom, $timeTo) { + return Db::loadAll('SELECT * FROM records WHERE subdevice_id = ? AND time >= ? AND time <= ? AND value != ? ORDER BY time;', array($subDeviceId, $timeFrom, $timeTo, 999)); + } + + public static function getAllRecordForGraph($subDeviceId, $period = "day", $groupBy = "hour") { + $periodLocal = '- 1 ' . strtoupper($period); + $dateTime = new DateTime(); + $dateTime = $dateTime->modify($periodLocal); + $dateTime = $dateTime->format('Y-m-d'); + $groupBy = strtoupper($groupBy).'(time)'; + $sql = 'SELECT value, time FROM records + WHERE + subdevice_id = ? + AND + value != 999 + AND + time > ? + GROUP BY '.$groupBy.' + ORDER BY time ASC'; + //TODO: Prasárna Opravit + return Db::loadAll($sql, array($subDeviceId, $dateTime)); + } + + public static function clean ($day) { + if (isset($day)) { + Db::command ('DELETE FROM records WHERE `time` < ADDDATE(NOW(), INTERVAL -? DAY);', array($day)); + } + } + + + //TODO: zkontrolovat jestli neco nezbilo po smazaní + public static function cleanSubdeviceRecords ($subDeviceId) { + Db::command ('DELETE FROM records WHERE subdevice_id = ?);', array($subDeviceId)); + } +} +?> diff --git a/app/models/RoomManager.php b/app/models/RoomManager.php new file mode 100644 index 0000000..928b829 --- /dev/null +++ b/app/models/RoomManager.php @@ -0,0 +1,31 @@ + $name, + ); + try { + Db::add ('rooms', $room); + } catch(PDOException $error) { + echo $error->getMessage(); + die(); + } + } + + public static function delete ($roomId) { + Db::command ('DELETE FROM rooms WHERE room_id=?', array ($roomId)); + } +} +?> diff --git a/app/models/SceneManager.php b/app/models/SceneManager.php new file mode 100644 index 0000000..2cd7fb8 --- /dev/null +++ b/app/models/SceneManager.php @@ -0,0 +1,41 @@ + $icon, + 'name' => $name, + 'do_something' => $doCode, + ); + try { + Db::add ('scenes', $scene); + } catch(PDOException $error) { + echo $error->getMessage(); + die(); + } + } + + public static function getAllScenes () { + return Db::loadAll ("SELECT * FROM scenes"); + } + + public static function getScene ($sceneId) { + return Db::loadOne("SELECT * FROM scenes WHERE scene_id = ?", array($sceneId)); + } + + public static function execScene ($sceneId) { + $sceneData = SceneManager::getScene($sceneId); + $sceneDoJson = $sceneData['do_something']; + $sceneDoArray = json_decode($sceneDoJson); + foreach ($sceneDoArray as $deviceId => $deviceState) { + RecordManager::create($deviceId, 'on/off', $deviceState); + } + return true; + } + + public static function delete($sceneId){ + Db::command ('DELETE FROM scenes WHERE scene_id=?', array ($sceneId)); + } +} +?> diff --git a/app/models/UserManager.php b/app/models/UserManager.php new file mode 100644 index 0000000..05fd3ef --- /dev/null +++ b/app/models/UserManager.php @@ -0,0 +1,210 @@ +getMessage(); + die(); + } + } + + public static function getUser ($userName) { + try { + $user = Db::loadOne ("SELECT * FROM users WHERE username = ?", [$userName]); + return $user; + } catch(PDOException $error) { + echo $error->getMessage(); + die(); + } + } + + public static function getUserId ($userId) { + try { + $user = Db::loadOne ("SELECT * FROM users WHERE user_id = ?", [$userId]); + return $user; + } catch(PDOException $error) { + echo $error->getMessage(); + die(); + } + } + + public static function getAvatarUrl($userId = null){ + $email = self::getUserData('email'); + if ($userId != null){ + $email = self::getUserData('email',$userId); + } + return 'https://secure.gravatar.com/avatar/' . md5( strtolower( trim( $email ) ) ); + } + + public static function login ($username, $password, $rememberMe) { + try { + if ($user = Db::loadOne ('SELECT * FROM users WHERE LOWER(username)=LOWER(?)', array ($username))) { + if ($user['password'] == UserManager::getHashPassword($password)) { + if (isset($rememberMe) && $rememberMe == 'true') { + setcookie ("rememberMe", self::setEncryptedCookie($user['username']), time () + (30 * 24 * 60 * 60 * 1000), BASEDIR, $_SERVER['HTTP_HOST'], 1); + } + $_SESSION['user']['id'] = $user['user_id']; + $page = ""; + if ($user["startPage"] == 1) { + $page = "dashboard"; + } + unset($_POST['login']); + return $page; + } else { + throw new PDOException("Heslo není správné!"); + } + } else { + throw new PDOException("Uživatel s tím to jménem neexistuje!"); + } + } catch(PDOException $error) { + echo $error->getMessage(); + die(); + } + } + + public static function loginNew ($username, $password) { + try { + if ($user = Db::loadOne ('SELECT * FROM users WHERE LOWER(username)=LOWER(?)', array ($username))) { + if ($user['password'] == UserManager::getHashPassword($password)) { + echo "user loged in"; + return $user['user_id']; + } else { + return false; + } + } else { + return false; + } + } catch(PDOException $error) { + echo $error->getMessage(); + die(); + } + } + + public static function isLogin () { + if (isset ($_SESSION['user']) && isset($_SESSION['user']['id'])) { + return true; + } else { + if (isset ($_COOKIE['rememberMe'])){ + if ($user = Db::loadOne ('SELECT * FROM users WHERE LOWER(username)=LOWER(?)', array (self::getDecryptedCookie($_COOKIE['rememberMe'])))) { + $_SESSION['user']['id'] = $user['user_id']; + return true; + } + } + } + return false; + } + + public static function logout () { + unset($_SESSION['user']); + session_destroy(); + if (isset($_COOKIE['rememberMe'])){ + unset($_COOKIE['rememberMe']); + setcookie("rememberMe", 'false', time(), BASEDIR, $_SERVER['HTTP_HOST']); + } + } + + public static function setEncryptedCookie($value){ + $first_key = base64_decode(FIRSTKEY); + $second_key = base64_decode(SECONDKEY); + + $method = "aes-256-cbc"; + $ivlen = openssl_cipher_iv_length($method); + $iv = openssl_random_pseudo_bytes($ivlen); + $newvalue_raw = openssl_encrypt($value, $method, $first_key, OPENSSL_RAW_DATA, $iv); + $hmac = hash_hmac('sha256', $newvalue_raw, $second_key, TRUE); + $newvalue = base64_encode ($iv.$hmac.$newvalue_raw); + return $newvalue; + } + + public static function getDecryptedCookie($value){ + $first_key = base64_decode(FIRSTKEY); + $second_key = base64_decode(SECONDKEY); + + $c = base64_decode($value); + $method = "aes-256-cbc"; + $ivlen = openssl_cipher_iv_length($method); + $iv = substr($c, 0, $ivlen); + $hmac = substr($c, $ivlen, 32); + $newValue_raw = substr($c, $ivlen+32); + $newValue = openssl_decrypt($newValue_raw, $method, $first_key, OPENSSL_RAW_DATA, $iv); + $calcmac = hash_hmac('sha256', $newValue_raw, $second_key, TRUE); + if (hash_equals ($hmac, $calcmac)) { + return $newValue; + } + return false; + } + + public static function getUserData ($type, $userId = '') { + if ($userId == '') { + $userId = $_SESSION['user']['id']; + } + $user = Db::loadOne ('SELECT ' . $type . ' FROM users WHERE user_id=?', array ($userId)); + return $user[$type]; + } + + public static function setUserData ($type, $value) { + if (isset ($_SESSION['user']['id'])) { + Db::command ('UPDATE users SET ' . $type . '=? WHERE user_id=?', array ($value, $_SESSION['user']['id'])); + } + } + + public static function getHashPassword ($password) { + $salt = "s0mRIdlKvI"; + $hashPassword = hash('sha512', ($password . $salt)); + return $hashPassword; + } + + public static function atHome($userId, $atHome){ + try { + Db::edit ('users', ['at_home' => $atHome], 'WHERE user_id = ?', array($userId)); + } catch(PDOException $error) { + echo $error->getMessage(); + die(); + } + } + + public static function changePassword($oldPassword, $newPassword, $newPassword2){ + if ($newPassword == $newPassword2) { + //Password Criteria + $oldPasswordSaved = self::getUserData('password'); + if (self::getHashPassword($oldPassword) == $oldPasswordSaved) { + self::setUserData('password', self::getHashPassword($newPassword)); + } else { + throw new Exception ("old password did not match"); + } + } else { + throw new Exception ("new password arent same"); + } + } + + public static function createUser($userName, $password){ + $userId = Db::loadOne('SELECT * FROM users WHERE username = ?;', array($userName))['user_id']; + if ($userId != null) { + return false; + }; + try { + $user = [ + 'username' => $userName, + 'password' => self::getHashPassword($password), + ]; + return Db::add ('users', $user); + } catch(PDOException $error) { + echo $error->getMessage(); + die(); + } + } + + public static function haveOtaEnabled($userName){ + $ota = self::getUser($userName)['ota']; + + if ($ota != ''){ + return ($ota != '' ? $ota : false); + } else { + return false; + } + } +} +?> diff --git a/app/models/Utilities.php b/app/models/Utilities.php new file mode 100644 index 0000000..32b66af --- /dev/null +++ b/app/models/Utilities.php @@ -0,0 +1,144 @@ + 'a', + '/[ÁÀÂÃÄ]/u' => 'A', + '/[ÍÌÎÏ]/u' => 'I', + '/[íìîï]/u' => 'i', + '/[ěéèêë]/u' => 'e', + '/[ĚÉÈÊË]/u' => 'E', + '/[óòôõºö]/u' => 'o', + '/[ÓÒÔÕÖ]/u' => 'O', + '/[úùûü]/u' => 'u', + '/[ÚÙÛÜ]/u' => 'U', + '/Š/' => 'S', + '/š/' => 's', + '/Č/' => 'C', + '/č/' => 'c', + '/ř/' => 'r', + '/Ř/' => 'R', + '/Ý/' => 'Y', + '/ý/' => 'y', + '/ç/' => 'c', + '/Ç/' => 'C', + '/ñ/' => 'n', + '/Ñ/' => 'N', + '/–/' => '-', // UTF-8 hyphen to "normal" hyphen + '/[’‘‹›‚]/u' => ' ', // Literally a single quote + '/[“”«»„]/u' => ' ', // Double quote + '/ /' => ' ', // nonbreaking space (equiv. to 0x160) + ); + return preg_replace(array_keys($utf8), array_values($utf8), $text); + } + + static function stringInsert($str,$insertstr,$pos) + { + $str = substr($str, 0, $pos) . $insertstr . substr($str, $pos); + return $str; + } + + /** + * [generateGraphJson description] + * @param string $type [line/bar] + * @param array $data [description] + * @param array $options [description] + * @return [type] [description] + */ + + static function generateGraphJson(string $type = 'line', array $data = [], array $options = []){ + $array = [ + 'type' => $type, + 'data' => [ + 'datasets' => [ + [ + 'data' => $data, + 'borderColor' => "#d4def7", + 'backgroundColor' => "#d4def7" + ] + ] + ], + 'options' => [ + 'scales' => [ + 'xAxes' => [ + [ + 'type' => 'time', + 'distribution' => 'linear', + ] + ], + 'yAxes' => [ + [ + 'ticks' => [ + 'min' => $options['min'], + 'max' => $options['max'], + 'steps' => $options['scale'] + ] + ] + ] + ], + 'legend' => [ + 'display' => false + ], + 'tooltips' => [ + 'enabled' => true + ], + 'hover' => [ + 'mode' => true + ] + ] + ]; + return json_encode($array, JSON_PRETTY_PRINT); + } + + static function ago( $datetime ) + { + $interval = date_create('now')->diff( $datetime ); + $suffix = ( $interval->invert ? ' ago' : '' ); + if ( $v = $interval->y >= 1 ) return self::pluralize( $interval->m, 'month' ) . $suffix; + if ( $v = $interval->d >= 1 ) return self::pluralize( $interval->d, 'day' ) . $suffix; + if ( $v = $interval->h >= 1 ) return self::pluralize( $interval->h, 'hour' ) . $suffix; + if ( $v = $interval->i >= 1 ) return self::pluralize( $interval->i, 'minute' ) . $suffix; + return self::pluralize( $interval->s, 'second' ) . $suffix; + } + + static function pluralize( $count, $text ) + { + return $count . ( ( $count == 1 ) ? ( " $text" ) : ( " ${text}s" ) ); + } + + static function checkOperator($value1, $operator, $value2) { + switch ($operator) { + case '<': // Less than + return $value1 < $value2; + case '<=': // Less than or equal to + return $value1 <= $value2; + case '>': // Greater than + return $value1 > $value2; + case '>=': // Greater than or equal to + return $value1 >= $value2; + case '==': // Equal + return ($value1 == $value2); + case '===': // Identical + return $value1 === $value2; + case '!==': // Not Identical + return $value1 !== $value2; + case '!=': // Not equal + case '<>': // Not equal + return $value1 != $value2; + case '||': // Or + case 'or': // Or + return $value1 || $value2; + case '&&': // And + case 'and': // And + return $value1 && $value2; + case 'xor': // Or + return $value1 xor $value2; + default: + return FALSE; + } // end switch + } +} diff --git a/app/models/managers/AuthManager.php b/app/models/managers/AuthManager.php new file mode 100644 index 0000000..88c96a6 --- /dev/null +++ b/app/models/managers/AuthManager.php @@ -0,0 +1,45 @@ +loginNew($username, $password); + + if ($userLogedIn != false){ + // Create token header as a JSON string + $header = json_encode(['typ' => 'JWT', 'alg' => 'HS256']); + // Create token payload as a JSON string + $payload = json_encode(['user_id' => $userLogedIn]); + // Encode Header to Base64Url String + $base64UrlHeader = str_replace(['+', '/', '='], ['-', '_', ''], base64_encode($header)); + // Encode Payload to Base64Url String + $base64UrlPayload = str_replace(['+', '/', '='], ['-', '_', ''], base64_encode($payload)); + // Create Signature Hash + $signature = hash_hmac('sha256', $base64UrlHeader . "." . $base64UrlPayload, 'abC123!', true); + // Encode Signature to Base64Url String + $base64UrlSignature = str_replace(['+', '/', '='], ['-', '_', ''], base64_encode($signature)); + // Create JWT + $jwt = $base64UrlHeader . "." . $base64UrlPayload . "." . $base64UrlSignature; + + return $jwt; + } + } + return false; + } + + public function deleteToken($token){ + Db::command ('DELETE FROM tokens WHERE token=?', array ($token)); + return true; + } + + public function validateToken($token){ + $tokens = Db::loadAll('SELECT * FROM tokens WHERE token = ? AND expire >= CURRENT_TIMESTAMP AND blocked = 0;', array($token)); + if (count($tokens) == 1) { + return true; + } else if (count($tokens) == 0) { + return false; + }; + return false; + } +} diff --git a/app/models/managers/AutomationManager.php b/app/models/managers/AutomationManager.php new file mode 100644 index 0000000..aacf6f7 --- /dev/null +++ b/app/models/managers/AutomationManager.php @@ -0,0 +1,175 @@ + $name, + 'owner_id' => $userId, + 'on_days' => $onDays, + 'if_something' => $ifCode, + 'do_something' => $doCode, + ); + try { + if ($automationId == "") { + Db::add ('automation', $scene); + } else { + Db::edit ('automation', $scene, 'WHERE automation_id = ?', array ($automationId)); + } + } catch(PDOException $error) { + echo $error->getMessage(); + die(); + } + } + + public static function getAll(){ + return Db::loadAll ("SELECT * FROM automation"); + + } + + public static function executeAll(){ + global $logManager; + + $automations = Db::loadAll ("SELECT * FROM automation"); + $dayNameNow = strtolower (date('D', time())); + + foreach ($automations as $automation) { + $onValue = json_decode($automation['if_something'], true); + $sceneDoJson = $automation['do_something']; + $actionDays = json_decode($automation['on_days'], true); + $value = time(); + $run = false; + $restart = false; + + if ($automation['active'] == 1 && $automation['locked'] != 1){ + Db::edit('automation', array('locked' => 1), 'WHERE automation_id = ?', array($automation['automation_id'])); + if (in_array($dayNameNow, $actionDays)){ + if (in_array($onValue['type'], ['sunSet', 'sunRise', 'time','now'])) { + if ($onValue['type'] == 'sunSet') { + $value = date_sunset($value, SUNFUNCS_RET_TIMESTAMP, 50.0755381 , 14.4378005, 90); + } else if ($onValue['type'] == 'sunRise') { + $value = date_sunrise($value, SUNFUNCS_RET_TIMESTAMP, 50.0755381 , 14.4378005, 90); + } else if ($onValue['type'] == 'time') { + $onValue = explode(':',$onValue['value']); + $today = date_create('now'); + $onValue = $today->setTime($onValue[0], $onValue[1]); + $value = $today->getTimestamp(); + } + + if (time() > $value && $automation['executed'] == 0){ + $run = true; + } else if (time() < $value && $automation['executed'] == 1) { //recovery realowing of automation + $restart = true; + } + + } else if ($onValue['type'] == 'outHome') { + //TODO: Add Ovner to automation + $userHomeStatus = UserManager::getUserData('at_home', $onValue['value']); + if ($userHomeStatus == 'false' && $automation['executed'] == 0) { + $run = true; + } else if ($userHomeStatus == 'true' && $automation['executed'] == 1) { + $restart = true; + } + } else if ($onValue['type'] == 'inHome') { + //TODO: Add Ovner to automation + $userHomeStatus = UserManager::getUserData('at_home', $onValue['value']); + if ($userHomeStatus == 'true' && $automation['executed'] == 0) { + $run = true; + } else if ($userHomeStatus == 'false' && $automation['executed'] == 1) { + $restart = true; + } + } else if ($onValue['type'] == 'noOneHome') { + $users = UserManager::getUsers(); + $membersHome = 0; + foreach ($users as $key => $user) { + if ($user['at_home'] == 'true'){ + $membersHome++; + } + } + if ($membersHome == 0 && $automation['executed'] == 0) { + $run = true; + } else if ($membersHome > 0 && $automation['executed'] == 1){ + $restart = true; + } + } else if ($onValue['type'] == 'someOneHome') { + $users = UserManager::getUsers(); + $membersHome = 0; + foreach ($users as $key => $user) { + if ($user['at_home'] == 'true'){ + $membersHome++; + } + } + if ($membersHome == 0 && $automation['executed'] == 1) { + $restart = true; + } else if ($membersHome > 0 && $automation['executed'] == 0){ + $run = true; + } + } else if ($onValue['type'] == 'atDeviceValue') { + + $subDeviceId = SubDeviceManager::getSubDeviceByMaster($onValue['value']['deviceID'], $onValue['value']['type'])["subdevice_id"]; + $lastValue = RecordManager::getLastRecord($subDeviceId); + + if ($lastValue['value'] == $onValue['value']['value'] && $automation['executed'] == 0) { + $run = true; + + } else if ($lastValue['value'] != $onValue['value']['value'] && $automation['executed'] == 1){ + $restart = true; + + } + } + + //finalization + if ($run) { + $body = ''; + + $sceneDoArray = json_decode($sceneDoJson); + foreach ($sceneDoArray as $deviceId => $deviceState) { + RecordManager::create($deviceId, 'on/off', $deviceState); + } + + $subscribers = NotificationManager::getSubscription(); + $i = 0; + + $notificationMng = new NotificationManager; + $notificationData = [ + 'title' => 'Automatization', + 'body' => 'Automatization '.$automation['name']." was just executed", + 'icon' => BASEDIR . '/app/templates/images/icon-192x192.png', + ]; + + if ($notificationData != []) { + $subscribers = $notificationMng::getSubscription(); + foreach ($subscribers as $key => $subscriber) { + $logManager->write("[NOTIFICATION/AUTOOMATION] SENDING TO" . $subscriber['id'] . " "); + $notificationMng::sendSimpleNotification(SERVERKEY, $subscriber['token'], $notificationData); + } + } + + $logManager->write("[AUTOMATIONS] automation id ". $automation['automation_id'] . " was executed"); + Db::edit('automation', array('executed' => 1, 'execution_time' => date("Y-m-d H:i:s")), 'WHERE automation_id = ?', array($automation['automation_id'])); + } else if ($restart) { + $logManager->write("[AUTOMATIONS] automation id ". $automation['automation_id'] . " was restarted"); + Db::edit('automation', array('executed' => 0), 'WHERE automation_id = ?', array($automation['automation_id'])); + } + Db::edit('automation', array('locked' => 0), 'WHERE automation_id = ?', array($automation['automation_id'])); + } + } + } + } +} diff --git a/app/models/managers/ChartManager.php b/app/models/managers/ChartManager.php new file mode 100644 index 0000000..d26757c --- /dev/null +++ b/app/models/managers/ChartManager.php @@ -0,0 +1,129 @@ +Aktuální Hodnota: '.$data[0]['value']; + echo ""; + echo '
'; + echo '
'; + for ($valuesRow = 0; $valuesRow < count($data); $valuesRow++) { + $row = $data[$valuesRow]; + + echo '
'; + } + echo '
'; + echo '
'; + echo ''; + echo 'Poslední Update: '; + + echo ' + '; + } + + function generateChartData(int $subDeviceId, string $periode, string $groupBy) { + $chartData = []; + + $subDevice = SubDeviceManager::getSubDevice($subDeviceId); + $records = RecordManager::getAllRecordForGraph($subDeviceId, $periode, $groupBy); + + $array = array_column($records, 'value'); + $arrayTime = array_column($records, 'time'); + $output = []; + + foreach ($array as $key => $value) { + $output[$key]['y'] = $value; + if ($subDevice['type'] == 'light'){ + if ($value > 810){ + $output[$key]['y'] = 1; + } else { + $output[$key]['y'] = 0; + } + } + + $timeStamp = new DateTime($arrayTime[$key]); + $output[$key]['t'] = $timeStamp->format("Y-m-d") . 'T' . $timeStamp->format("H:i:s") . 'Z'; + } + + $data = json_encode($output); + $data = $output; + $arrayTimeStamps = array_column($records, 'time'); + foreach ($arrayTimeStamps as $key => $value) { + $arrayTimeStamps[$key] = (new DateTime($value))->format(TIMEFORMAT); + } + + $chartData['graphRange'] = RANGES[$subDevice['type']]; + $chartData['graphType'] = RANGES[$subDevice['type']]['graph']; + $chartData['graphData'] = $data; + + return $chartData; + } +} +?> diff --git a/app/models/managers/DashboardManager.php b/app/models/managers/DashboardManager.php new file mode 100644 index 0000000..b241a35 --- /dev/null +++ b/app/models/managers/DashboardManager.php @@ -0,0 +1,41 @@ + UserManager::getUserData('user_id'), + 'subdevice_id' => $subDeviceId, + ); + try { + Db::add ('dashboard', $dashboardItem); + } catch(PDOException $error) { + echo $error->getMessage(); + die(); + } + } + } + + static function Remove ($subDeviceId){ + $userId = UserManager::getUserData('user_id'); + Db::command ('DELETE FROM dashboard WHERE subdevice_id=? AND user_id = ?', array ($subDeviceId, $userId)); + } +} diff --git a/app/models/managers/DeviceManager.php b/app/models/managers/DeviceManager.php new file mode 100644 index 0000000..53255f8 --- /dev/null +++ b/app/models/managers/DeviceManager.php @@ -0,0 +1,96 @@ + $name, + 'token' => $token, + 'room_id' => $defaultRoom, + ); + try { + Db::add ('devices', $device); + return Db::loadOne("SELECT device_id FROM devices WHERE token = ?", array($token))['device_id']; + } catch(PDOException $error) { + echo $error->getMessage(); + die(); + } + } + + public static function edit ($deviceId, $values = []) { + try { + Db::edit ('devices', $values, 'WHERE device_id = ?', array($deviceId)); + } catch(PDOException $error) { + echo $error->getMessage(); + die(); + } + } + + public static function editByToken ($token, $values = []) { + try { + Db::edit ('devices', $values, 'WHERE token = ?', array($token)); + } catch(PDOException $error) { + echo $error->getMessage(); + die(); + } + } + + /** + * [assignRoom Přiřazení zařízení do třídy] + * @param [type] $roomId [číslo místnosti do kter se má zařízení přiřadit] + * @param [type] $deviceId [Číslo zařízení které chcete přiřadit do místnosti] + */ + public static function assignRoom ($roomId, $deviceId) { + $device = array ( + 'room_id' => $roomId, + ); + try { + Db::edit ('devices', $device, 'WHERE device_id = ?', array($deviceId)); + } catch(PDOException $error) { + echo $error->getMessage(); + die(); + } + } + + /** + * [delete Smazání zařízení] + * @param [type] $deviceId [Id zařízení ke smazání] + */ + public static function delete ($deviceId) { + Db::command ('DELETE FROM devices WHERE device_id=?', array ($deviceId)); + } + + public static function registeret ($deviceToken) { + return (count(Db::loadAll ("SELECT * FROM devices WHERE token=?", array($deviceToken))) == 1 ? true : false); + } + + public static function approved ($deviceToken) { + return (count(Db::loadAll ("SELECT * FROM devices WHERE token=? AND approved = ?", array($deviceToken, 1))) == 1 ? true : false); + } +} +?> diff --git a/app/models/managers/FallbackManager.php b/app/models/managers/FallbackManager.php new file mode 100644 index 0000000..cb3fb79 --- /dev/null +++ b/app/models/managers/FallbackManager.php @@ -0,0 +1,44 @@ +deviceDefinitions = $deviceDefinition; + } + + function check(){ + //TODO: FIX IT + $allDevicesData = DeviceManager::getAllDevices(); + foreach ($allDevicesData as $deviceKey => $deviceValue) { + $allSubDevicesData = SubDeviceManager::getAllSubDevices($deviceValue['device_id']); + foreach ($allSubDevicesData as $subDeviceKey => $subDeviceValue) { + if (!isset($this->deviceDefinitions[$subDeviceValue['type']]["fallBack"])) { + continue; + } + + if (!isset($this->deviceDefinitions[$subDeviceValue['type']]["fallBackTime"])) { + continue; + } + + $lastRecord = RecordManager::getLastRecord($subDeviceValue['subdevice_id']); + if ($lastRecord["value"] == $this->deviceDefinitions[$subDeviceValue['type']]["fallBack"]) { + continue; + } + + $minutes = (time() - strtotime($lastRecord['time'])) / 60; + + if ( $minutes > $this->deviceDefinitions[$subDeviceValue['type']]["fallBackTime"]){ + RecordManager::create($deviceValue['device_id'], $subDeviceValue['type'], $this->deviceDefinitions[$subDeviceValue['type']]["fallBack"]); + } + } + } + } +} diff --git a/app/models/managers/LanguageManager.php b/app/models/managers/LanguageManager.php new file mode 100644 index 0000000..507bd88 --- /dev/null +++ b/app/models/managers/LanguageManager.php @@ -0,0 +1,60 @@ +lngCode = $lngCode; + $this->debug = $debug; + } + + function load() + { + $file = '../lang/en.php'; + if (!file_exists($file)){ + echo 'ERROR: en.php not found'; + die(); + //TODO add lng EXEPTIONS + } + $arrayFirst = include($file); + $file = '../lang/' . $this->lngCode . '.php'; + $arraySecond = []; + if (file_exists($file)){ + $arraySecond = include($file); + } + $this->lngDatabase = array_merge($arrayFirst, $arraySecond); + return true; + } + + function get(string $stringKey) + { + if ($this->debug) { + return $stringKey; + } + if (isset($this->lngDatabase[$stringKey])) { + return $this->lngDatabase[$stringKey]; + } + return $stringKey; + } + + function echo(string $stringKey) + { + if ($this->debug) { + echo $stringKey; + return; + } + if (isset($this->lngDatabase[$stringKey])) { + echo $this->lngDatabase[$stringKey]; + return; + } + echo $stringKey; + return; + } +} diff --git a/app/models/managers/LogManager.php b/app/models/managers/LogManager.php new file mode 100644 index 0000000..dde1c14 --- /dev/null +++ b/app/models/managers/LogManager.php @@ -0,0 +1,57 @@ + $file) { + if (in_array($file,array(".","..", ".gitkeep", $todayFileName))) + { + continue; + } + if (filemtime($file) > $seconds) { + unlink('../logs/'.$file); + } + } + } +} + +class LogManager +{ + + private $logFile; + function __construct($fileName = "") + { + if ($fileName == ""){ + $fileName = '../logs/'. date("Y-m-d").'.log'; + } + if(!is_dir("../logs/")) + { + mkdir("../logs/"); + } + $this->logFile = fopen($fileName, "a") or die("Unable to open file!"); + } + + function write($value, $type = LogRecordType::ERROR){ + $record = "[".date("H:m:s")."][".$type."]" . $value . "\n"; + fwrite($this->logFile, $record); + } + + function __destruct(){ + if (isset($this->logFile)) { + fclose($this->logFile); + } + } +} diff --git a/app/models/managers/NetworkManager.php b/app/models/managers/NetworkManager.php new file mode 100644 index 0000000..247e0df --- /dev/null +++ b/app/models/managers/NetworkManager.php @@ -0,0 +1,18 @@ + $userID, + 'token' => $token, + ); + Db::add ('notifications', $notification); + } + } + + function getSubscription () { + return Db::loadAll ("SELECT * FROM notifications"); + } + + function sendSimpleNotification(string $serverKey, string $to, array $data, bool $timeStamp = false){ + $dataTemplate = [ + 'title' => '', + 'body' => '', + 'icon' => '', + ]; + + if (array_diff_key ($dataTemplate , $data)){ + return; + } + + if ($timeStamp) { + $data['title'] = $data['title'] . date(); + } + + $notification = new Notification($serverKey); + $notification->to($to); + $notification->notification($data['title'], $data['body'], $data['icon'], ''); + $answer = $notification->send(); + $notification = null; + + return $answer; + } +} + +class Notification +{ + public $server_key = ''; + public $jsonPayload = [ + "to" => '', + "data" => [ + "notification" => [ + "body" => '', + "title" => '', + "icon" => '', + "click_action" => '', + ] + ] + ]; + + function __construct($serverKey = '') + { + $this->server_key = $serverKey; + } + + function to($to = ''){ + $this->jsonPayload["to"] = $to; + } + + function notification($title = '', $body = '', $icon = '', $action = '', bool $timeStamp = false) + { + if ($timeStamp) { + $data['title'] = $data['title'] . date(); + } + + $this->jsonPayload["data"]["notification"]["title"] = $title; + $this->jsonPayload["data"]["notification"]["body"] = $body; + $this->jsonPayload["data"]["notification"]["icon"] = $icon; + $this->jsonPayload["data"]["notification"]["click_action"] = $action; + } + + function send(){ + $data = json_encode($this->jsonPayload); + $url = 'https://fcm.googleapis.com/fcm/send'; + $headers = array( + 'Content-Type:application/json', + 'Authorization:key='.$this->server_key, + ); + + $ch = curl_init(); + curl_setopt($ch, CURLOPT_URL, $url); + curl_setopt($ch, CURLOPT_POST, true); + curl_setopt($ch, CURLOPT_HTTPHEADER, $headers); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); + curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0); + curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); + curl_setopt($ch, CURLOPT_POSTFIELDS, $data); + $result = curl_exec($ch); + if ($result === FALSE) { + die('Oops! FCM Send Error: ' . curl_error($ch)); + } + curl_close($ch); + return $result; + } +} diff --git a/app/models/managers/RecordManager.php b/app/models/managers/RecordManager.php new file mode 100644 index 0000000..143b6a2 --- /dev/null +++ b/app/models/managers/RecordManager.php @@ -0,0 +1,106 @@ + 1, + ]; + Db::edit ('records', $record, 'WHERE subdevice_id = ?', array ($subDeviceId)); + $record = array ( + 'subdevice_id' => $subDeviceId, + 'value' => $value, + ); + return Db::add ('records', $record); + } catch(PDOException $error) { + echo $error->getMessage(); + die(); + } + } + + public static function create ($deviceId, $type, $value) { + $subDeviceId = Db::loadOne('SELECT * FROM subdevices WHERE device_id = ? AND type = ?;', array($deviceId, $type))['subdevice_id']; + if ($subDeviceId == '') { + return false; + }; + try { + $record = [ + 'execuded' => 1, + ]; + Db::edit ('records', $record, 'WHERE subdevice_id = ?', array ($subDeviceId)); + $record = array ( + 'subdevice_id' => $subDeviceId, + 'value' => $value, + ); + return Db::add ('records', $record); + } catch(PDOException $error) { + echo $error->getMessage(); + die(); + } + } + + + public static function setExecuted($recordId) { + try { + Db::edit ('records', ['execuded' => 1], 'WHERE record_id = ?', array($recordId)); + } catch(PDOException $error) { + echo $error->getMessage(); + die(); + } + } + + public static function getRecordById($recordId) { + return Db::loadOne('SELECT * FROM records WHERE record_id = ?;', array($recordId)); + } + + public static function getLastInsertedRecordId() { + return Db::insertId(); + } + + public static function getLastRecord($subDeviceId, $num = 1) { + if ($num == 1) + return Db::loadOne('SELECT * FROM records WHERE subdevice_id = ? AND value != ? ORDER BY time DESC;', array($subDeviceId, 999)); + return Db::loadAll('SELECT * FROM records WHERE subdevice_id = ? AND value != ? ORDER BY time DESC LIMIT ?;', array($subDeviceId, 999, $num)); + } + + public static function getLastRecordNotNull($subDeviceId) { + return Db::loadOne('SELECT * FROM records WHERE subdevice_id = ? AND value != ? ORDER BY time DESC;', array($subDeviceId, 0)); + } + + public static function getAllRecord($subDeviceId, $timeFrom, $timeTo) { + return Db::loadAll('SELECT * FROM records WHERE subdevice_id = ? AND time >= ? AND time <= ? AND value != ? ORDER BY time;', array($subDeviceId, $timeFrom, $timeTo, 999)); + } + + public static function getAllRecordForGraph($subDeviceId, $period = "day", $groupBy = "hour") { + $periodLocal = '- 1 ' . strtoupper($period); + $dateTime = new DateTime(); + $dateTime = $dateTime->modify($periodLocal); + $dateTime = $dateTime->format('Y-m-d'); + $groupBy = strtoupper($groupBy).'(time)'; + $sql = 'SELECT value, time FROM records + WHERE + subdevice_id = ? + AND + value != 999 + AND + time > ? + GROUP BY '.$groupBy.' + ORDER BY time ASC'; + //TODO: Prasárna Opravit + return Db::loadAll($sql, array($subDeviceId, $dateTime)); + } + + public static function clean ($day) { + if (isset($day)) { + Db::command ('DELETE FROM records WHERE `time` < ADDDATE(NOW(), INTERVAL -? DAY);', array($day)); + } + } + + + //TODO: zkontrolovat jestli neco nezbilo po smazaní + public static function cleanSubdeviceRecords ($subDeviceId) { + Db::command ('DELETE FROM records WHERE subdevice_id = ?);', array($subDeviceId)); + } +} +?> diff --git a/app/models/managers/RoomManager.php b/app/models/managers/RoomManager.php new file mode 100644 index 0000000..795ee79 --- /dev/null +++ b/app/models/managers/RoomManager.php @@ -0,0 +1,36 @@ + $name, + ); + try { + Db::add ('rooms', $room); + } catch(PDOException $error) { + echo $error->getMessage(); + die(); + } + } + + public static function delete ($roomId) { + Db::command ('DELETE FROM rooms WHERE room_id=?', array ($roomId)); + } +} +?> diff --git a/app/models/managers/SceneManager.php b/app/models/managers/SceneManager.php new file mode 100644 index 0000000..2cd7fb8 --- /dev/null +++ b/app/models/managers/SceneManager.php @@ -0,0 +1,41 @@ + $icon, + 'name' => $name, + 'do_something' => $doCode, + ); + try { + Db::add ('scenes', $scene); + } catch(PDOException $error) { + echo $error->getMessage(); + die(); + } + } + + public static function getAllScenes () { + return Db::loadAll ("SELECT * FROM scenes"); + } + + public static function getScene ($sceneId) { + return Db::loadOne("SELECT * FROM scenes WHERE scene_id = ?", array($sceneId)); + } + + public static function execScene ($sceneId) { + $sceneData = SceneManager::getScene($sceneId); + $sceneDoJson = $sceneData['do_something']; + $sceneDoArray = json_decode($sceneDoJson); + foreach ($sceneDoArray as $deviceId => $deviceState) { + RecordManager::create($deviceId, 'on/off', $deviceState); + } + return true; + } + + public static function delete($sceneId){ + Db::command ('DELETE FROM scenes WHERE scene_id=?', array ($sceneId)); + } +} +?> diff --git a/app/models/managers/SubDeviceManager.php b/app/models/managers/SubDeviceManager.php new file mode 100644 index 0000000..712db1d --- /dev/null +++ b/app/models/managers/SubDeviceManager.php @@ -0,0 +1,97 @@ + $type) { + $parsedTypes[$orderNum] = $type['type']; + } + return $parsedTypes; + } + + //check if dubdevice exist + + public static function create($deviceId, $type, $unit) + { + $record = array( + 'device_id' => $deviceId, + 'type' => $type, + 'unit' => $unit, + ); + try { + Db::add('subdevices', $record); + } catch (PDOException $error) { + echo $error->getMessage(); + die(); + } + } + + public static function remove($subDeviceId) + { + RecordManager::cleanSubdeviceRecords($subDeviceId); + return Db::loadAll("DELETE FROM subdevices WHERE subdevice_id = ?", array($subDeviceId)); + } + + public static function getSubdevicesByRoomIds($roomIds = NULL) { + if(empty($roomIds)) return NULL; + + $rows = Db::loadAll(" + SELECT d.room_id, sd.subdevice_id, sd.device_id, d.name, sd.type, sd.unit, r.value FROM subdevices sd + JOIN devices d ON sd.device_id = d.device_id + JOIN records r ON r.subdevice_id = sd.subdevice_id + WHERE d.room_id IN (".str_repeat("?,", count($roomIds)-1)."?) + AND r.record_id IN ( + SELECT MAX(record_id) + FROM records + GROUP BY subdevice_id + ) + ", $roomIds); + + $ret = []; + foreach($rows as $row){ + $ret[$row['room_id']][] = $row; + } + + return $ret; + } +} diff --git a/app/models/managers/UserManager.php b/app/models/managers/UserManager.php new file mode 100644 index 0000000..05fd3ef --- /dev/null +++ b/app/models/managers/UserManager.php @@ -0,0 +1,210 @@ +getMessage(); + die(); + } + } + + public static function getUser ($userName) { + try { + $user = Db::loadOne ("SELECT * FROM users WHERE username = ?", [$userName]); + return $user; + } catch(PDOException $error) { + echo $error->getMessage(); + die(); + } + } + + public static function getUserId ($userId) { + try { + $user = Db::loadOne ("SELECT * FROM users WHERE user_id = ?", [$userId]); + return $user; + } catch(PDOException $error) { + echo $error->getMessage(); + die(); + } + } + + public static function getAvatarUrl($userId = null){ + $email = self::getUserData('email'); + if ($userId != null){ + $email = self::getUserData('email',$userId); + } + return 'https://secure.gravatar.com/avatar/' . md5( strtolower( trim( $email ) ) ); + } + + public static function login ($username, $password, $rememberMe) { + try { + if ($user = Db::loadOne ('SELECT * FROM users WHERE LOWER(username)=LOWER(?)', array ($username))) { + if ($user['password'] == UserManager::getHashPassword($password)) { + if (isset($rememberMe) && $rememberMe == 'true') { + setcookie ("rememberMe", self::setEncryptedCookie($user['username']), time () + (30 * 24 * 60 * 60 * 1000), BASEDIR, $_SERVER['HTTP_HOST'], 1); + } + $_SESSION['user']['id'] = $user['user_id']; + $page = ""; + if ($user["startPage"] == 1) { + $page = "dashboard"; + } + unset($_POST['login']); + return $page; + } else { + throw new PDOException("Heslo není správné!"); + } + } else { + throw new PDOException("Uživatel s tím to jménem neexistuje!"); + } + } catch(PDOException $error) { + echo $error->getMessage(); + die(); + } + } + + public static function loginNew ($username, $password) { + try { + if ($user = Db::loadOne ('SELECT * FROM users WHERE LOWER(username)=LOWER(?)', array ($username))) { + if ($user['password'] == UserManager::getHashPassword($password)) { + echo "user loged in"; + return $user['user_id']; + } else { + return false; + } + } else { + return false; + } + } catch(PDOException $error) { + echo $error->getMessage(); + die(); + } + } + + public static function isLogin () { + if (isset ($_SESSION['user']) && isset($_SESSION['user']['id'])) { + return true; + } else { + if (isset ($_COOKIE['rememberMe'])){ + if ($user = Db::loadOne ('SELECT * FROM users WHERE LOWER(username)=LOWER(?)', array (self::getDecryptedCookie($_COOKIE['rememberMe'])))) { + $_SESSION['user']['id'] = $user['user_id']; + return true; + } + } + } + return false; + } + + public static function logout () { + unset($_SESSION['user']); + session_destroy(); + if (isset($_COOKIE['rememberMe'])){ + unset($_COOKIE['rememberMe']); + setcookie("rememberMe", 'false', time(), BASEDIR, $_SERVER['HTTP_HOST']); + } + } + + public static function setEncryptedCookie($value){ + $first_key = base64_decode(FIRSTKEY); + $second_key = base64_decode(SECONDKEY); + + $method = "aes-256-cbc"; + $ivlen = openssl_cipher_iv_length($method); + $iv = openssl_random_pseudo_bytes($ivlen); + $newvalue_raw = openssl_encrypt($value, $method, $first_key, OPENSSL_RAW_DATA, $iv); + $hmac = hash_hmac('sha256', $newvalue_raw, $second_key, TRUE); + $newvalue = base64_encode ($iv.$hmac.$newvalue_raw); + return $newvalue; + } + + public static function getDecryptedCookie($value){ + $first_key = base64_decode(FIRSTKEY); + $second_key = base64_decode(SECONDKEY); + + $c = base64_decode($value); + $method = "aes-256-cbc"; + $ivlen = openssl_cipher_iv_length($method); + $iv = substr($c, 0, $ivlen); + $hmac = substr($c, $ivlen, 32); + $newValue_raw = substr($c, $ivlen+32); + $newValue = openssl_decrypt($newValue_raw, $method, $first_key, OPENSSL_RAW_DATA, $iv); + $calcmac = hash_hmac('sha256', $newValue_raw, $second_key, TRUE); + if (hash_equals ($hmac, $calcmac)) { + return $newValue; + } + return false; + } + + public static function getUserData ($type, $userId = '') { + if ($userId == '') { + $userId = $_SESSION['user']['id']; + } + $user = Db::loadOne ('SELECT ' . $type . ' FROM users WHERE user_id=?', array ($userId)); + return $user[$type]; + } + + public static function setUserData ($type, $value) { + if (isset ($_SESSION['user']['id'])) { + Db::command ('UPDATE users SET ' . $type . '=? WHERE user_id=?', array ($value, $_SESSION['user']['id'])); + } + } + + public static function getHashPassword ($password) { + $salt = "s0mRIdlKvI"; + $hashPassword = hash('sha512', ($password . $salt)); + return $hashPassword; + } + + public static function atHome($userId, $atHome){ + try { + Db::edit ('users', ['at_home' => $atHome], 'WHERE user_id = ?', array($userId)); + } catch(PDOException $error) { + echo $error->getMessage(); + die(); + } + } + + public static function changePassword($oldPassword, $newPassword, $newPassword2){ + if ($newPassword == $newPassword2) { + //Password Criteria + $oldPasswordSaved = self::getUserData('password'); + if (self::getHashPassword($oldPassword) == $oldPasswordSaved) { + self::setUserData('password', self::getHashPassword($newPassword)); + } else { + throw new Exception ("old password did not match"); + } + } else { + throw new Exception ("new password arent same"); + } + } + + public static function createUser($userName, $password){ + $userId = Db::loadOne('SELECT * FROM users WHERE username = ?;', array($userName))['user_id']; + if ($userId != null) { + return false; + }; + try { + $user = [ + 'username' => $userName, + 'password' => self::getHashPassword($password), + ]; + return Db::add ('users', $user); + } catch(PDOException $error) { + echo $error->getMessage(); + die(); + } + } + + public static function haveOtaEnabled($userName){ + $ota = self::getUser($userName)['ota']; + + if ($ota != ''){ + return ($ota != '' ? $ota : false); + } else { + return false; + } + } +} +?> diff --git a/app/models/managers/Utilities.php b/app/models/managers/Utilities.php new file mode 100644 index 0000000..32b66af --- /dev/null +++ b/app/models/managers/Utilities.php @@ -0,0 +1,144 @@ + 'a', + '/[ÁÀÂÃÄ]/u' => 'A', + '/[ÍÌÎÏ]/u' => 'I', + '/[íìîï]/u' => 'i', + '/[ěéèêë]/u' => 'e', + '/[ĚÉÈÊË]/u' => 'E', + '/[óòôõºö]/u' => 'o', + '/[ÓÒÔÕÖ]/u' => 'O', + '/[úùûü]/u' => 'u', + '/[ÚÙÛÜ]/u' => 'U', + '/Š/' => 'S', + '/š/' => 's', + '/Č/' => 'C', + '/č/' => 'c', + '/ř/' => 'r', + '/Ř/' => 'R', + '/Ý/' => 'Y', + '/ý/' => 'y', + '/ç/' => 'c', + '/Ç/' => 'C', + '/ñ/' => 'n', + '/Ñ/' => 'N', + '/–/' => '-', // UTF-8 hyphen to "normal" hyphen + '/[’‘‹›‚]/u' => ' ', // Literally a single quote + '/[“”«»„]/u' => ' ', // Double quote + '/ /' => ' ', // nonbreaking space (equiv. to 0x160) + ); + return preg_replace(array_keys($utf8), array_values($utf8), $text); + } + + static function stringInsert($str,$insertstr,$pos) + { + $str = substr($str, 0, $pos) . $insertstr . substr($str, $pos); + return $str; + } + + /** + * [generateGraphJson description] + * @param string $type [line/bar] + * @param array $data [description] + * @param array $options [description] + * @return [type] [description] + */ + + static function generateGraphJson(string $type = 'line', array $data = [], array $options = []){ + $array = [ + 'type' => $type, + 'data' => [ + 'datasets' => [ + [ + 'data' => $data, + 'borderColor' => "#d4def7", + 'backgroundColor' => "#d4def7" + ] + ] + ], + 'options' => [ + 'scales' => [ + 'xAxes' => [ + [ + 'type' => 'time', + 'distribution' => 'linear', + ] + ], + 'yAxes' => [ + [ + 'ticks' => [ + 'min' => $options['min'], + 'max' => $options['max'], + 'steps' => $options['scale'] + ] + ] + ] + ], + 'legend' => [ + 'display' => false + ], + 'tooltips' => [ + 'enabled' => true + ], + 'hover' => [ + 'mode' => true + ] + ] + ]; + return json_encode($array, JSON_PRETTY_PRINT); + } + + static function ago( $datetime ) + { + $interval = date_create('now')->diff( $datetime ); + $suffix = ( $interval->invert ? ' ago' : '' ); + if ( $v = $interval->y >= 1 ) return self::pluralize( $interval->m, 'month' ) . $suffix; + if ( $v = $interval->d >= 1 ) return self::pluralize( $interval->d, 'day' ) . $suffix; + if ( $v = $interval->h >= 1 ) return self::pluralize( $interval->h, 'hour' ) . $suffix; + if ( $v = $interval->i >= 1 ) return self::pluralize( $interval->i, 'minute' ) . $suffix; + return self::pluralize( $interval->s, 'second' ) . $suffix; + } + + static function pluralize( $count, $text ) + { + return $count . ( ( $count == 1 ) ? ( " $text" ) : ( " ${text}s" ) ); + } + + static function checkOperator($value1, $operator, $value2) { + switch ($operator) { + case '<': // Less than + return $value1 < $value2; + case '<=': // Less than or equal to + return $value1 <= $value2; + case '>': // Greater than + return $value1 > $value2; + case '>=': // Greater than or equal to + return $value1 >= $value2; + case '==': // Equal + return ($value1 == $value2); + case '===': // Identical + return $value1 === $value2; + case '!==': // Not Identical + return $value1 !== $value2; + case '!=': // Not equal + case '<>': // Not equal + return $value1 != $value2; + case '||': // Or + case 'or': // Or + return $value1 || $value2; + case '&&': // And + case 'and': // And + return $value1 && $value2; + case 'xor': // Or + return $value1 xor $value2; + default: + return FALSE; + } // end switch + } +} diff --git a/app/models/types/GoogleHomeDeviceTypes.php b/app/models/types/GoogleHomeDeviceTypes.php new file mode 100644 index 0000000..6f142b7 --- /dev/null +++ b/app/models/types/GoogleHomeDeviceTypes.php @@ -0,0 +1,107 @@ + 'action.devices.types.OUTLET', + 'temp_cont' => 'action.devices.types.THERMOSTAT', + ]; + + static function getAction($deviceType){ + return self::$actionWordBook[$deviceType]; + } + + static function getSyncObj($deviceBaseObj, $deviceType){ + switch ($deviceType) { + case 'action.devices.types.LIGHT': + case 'action.devices.types.OUTLET': + $deviceBaseObj['traits'] = [ + 'action.devices.traits.OnOff' + ]; + break; + case 'action.devices.types.THERMOSTAT': + $deviceBaseObj['traits'] = [ + 'action.devices.traits.TemperatureSetting', + ]; + $deviceBaseObj['attributes'] = [ + "availableThermostatModes" => "off,heat", + "thermostatTemperatureUnit" => "C", + ]; + break; + } + return $deviceBaseObj; + } + + static function getQueryJson($deviceType, $type){ + return self::$wordBook[$type]; + } +} diff --git a/app/models/types/WidgetTypes.php b/app/models/types/WidgetTypes.php new file mode 100644 index 0000000..7e0dd7d --- /dev/null +++ b/app/models/types/WidgetTypes.php @@ -0,0 +1,45 @@ + [ + 'name' => 'value', + 'active' => false + ], + self::ICON => [ + 'name' => 'icon', + 'active' => false + ], + self::BUTTON => [ + 'name' => 'button', + 'active' => true + ], + self::SWITH => [ + 'name' => 'switch', + 'active' => true + ], + self::RANGE => [ + 'name' => 'range', + 'active' => true + ], + self::CUSTOM => [ + 'name' => 'custom', + 'active' => true + ], + ]; + + public static function getName($type){ + return self::$types[$type]; + } + + public static function isActive($type){ + return isset(self::$types[$type]) && self::$types[$type]['active']; + } +} diff --git a/app/views/Ajax.php b/app/views/Ajax.php new file mode 100644 index 0000000..96554a3 --- /dev/null +++ b/app/views/Ajax.php @@ -0,0 +1,223 @@ +isLogin()){ + header('Location: ' . BASEURL); + } + + $is_ajax = 'XMLHttpRequest' == ( $_SERVER['HTTP_X_REQUESTED_WITH'] ?? '' ); + if (!$is_ajax){ + header('Location: ' . BASEURL); + } + + if ( + isset($_POST['automation_id']) && + $_POST['automation_id'] != '' && + isset($_POST['action']) && + $_POST['action'] != '' + ) { + $automationId = $_POST['automation_id']; + //Automation Editation of Automations from Buttons/Details + switch ($_POST['action']) { + case 'delete': + AutomationManager::remove($automationId); + die(); + break; + + case 'deactive': + AutomationManager::deactive($automationId); + die(); + break; + + case 'restart': + AutomationManager::restart($automationId); + die(); + break; + + default: + echo 'no action detected'; + break; + } + } else if ( + isset($_POST['subDevice_id']) && + $_POST['subDevice_id'] != '' && + isset($_POST['action']) && + $_POST['action'] != '' + ) { + $subDeviceId = $_POST['subDevice_id']; + switch ($_POST['action']) { + case 'chart': + $period = $_POST['period']; + $groupBy = $_POST['group']; + header('Content-Type: application/json'); + $graphData = ChartManager::generateChartData($subDeviceId, $period, $groupBy); + echo Utilities::generateGraphJson($graphData['graphType'], $graphData['graphData'], $graphData['graphRange']); + die(); + break; + + //Change On/Off Device State of Device Button + case 'change': + $subDeviceData = SubDeviceManager::getSubDevice($subDeviceId); + $deviceId = SubDeviceManager::getSubDeviceMaster($subDeviceId)['device_id']; + if ($subDeviceData['type'] == 'on/off'){ + $lastValue = RecordManager::getLastRecord($subDeviceData['subdevice_id'])['value']; + RecordManager::create($deviceId, 'on/off', !$lastValue); + echo (!$lastValue ? 'ON' : 'OFF'); + } + die(); + break; + + //Waitin for execution of Changet walue for Device Button + case 'executed': + echo RecordManager::getLastRecord($subDeviceId)['execuded']; + die(); + break; + + case 'set': + $value = $_POST['value']; + $subDevice = SubDeviceManager::getSubDevice($subDeviceId); + RecordManager::create($subDevice['device_id'], $subDevice['type'], $value); + echo 'test id' . $subDevice['device_id'] .$subDevice['type'] . $value ; + die(); + break; + + default: + echo 'no action detected'; + break; + } + } else if ( + isset($_POST['scene_id']) && + $_POST['scene_id'] != '' && + isset($_POST['action']) && + $_POST['action'] != '' + ) { + $sceneId = $_POST['scene_id']; + switch ($_POST['action']) { + case 'delete': + SceneManager::delete($sceneId); + die(); + break; + + case 'execute': + echo SceneManager::execScene($sceneId); + die(); + break; + + default: + echo 'no action detected'; + break; + } + } else if ( + isset($_POST['notification']) && + $_POST['notification'] != '' && + isset($_POST['action']) && + $_POST['action'] != '' + ) { + switch ($_POST['action']) { + //add suscription to database + case 'subscribe': + $subscriptionToken = $_POST['token']; + NotificationManager::addSubscriber($_SESSION['user']['id'], $subscriptionToken); + die(); + break; + + case 'sendTest': + $notificationData = [ + 'title' => 'Alert', + 'body' => 'test notification', + 'icon' => BASEDIR . '/app/templates/images/icon-192x192.png', + ]; + $notificationMng = new NotificationManager; + $subscribers = $notificationMng::getSubscription(); + foreach ($subscribers as $key => $subscriber) { + echo $subscriber['user_id']; + if ($subscriber['user_id'] != $_SESSION['user']['id']) continue; + echo $notificationMng::sendSimpleNotification(SERVERKEY, $subscriber['token'], $notificationData); + } + die(); + break; + + default: + echo 'no action detected'; + break; + } + } else if ( + isset($_POST['action']) && + $_POST['action'] != '' + ) { + $updateData = []; + $allDevicesData = DeviceManager::getAllDevices(); + foreach ($allDevicesData as $deviceKey => $deviceValue) { + $allSubDevices = SubDeviceManager::getAllSubDevices($deviceValue['device_id']); + foreach ($allSubDevices as $key => $subDevicesData) { + + $lastRecord = RecordManager::getLastRecord($subDevicesData['subdevice_id']); + $parsedValue = $lastRecord['value'] . $subDevicesData['unit']; + + //TODO: udělat parser a ten použít jak v houmu tak zde + switch ($subDevicesData['type']) { + case 'on/off': + $replacementTrue = 'On'; + $replacementFalse = 'Off'; + $operator = '=='; + $breakValue = 1; + break; + + case 'door': + $replacementTrue = 'Closed'; + $replacementFalse = 'Open'; + $operator = '=='; + $breakValue = 1; + break; + + case 'light': + $replacementTrue = 'Light'; + $replacementFalse = 'Dark'; + $operator = '=='; + $breakValue = 1; + if ($lastRecord['value'] != 1 && $lastRecord['value'] != 0) { //Digital Light Senzor + $operator = '<'; + $breakValue = 810; + } + break; + + case 'water': + $replacementTrue = 'Wet'; + $replacementFalse = 'Dry'; + $operator = '=='; + $breakValue = 1; + break; + + default: + $replacementTrue = ''; + $replacementFalse = ''; + break; + } + + if ($replacementTrue != '' && $replacementFalse != '') { + //parsing last values + $parsedValue = $replacementFalse; + + if (Utilities::checkOperator($lastRecord['value'], $operator, $breakValue)) { + $parsedValue = $replacementTrue; + } + } + + $updateData[$subDevicesData['subdevice_id']] = [ + 'time' => $lastRecord['time'], + 'value' => $parsedValue, + ]; + } + } + + //TODO: PRO JS VRACET DATA + echo json_encode($updateData, JSON_PRETTY_PRINT); + } + } +} diff --git a/app/views/Automation.php b/app/views/Automation.php new file mode 100644 index 0000000..8bd7263 --- /dev/null +++ b/app/views/Automation.php @@ -0,0 +1,66 @@ +isLogin()){ + header('Location: ' . BASEURL . 'login'); + } + + $automations = []; + $automationsData = AutomationManager::getAll(); + foreach ($automationsData as $automationKey => $automationData) { + $doSomething = []; + foreach (json_decode($automationData['do_something']) as $deviceId => $subDeviceState) { + $subDeviceMasterDeviceData = DeviceManager::getDeviceById($deviceId); + $doSomething[$deviceId] = [ + 'name' => $subDeviceMasterDeviceData['name'], + 'state' => $subDeviceState, + ]; + } + //TODO: Transaltion add + $executionTime = 'never'; + if ($automationData['execution_time'] != '0000-00-00 00:00:00') { + $executionTime = date(DATEFORMAT,strtotime($automationData['execution_time'])); + } + $automations[$automationData['automation_id']] = [ + 'name' => $automationData['name'], + 'owner_name' => $userManager->getUserId($automationData['owner_id'])['username'], + 'onDays' => json_decode($automationData['on_days']), + 'ifSomething' => $automationData['if_something'], + 'doSomething' => $doSomething, + 'active' => $automationData['active'], + 'execution_time' => $executionTime, + ]; + } + + $approvedSubDevices = []; + $allDevicesData = DeviceManager::getAllDevices(); + foreach ($allDevicesData as $deviceKey => $deviceValue) { + if (!$deviceValue['approved']) continue; + $allSubDevicesData = SubDeviceManager::getAllSubDevices($deviceValue['device_id']); + foreach ($allSubDevicesData as $subDeviceKey => $subDeviceValue) { + $approvedSubDevices[$subDeviceValue['subdevice_id']] = [ + 'name' => $allDevicesData[$deviceKey]['name'], + 'type' => $subDeviceValue['type'], + 'masterDevice' => $subDeviceValue['device_id'], + ]; + } + } + + $template = new Template('automation'); + $template->prepare('baseDir', BASEDIR); + $template->prepare('debugMod', DEBUGMOD); + $template->prepare('title', 'Automation'); + $template->prepare('langMng', $langMng); + $template->prepare('userManager', $userManager); + + $template->prepare('automations', $automations); + $template->prepare('subDevices', $approvedSubDevices); + + $template->render(); + } +} diff --git a/app/views/Log.php b/app/views/Log.php new file mode 100644 index 0000000..81fedd6 --- /dev/null +++ b/app/views/Log.php @@ -0,0 +1,63 @@ +isLogin()){ + header('Location: ' . BASEURL . 'login'); + } + + $template = new Template('log'); + $template->prepare('title', 'Log'); + + $result = array(); + $cdir = scandir('../logs/'); + foreach ($cdir as $key => $value) + { + if (!in_array($value,array(".","..", ".gitkeep"))) + { + $result[$value] = $value; + } + } + + $template->prepare('baseDir', BASEDIR); + $template->prepare('debugMod', DEBUGMOD); + $template->prepare('logToLiveTime', LOGTIMOUT); + $template->prepare('title', 'Logy'); + $template->prepare('logsFiles', $result); + $template->prepare('langMng', $langMng); + $template->prepare('CPU', sys_getloadavg()[0]); + $template->prepare('UPTIME', shell_exec('uptime -p')); + $template->prepare('ramFree', $this->getSystemMemInfo()["MemFree"]); + $template->prepare('ramTotal', $this->getSystemMemInfo()["MemTotal"]); + $template->prepare('diskTotal', disk_total_space("/")); + $template->prepare('serverTime', date('m. d. Y H:i:s - e')); + + + + + + + + $template->render(); + + } +} diff --git a/app/views/Login.php b/app/views/Login.php new file mode 100644 index 0000000..d905d03 --- /dev/null +++ b/app/views/Login.php @@ -0,0 +1,22 @@ +isLogin()){ + header('Location: ' . BASEURL); + } + + $template = new Template('login'); + $template->prepare('baseDir', BASEDIR); + $template->prepare('title', 'Home'); + $template->prepare('lang', $lang); + + + + $template->render(); + } +} diff --git a/app/views/Logout.php b/app/views/Logout.php new file mode 100644 index 0000000..e0cf627 --- /dev/null +++ b/app/views/Logout.php @@ -0,0 +1,11 @@ +logout(); + header('Location: ' . BASEURL . 'login'); + die(); + } +} diff --git a/app/views/Setting.php b/app/views/Setting.php new file mode 100644 index 0000000..d89c28d --- /dev/null +++ b/app/views/Setting.php @@ -0,0 +1,62 @@ +isLogin()){ + header('Location: ' . BASEURL . 'login'); + } + + $automations = []; + $automationsData = AutomationManager::getAll(); + foreach ($automationsData as $automationKey => $automationData) { + $automations[$automationData['automation_id']] = [ + 'name' => '', + 'onDays' => $automationData['on_days'], + 'ifSomething' => $automationData['if_something'], + 'doSomething' => $automationData['do_something'], + ]; + } + + $template = new Template('setting'); + $template->prepare('baseDir', BASEDIR); + $template->prepare('debugMod', DEBUGMOD); + $template->prepare('title', 'Automation'); + $template->prepare('langMng', $langMng); + $template->prepare('automations', $automations); + + $users = $userManager->getUsers(); + foreach ($users as $key => $value) { + $users[$key]['gavatar_url'] = $userManager->getAvatarUrl($value['user_id']); + } + $template->prepare('users', $users); + + $template->prepare('userName', $userManager->getUserData('username')); + $template->prepare('userEmail', $userManager->getUserData('email')); + $template->prepare('userAvatarUrl', $userManager->getAvatarUrl()); + + if ($userManager->getUserData('ota') == ''){ + $ga = new PHPGangsta_GoogleAuthenticator(); + $otaSecret = $ga->createSecret(); + $qrCodeUrl = $ga->getQRCodeGoogleUrl('Smart Home', $otaSecret); + $oneCode = $ga->getCode($otaSecret); + $template->prepare('qrUrl', $qrCodeUrl); + $template->prepare('otaSecret', $otaSecret); + $template->prepare('otaCode', $oneCode); + + // echo "Secret is: ".$secret."\n\n"; + // echo "Google Charts URL for the QR-Code: ".$qrCodeUrl."\n\n"; + // echo "Checking Code '$oneCode' and Secret '$otaSecret':\n"; + } + + $rooms = RoomManager::getAllRooms(); + $template->prepare('rooms', $rooms); + + + $template->render(); + } +} diff --git a/app/views/layouts/default.phtml b/app/views/layouts/default.phtml new file mode 100644 index 0000000..6479b79 --- /dev/null +++ b/app/views/layouts/default.phtml @@ -0,0 +1,20 @@ + + + + + + <?php echo $this->title ?> + + + +
+ {HEADER} +
+ + content(); ?> + + + + diff --git a/app/views/templates/automation.phtml b/app/views/templates/automation.phtml new file mode 100644 index 0000000..84cd043 --- /dev/null +++ b/app/views/templates/automation.phtml @@ -0,0 +1,66 @@ + + + + prepare('baseDir', $BASEDIR); + $partial->render(); + ?> + <?php echo $TITLE ?> + + +
+
+ +
+ echo('t_createAutomation'); ?> +
+ $automationData) { + //BUTTON + $partial = new Partial('automationButton'); + $partial->prepare('langMng',$LANGMNG); + $partial->prepare('automationId',$automationId); + $partial->prepare('automationData',$automationData); + $partial->render(); + + //EDIT + $partial = new Partial('automationEdit'); + $partial->prepare('langMng',$LANGMNG); + $partial->prepare('userManager',$USERMANAGER); + $partial->prepare('automationId',$automationId); + $partial->prepare('automation',$automationData); + $partial->prepare('subDevices',$SUBDEVICES); + $partial->render(); + } ?> +
+
+
+ prepare('langMng',$LANGMNG); + $partial->prepare('userManager',$USERMANAGER); + $partial->prepare('subDevices',$SUBDEVICES); + $partial->render(); + } else { + $partial = new Partial('automationCreate'); + $partial->prepare('langMng',$LANGMNG); + + $partial->prepare('subDevices',$SUBDEVICES); + $partial->render(); + }?> + + render(); + ?> + + diff --git a/app/views/templates/example.phtml b/app/views/templates/example.phtml new file mode 100644 index 0000000..b5d2471 --- /dev/null +++ b/app/views/templates/example.phtml @@ -0,0 +1 @@ +Example template diff --git a/www/public/css/loading.css b/app/views/templates/loading.css similarity index 100% rename from www/public/css/loading.css rename to app/views/templates/loading.css diff --git a/app/views/templates/log.phtml b/app/views/templates/log.phtml new file mode 100644 index 0000000..08bb04f --- /dev/null +++ b/app/views/templates/log.phtml @@ -0,0 +1,70 @@ + + + + prepare('baseDir', $BASEDIR); + $partial->render(); + ?> + <?php echo $TITLE ?> + + +
+
+ +
+
+
+ +
+
+
+
+
+ " max="">
+ +
+
+ + + +
+
+ +
+
+ +
+
+ '; + foreach ($file_lines as $line) { + echo $line; + } + echo ''; + } + ?> +
+
+ + render(); + //TODO js do main.js + ?> + + diff --git a/app/views/templates/login.phtml b/app/views/templates/login.phtml new file mode 100644 index 0000000..ae0636b --- /dev/null +++ b/app/views/templates/login.phtml @@ -0,0 +1,27 @@ + + + + render(); + ?> + <?php echo $TITLE ?> + + + prepare('ota',$ota); + $partial->render(); + } else { + $partial = new Partial('loginForm'); + $partial->render(); + } + ?> + + render(); + ?> + + diff --git a/app/views/templates/part/automationButton.phtml b/app/views/templates/part/automationButton.phtml new file mode 100644 index 0000000..002aaab --- /dev/null +++ b/app/views/templates/part/automationButton.phtml @@ -0,0 +1,70 @@ +
+
+
+
+
+
+ type) { + case 'sunSet': + echo''; + break; + + case 'sunRise': + echo' '; + break; + + case 'inHome': + echo''; + break; + + case 'outHome': + echo''; + break; + + case 'outDevice': + echo''; + break; + + default: + echo''; + break; + } + ?> +
+
+
+
+ +
+
+
+
+
+ +
+
+ +
+
+ +
+
+ +
+
+
diff --git a/app/views/templates/part/automationCreate.phtml b/app/views/templates/part/automationCreate.phtml new file mode 100644 index 0000000..44a731a --- /dev/null +++ b/app/views/templates/part/automationCreate.phtml @@ -0,0 +1,69 @@ + diff --git a/app/views/templates/part/automationCreateFinal.phtml b/app/views/templates/part/automationCreateFinal.phtml new file mode 100644 index 0000000..0eb48c3 --- /dev/null +++ b/app/views/templates/part/automationCreateFinal.phtml @@ -0,0 +1,44 @@ + diff --git a/app/views/templates/part/automationEdit.phtml b/app/views/templates/part/automationEdit.phtml new file mode 100644 index 0000000..6411388 --- /dev/null +++ b/app/views/templates/part/automationEdit.phtml @@ -0,0 +1,85 @@ + diff --git a/app/views/templates/part/footer.phtml b/app/views/templates/part/footer.phtml new file mode 100644 index 0000000..0fcb4bf --- /dev/null +++ b/app/views/templates/part/footer.phtml @@ -0,0 +1,5 @@ + + + + + diff --git a/app/views/templates/part/head.phtml b/app/views/templates/part/head.phtml new file mode 100644 index 0000000..1555607 --- /dev/null +++ b/app/views/templates/part/head.phtml @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/views/templates/part/loginForm.phtml b/app/views/templates/part/loginForm.phtml new file mode 100644 index 0000000..c06b535 --- /dev/null +++ b/app/views/templates/part/loginForm.phtml @@ -0,0 +1,20 @@ + diff --git a/app/views/templates/part/loginOta.phtml b/app/views/templates/part/loginOta.phtml new file mode 100644 index 0000000..3e8d294 --- /dev/null +++ b/app/views/templates/part/loginOta.phtml @@ -0,0 +1,13 @@ + diff --git a/app/views/templates/part/menu.phtml b/app/views/templates/part/menu.phtml new file mode 100644 index 0000000..79c3fa4 --- /dev/null +++ b/app/views/templates/part/menu.phtml @@ -0,0 +1,35 @@ + diff --git a/app/views/templates/part/test.phtml b/app/views/templates/part/test.phtml new file mode 100644 index 0000000..002c703 --- /dev/null +++ b/app/views/templates/part/test.phtml @@ -0,0 +1,3 @@ +

+ TEST - TEST +

\ No newline at end of file diff --git a/app/views/templates/setting.phtml b/app/views/templates/setting.phtml new file mode 100644 index 0000000..18ac4f2 --- /dev/null +++ b/app/views/templates/setting.phtml @@ -0,0 +1,203 @@ + + + + prepare('baseDir', $BASEDIR); + $partial->render(); + ?> + <?php echo $TITLE ?> + + +
+
+ +
+
+

+ + echo('t_pageAfterLogIn') ?> +

+
+
+
+ +
+ +
+
+ +
+

echo('t_profile') ?>

+
+
echo('l_userAvatar') ?>:
+ +
* providet by Gavatar
+
+
+
echo('l_userName') ?>:
+ +
+
+
echo('l_userEmail') ?>:
+ +
+ +
+
+

echo('t_notification') ?>

+ +
echo('l_notificationStatus') ?>
+ +
+
+

echo('t_experimental') ?>

+ +
+
+

echo('t_changePassword') ?>

+
+
+
echo('l_oldPassword') ?>:
+ +
+
+
echo('l_newPassword') ?>:
+ +
+
+
echo('l_newPassword') ?>:
+ +
+
+ +
+
+
+
+

echo('t_ota') ?>

+ + + +
+
+
echo('l_gooleAutenticatorOtaCode') ?>:
+ + +
+
+ +
+
+ + + +
+
+

echo('t_listUsers') ?>

+ + + + + + + + + + + $user) { ?> + + + + + + + + +
echo('t_avatar');?>echo('t_userName');?>echo('t_ota');?>echo('t_action');?>
' : ''); ?>
+
+
+

echo('t_createuser') ?>

+
+
+
echo('l_userName') ?>:
+ +
+
+
echo('l_password') ?>:
+ +
+
+ +
+
+
+ + +
+

echo('t_listRooms') ?>

+ + + + + + + + + $room) { ?> + + + + + + +
echo('t_roomName');?>echo('t_action');?>
+ + +
+
+ + +
+

echo('t_createRoom') ?>

+
+
+
echo('l_roomName') ?>:
+ +
+
+ +
+
+
+ + +
+ + +
+ render(); + ?> + + + + diff --git a/app/views/templates/template.phtml b/app/views/templates/template.phtml new file mode 100644 index 0000000..090cd1b --- /dev/null +++ b/app/views/templates/template.phtml @@ -0,0 +1,11 @@ + + + + + + <?php echo $this->title ?> + + + content(); ?> + + diff --git a/www/config/config_sample.php b/config/config_sample.php similarity index 100% rename from www/config/config_sample.php rename to config/config_sample.php diff --git a/www/docker-compose.yml b/docker-compose.yml similarity index 100% rename from www/docker-compose.yml rename to docker-compose.yml diff --git a/www/lang/cs.php b/lang/cs.php similarity index 100% rename from www/lang/cs.php rename to lang/cs.php diff --git a/www/lang/en.php b/lang/en.php similarity index 100% rename from www/lang/en.php rename to lang/en.php diff --git a/www/lang/nl.php b/lang/nl.php similarity index 100% rename from www/lang/nl.php rename to lang/nl.php diff --git a/www/lang/pl.php b/lang/pl.php similarity index 100% rename from www/lang/pl.php rename to lang/pl.php diff --git a/www/library/ApiController.php b/library/ApiController.php similarity index 100% rename from www/library/ApiController.php rename to library/ApiController.php diff --git a/www/library/Controller.php b/library/Controller.php similarity index 100% rename from www/library/Controller.php rename to library/Controller.php diff --git a/www/library/DB.php b/library/DB.php similarity index 100% rename from www/library/DB.php rename to library/DB.php diff --git a/library/Partial.php b/library/Partial.php new file mode 100644 index 0000000..5609556 --- /dev/null +++ b/library/Partial.php @@ -0,0 +1,34 @@ +debug = $debug; + if (!empty('../app/views/templates/part/' . $path . '.phtml') && file_exists('../app/views/templates/part/' . $path . '.phtml')) { + $this->path = $path; + } else { + echo '
';
+			echo 'PHTML: Parial File ' . $path . ' not found';
+			echo '
'; + die(); + } + } + + function prepare($searchS, $repleaceS) { + if (!empty($searchS)) { + $this->assignedValues[strtoupper($searchS)] = $repleaceS; + } + echo ($this->debug == true ? var_dump($this->assignedValues) : ''); + } + + function render() { + if (!empty($this->assignedValues)){ + extract($this->assignedValues); + } + + require('../app/views/templates/part/' . $this->path . '.phtml'); + } +} diff --git a/www/library/Router.php b/library/Router.php similarity index 100% rename from www/library/Router.php rename to library/Router.php diff --git a/www/library/Template.php b/library/Template.php similarity index 100% rename from www/library/Template.php rename to library/Template.php diff --git a/www/library/View.php b/library/View.php similarity index 100% rename from www/library/View.php rename to library/View.php diff --git a/www/library/vendor/PHPGangsta_GoogleAuthenticator.php b/library/vendor/GoogleAuthenticator.php similarity index 100% rename from www/library/vendor/PHPGangsta_GoogleAuthenticator.php rename to library/vendor/GoogleAuthenticator.php diff --git a/library/vendor/PHPGangsta_GoogleAuthenticator.php b/library/vendor/PHPGangsta_GoogleAuthenticator.php new file mode 100644 index 0000000..bf7d116 --- /dev/null +++ b/library/vendor/PHPGangsta_GoogleAuthenticator.php @@ -0,0 +1,252 @@ +_getBase32LookupTable(); + + // Valid secret lengths are 80 to 640 bits + if ($secretLength < 16 || $secretLength > 128) { + throw new Exception('Bad secret length'); + } + $secret = ''; + $rnd = false; + if (function_exists('random_bytes')) { + $rnd = random_bytes($secretLength); + } elseif (function_exists('mcrypt_create_iv')) { + $rnd = mcrypt_create_iv($secretLength, MCRYPT_DEV_URANDOM); + } elseif (function_exists('openssl_random_pseudo_bytes')) { + $rnd = openssl_random_pseudo_bytes($secretLength, $cryptoStrong); + if (!$cryptoStrong) { + $rnd = false; + } + } + if ($rnd !== false) { + for ($i = 0; $i < $secretLength; ++$i) { + $secret .= $validChars[ord($rnd[$i]) & 31]; + } + } else { + throw new Exception('No source of secure random'); + } + + return $secret; + } + + /** + * Calculate the code, with given secret and point in time. + * + * @param string $secret + * @param int|null $timeSlice + * + * @return string + */ + public function getCode($secret, $timeSlice = null) + { + if ($timeSlice === null) { + $timeSlice = floor(time() / 30); + } + + $secretkey = $this->_base32Decode($secret); + + // Pack time into binary string + $time = chr(0).chr(0).chr(0).chr(0).pack('N*', $timeSlice); + // Hash it with users secret key + $hm = hash_hmac('SHA1', $time, $secretkey, true); + // Use last nipple of result as index/offset + $offset = ord(substr($hm, -1)) & 0x0F; + // grab 4 bytes of the result + $hashpart = substr($hm, $offset, 4); + + // Unpak binary value + $value = unpack('N', $hashpart); + $value = $value[1]; + // Only 32 bits + $value = $value & 0x7FFFFFFF; + + $modulo = pow(10, $this->_codeLength); + + return str_pad($value % $modulo, $this->_codeLength, '0', STR_PAD_LEFT); + } + + /** + * Get QR-Code URL for image, from google charts. + * + * @param string $name + * @param string $secret + * @param string $title + * @param array $params + * + * @return string + */ + public function getQRCodeGoogleUrl($name, $secret, $title = null, $params = array()) + { + $width = !empty($params['width']) && (int) $params['width'] > 0 ? (int) $params['width'] : 200; + $height = !empty($params['height']) && (int) $params['height'] > 0 ? (int) $params['height'] : 200; + $level = !empty($params['level']) && array_search($params['level'], array('L', 'M', 'Q', 'H')) !== false ? $params['level'] : 'M'; + + $urlencoded = urlencode('otpauth://totp/'.$name.'?secret='.$secret.''); + if (isset($title)) { + $urlencoded .= urlencode('&issuer='.urlencode($title)); + } + + return "https://api.qrserver.com/v1/create-qr-code/?data=$urlencoded&size=${width}x${height}&ecc=$level"; + } + + /** + * Check if the code is correct. This will accept codes starting from $discrepancy*30sec ago to $discrepancy*30sec from now. + * + * @param string $secret + * @param string $code + * @param int $discrepancy This is the allowed time drift in 30 second units (8 means 4 minutes before or after) + * @param int|null $currentTimeSlice time slice if we want use other that time() + * + * @return bool + */ + public function verifyCode($secret, $code, $discrepancy = 1, $currentTimeSlice = null) + { + if ($currentTimeSlice === null) { + $currentTimeSlice = floor(time() / 30); + } + + if (strlen($code) != 6) { + return false; + } + + for ($i = -$discrepancy; $i <= $discrepancy; ++$i) { + $calculatedCode = $this->getCode($secret, $currentTimeSlice + $i); + if ($this->timingSafeEquals($calculatedCode, $code)) { + return true; + } + } + + return false; + } + + /** + * Set the code length, should be >=6. + * + * @param int $length + * + * @return PHPGangsta_GoogleAuthenticator + */ + public function setCodeLength($length) + { + $this->_codeLength = $length; + + return $this; + } + + /** + * Helper class to decode base32. + * + * @param $secret + * + * @return bool|string + */ + protected function _base32Decode($secret) + { + if (empty($secret)) { + return ''; + } + + $base32chars = $this->_getBase32LookupTable(); + $base32charsFlipped = array_flip($base32chars); + + $paddingCharCount = substr_count($secret, $base32chars[32]); + $allowedValues = array(6, 4, 3, 1, 0); + if (!in_array($paddingCharCount, $allowedValues)) { + return false; + } + for ($i = 0; $i < 4; ++$i) { + if ($paddingCharCount == $allowedValues[$i] && + substr($secret, -($allowedValues[$i])) != str_repeat($base32chars[32], $allowedValues[$i])) { + return false; + } + } + $secret = str_replace('=', '', $secret); + $secret = str_split($secret); + $binaryString = ''; + for ($i = 0; $i < count($secret); $i = $i + 8) { + $x = ''; + if (!in_array($secret[$i], $base32chars)) { + return false; + } + for ($j = 0; $j < 8; ++$j) { + $x .= str_pad(base_convert(@$base32charsFlipped[@$secret[$i + $j]], 10, 2), 5, '0', STR_PAD_LEFT); + } + $eightBits = str_split($x, 8); + for ($z = 0; $z < count($eightBits); ++$z) { + $binaryString .= (($y = chr(base_convert($eightBits[$z], 2, 10))) || ord($y) == 48) ? $y : ''; + } + } + + return $binaryString; + } + + /** + * Get array with all 32 characters for decoding from/encoding to base32. + * + * @return array + */ + protected function _getBase32LookupTable() + { + return array( + 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', // 7 + 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', // 15 + 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', // 23 + 'Y', 'Z', '2', '3', '4', '5', '6', '7', // 31 + '=', // padding char + ); + } + + /** + * A timing safe equals comparison + * more info here: http://blog.ircmaxell.com/2014/11/its-all-about-time.html. + * + * @param string $safeString The internal (safe) value to be checked + * @param string $userString The user submitted (unsafe) value + * + * @return bool True if the two strings are identical + */ + private function timingSafeEquals($safeString, $userString) + { + if (function_exists('hash_equals')) { + return hash_equals($safeString, $userString); + } + $safeLen = strlen($safeString); + $userLen = strlen($userString); + + if ($userLen != $safeLen) { + return false; + } + + $result = 0; + + for ($i = 0; $i < $userLen; ++$i) { + $result |= (ord($safeString[$i]) ^ ord($userString[$i])); + } + + // They are only identical strings if $result is exactly 0... + return $result === 0; + } +} diff --git a/www/logs/.gitkeep b/logs/.gitkeep similarity index 100% rename from www/logs/.gitkeep rename to logs/.gitkeep diff --git a/www/manifest.json b/manifest.json similarity index 100% rename from www/manifest.json rename to manifest.json diff --git a/www/public/.htaccess b/public/.htaccess similarity index 100% rename from www/public/.htaccess rename to public/.htaccess diff --git a/www/public/Elementum/scss/elements/_buttons.scss b/public/Elementum/scss/elements/_buttons.scss similarity index 100% rename from www/public/Elementum/scss/elements/_buttons.scss rename to public/Elementum/scss/elements/_buttons.scss diff --git a/www/public/css/font-awesome.min.css b/public/css/font-awesome.min.css similarity index 100% rename from www/public/css/font-awesome.min.css rename to public/css/font-awesome.min.css diff --git a/public/css/loading.css b/public/css/loading.css new file mode 100644 index 0000000..6c58598 --- /dev/null +++ b/public/css/loading.css @@ -0,0 +1,19 @@ +.loader { + border: 16px solid #f3f3f3; + border-radius: 50%; + border-top: 16px solid rgb(101, 30, 122);; + width: 100%; + height: 100%; + -webkit-animation: spin 2s linear infinite; /* Safari */ + animation: spin 2s linear infinite; +} + +@-webkit-keyframes spin { + 0% { -webkit-transform: rotate(0deg); } + 100% { -webkit-transform: rotate(360deg); } +} + +@keyframes spin { + 0% { transform: rotate(0deg); } + 100% { transform: rotate(360deg); } +} \ No newline at end of file diff --git a/www/public/css/main.css b/public/css/main.css similarity index 100% rename from www/public/css/main.css rename to public/css/main.css diff --git a/www/public/css/main.css.map b/public/css/main.css.map similarity index 100% rename from www/public/css/main.css.map rename to public/css/main.css.map diff --git a/www/public/css/modal.css b/public/css/modal.css similarity index 100% rename from www/public/css/modal.css rename to public/css/modal.css diff --git a/www/public/css/override.css b/public/css/override.css similarity index 100% rename from www/public/css/override.css rename to public/css/override.css diff --git a/www/public/css/pre.css b/public/css/pre.css similarity index 100% rename from www/public/css/pre.css rename to public/css/pre.css diff --git a/www/public/fonts/FontAwesome.otf b/public/fonts/FontAwesome.otf similarity index 100% rename from www/public/fonts/FontAwesome.otf rename to public/fonts/FontAwesome.otf diff --git a/www/public/fonts/Metropolis-Medium.otf b/public/fonts/Metropolis-Medium.otf similarity index 100% rename from www/public/fonts/Metropolis-Medium.otf rename to public/fonts/Metropolis-Medium.otf diff --git a/www/public/fonts/Metropolis-Regular.otf b/public/fonts/Metropolis-Regular.otf similarity index 100% rename from www/public/fonts/Metropolis-Regular.otf rename to public/fonts/Metropolis-Regular.otf diff --git a/www/public/fonts/Metropolis-SemiBold.otf b/public/fonts/Metropolis-SemiBold.otf similarity index 100% rename from www/public/fonts/Metropolis-SemiBold.otf rename to public/fonts/Metropolis-SemiBold.otf diff --git a/www/public/fonts/fontawesome-webfont.eot b/public/fonts/fontawesome-webfont.eot similarity index 100% rename from www/public/fonts/fontawesome-webfont.eot rename to public/fonts/fontawesome-webfont.eot diff --git a/www/public/fonts/fontawesome-webfont.svg b/public/fonts/fontawesome-webfont.svg similarity index 100% rename from www/public/fonts/fontawesome-webfont.svg rename to public/fonts/fontawesome-webfont.svg diff --git a/www/public/fonts/fontawesome-webfont.ttf b/public/fonts/fontawesome-webfont.ttf similarity index 100% rename from www/public/fonts/fontawesome-webfont.ttf rename to public/fonts/fontawesome-webfont.ttf diff --git a/www/public/fonts/fontawesome-webfont.woff b/public/fonts/fontawesome-webfont.woff similarity index 100% rename from www/public/fonts/fontawesome-webfont.woff rename to public/fonts/fontawesome-webfont.woff diff --git a/www/public/fonts/fontawesome-webfont.woff2 b/public/fonts/fontawesome-webfont.woff2 similarity index 100% rename from www/public/fonts/fontawesome-webfont.woff2 rename to public/fonts/fontawesome-webfont.woff2 diff --git a/www/public/images/icon-192x192.png b/public/images/icon-192x192.png similarity index 100% rename from www/public/images/icon-192x192.png rename to public/images/icon-192x192.png diff --git a/www/public/images/icon-512x512.png b/public/images/icon-512x512.png similarity index 100% rename from www/public/images/icon-512x512.png rename to public/images/icon-512x512.png diff --git a/www/public/index.php b/public/index.php similarity index 100% rename from www/public/index.php rename to public/index.php diff --git a/www/public/js/automation.js b/public/js/automation.js similarity index 100% rename from www/public/js/automation.js rename to public/js/automation.js diff --git a/www/public/js/jquery.js b/public/js/jquery.js similarity index 100% rename from www/public/js/jquery.js rename to public/js/jquery.js diff --git a/www/public/js/jquery.redirect.js b/public/js/jquery.redirect.js similarity index 100% rename from www/public/js/jquery.redirect.js rename to public/js/jquery.redirect.js diff --git a/www/public/js/post.js b/public/js/post.js similarity index 100% rename from www/public/js/post.js rename to public/js/post.js diff --git a/www/public/js/script.js b/public/js/script.js similarity index 100% rename from www/public/js/script.js rename to public/js/script.js diff --git a/www/public/js/setting.js b/public/js/setting.js similarity index 100% rename from www/public/js/setting.js rename to public/js/setting.js diff --git a/www/serviceWorker.js b/serviceWorker.js similarity index 100% rename from www/serviceWorker.js rename to serviceWorker.js diff --git a/www/update.php b/update.php similarity index 100% rename from www/update.php rename to update.php diff --git a/www/updater/.gitkeep b/updater/.gitkeep similarity index 100% rename from www/updater/.gitkeep rename to updater/.gitkeep