Browse Source

+ remind system; + test home page

Piotr Labudda 4 years ago
parent
commit
9467b80046

+ 157 - 23
auth.php

@@ -24,35 +24,28 @@ class Theme_Auth_panel_biall_net { // TODO: implements AuthBaseInterface {
 
 	static function login($login, $pass) { // @return User object or null
 
-		if (empty($login) || empty($pass)) throw new Exception("Proszę podać poprawny login i hasło!");
+		if (empty($login) || empty($pass)) throw new Exception("Proszę podać login i hasło!");
 
-		{ // TODO: TEST
-			$login = "krzys.dworski@gmail.com"; // COMPANIES.user_mail_contact
-			$pass = "76022801989"; // TODO: COMPANIES.P_PESEL or COMPANIES.PASSWD varchar(100) ?
-		}
-
-		$item = DB::getPDO()->fetchFirst("
-			select c.ID, c.user_mail_contact, c.P_PESEL, c.PASSWD
-			from COMPANIES c
-			where c.user_mail_contact like :email
-		", [
-			':email' => $login,
-		]);
-		// [ID] => 12807
-		// [user_mail_contact] => krzys.dworski@gmail.com
-		// [P_PESEL] => 76022801989
-		// [PASSWD] => 76022801989
+		// { // TODO: TEST
+		// 	$login = "krzys.dworski@gmail.com"; // COMPANIES.user_mail_contact
+		// 	$pass = "76022801989"; // COMPANIES.P_PESEL or COMPANIES.PASSWD varchar(100) --- table PANEL_KLIENTA_BN_AUTH
+		// }
 
-		throw new Exception("TODO: Proszę podać poprawny login i hasło!");
+		$item = self::fetchUser($login);
+		if (empty($item['PASSWD']) || 32 != strlen($item['PASSWD'])) {
+			throw new Exception("Proszę użyć funkcji przypomnienia hasła");
+		}
 
-		return null;
+		if (md5($pass) !== $item['PASSWD']) {
+			throw new Exception("Proszę podać poprawny login i hasło!");
+		}
 
 		return (object)[
-			'ID' => "", // ADM_ID
-			'ADM_ACCOUNT' => "", // AUTHORIZE_USER, ADM_ACCOUNT
-			'ADM_NAME' => "", // ADM_NAME
+			'ID' => $item['ID'],
+			'ADM_ACCOUNT' => $item['LOGIN'], // AUTHORIZE_USER, ADM_ACCOUNT
+			'ADM_NAME' => implode(" ", [ $item['P_NAME'], $item['P_NAME_SECOND'] ]), // ADM_NAME
 			'ADM_TECH_WORKER' => "", // ADM_TECH_WORKER
-			'ADM_COMPANY' => "", // ADM_COMPANY
+			'ADM_COMPANY' => $item['BILLING_OWNER'], // ADM_COMPANY
 			'ADM_ADMIN_LEVEL' => "", // ADM_ADMIN_LEVEL
 			'ADM_PHONE' => "", // ADM_PHONE
 			'ADM_ADMIN_EXPIRE' => "", // ADM_ADMIN_EXPIRE
@@ -61,4 +54,145 @@ class Theme_Auth_panel_biall_net { // TODO: implements AuthBaseInterface {
 		];
 	}
 
+	static function fetchUser($login) {
+		$item = DB::getPDO()->tryHandleException([ __CLASS__, 'preparePanelBNAuthTables' ], 'fetchFirst', [
+			"
+				select c.ID, c.user_mail_contact, c.P_PESEL
+			--		, c.PASSWD
+					, c.P_NAME, c.P_NAME_SECOND
+					, c.BILLING_OWNER -- 1 BN, 3 NETDAY
+					, c.is_firma
+					, c.P_NIP
+					, p.ID as ID_AUTH
+					, p.LOGIN
+					, p.PASSWD
+					, p.REMIND_PASS_KEY
+					, p.REMIND_PASS_VALID_TILL
+				from COMPANIES c
+					left join PANEL_KLIENTA_BN_AUTH p on ( p.ID_BILLING_USERS = c.ID and p.LOGIN = c.user_mail_contact )
+				where c.user_mail_contact like :email
+			",
+			[
+				':email' => $login,
+			]
+		]);
+		if (!$item) throw new Exception("BŁĄD: Brak zarejestrowanego użytkownika o wprowadzonym adresie email.");
+
+		if (!$item['ID_AUTH']) {
+			$passwd = (!empty($item['P_PESEL'])) ? $item['P_PESEL'] : $item['P_NIP'];
+			$hashPass = ($passwd) ? md5($passwd) : null;
+			DB::getPDO()->insert('PANEL_KLIENTA_BN_AUTH', [
+				'ID_BILLING_USERS' => $item['ID'],
+				'LOGIN' => $item['user_mail_contact'],
+				'PASSWD' => $hashPass,
+				'A_RECORD_CREATE_DATE' => "NOW()",
+			]);
+			$item['ID_BILLING_USERS'] = $item['ID'];
+			$item['LOGIN'] = $item['user_mail_contact'];
+			$item['PASSWD'] = $hashPass;
+		}
+
+		return $item;
+	}
+
+	static function generateRemindKey($email) {
+		$remindKey = substr(md5($email . "" . date("Y-m-d H:i:s")), 0, 16);
+		$remindTill = date("Y-m-d", mktime(0,0,0, date("m"), date("d") + 2, date("Y")));
+		$userInfo = self::fetchUser($email);
+		DB::getPDO()->execSql("
+			update PANEL_KLIENTA_BN_AUTH
+			set REMIND_PASS_KEY = :remind_key
+				, REMIND_PASS_VALID_TILL = :remind_till
+				, A_RECORD_UPDATE_DATE = NOW()
+			where ID_BILLING_USERS = :id_user
+				and LOGIN = :login
+		", [
+			':id_user' => $userInfo['ID'],
+			':login' => $userInfo['LOGIN'],
+			':remind_key' => $remindKey,
+			':remind_till' => $remindTill,
+		]);
+		return $remindKey;
+	}
+
+	static function setPasswd($email, $newPasswd, $remindKey) {
+		if (empty($email)) throw new Exception("Missing login!");
+		if (empty($newPasswd)) throw new Exception("Missing password!");
+		if (empty($remindKey)) throw new Exception("Missing remindKey!");
+
+		// TODO: validate password!
+		if (strlen($newPasswd) < 8) throw new Exception("Hasło musi się składać z co najmniej 8 znaków");
+
+		$userInfo = self::fetchUser($email);
+
+		// DBG::nicePrint([
+		// 	'c1' => empty($userInfo['REMIND_PASS_KEY']),
+		// 	'c2' => $userInfo['REMIND_PASS_KEY'] !== $remindKey,
+		// 	'c2.L' => $userInfo['REMIND_PASS_KEY'],
+		// 	'c2.R' => $remindKey,
+		// 	'c3' =>  date("Y-m-d") > $userInfo['REMIND_PASS_VALID_TILL'],
+		// 	'c3.L' => date("Y-m-d"),
+		// 	'c3.R' => $userInfo['REMIND_PASS_VALID_TILL'],
+		// 	'user' => $userInfo,
+		// ], 'DBG');
+		if (empty($userInfo['REMIND_PASS_KEY'])
+			|| $userInfo['REMIND_PASS_KEY'] !== $remindKey
+			|| date("Y-m-d") > $userInfo['REMIND_PASS_VALID_TILL']
+		) throw new Exception("Odnośnik do resetowania hasła wydaje się być niesprawny. Proszę użyć funkcji przypomnienia hasła.");
+
+		DB::getPDO()->execSql("
+			update PANEL_KLIENTA_BN_AUTH
+			set REMIND_PASS_KEY = ''
+				, REMIND_PASS_VALID_TILL = '0000-00-00'
+				, PASSWD = :hash_passwd
+				, A_RECORD_UPDATE_DATE = NOW()
+			where ID_BILLING_USERS = :id_user
+				and LOGIN = :login
+		", [
+			':id_user' => $userInfo['ID'],
+			':login' => $userInfo['LOGIN'],
+			':hash_passwd' => md5($newPasswd),
+		]);
+	}
+
+	static function preparePanelBNAuthTables() {
+		DB::getPDO()->execSql("
+			CREATE TABLE IF NOT EXISTS `PANEL_KLIENTA_BN_AUTH` (
+				`ID` int(11) NOT NULL AUTO_INCREMENT,
+				`ID_BILLING_USERS` int(11) NOT NULL,
+				`LOGIN` varchar(255) NOT NULL DEFAULT '',
+				`PASSWD` varchar(32) NOT NULL DEFAULT '',
+				`REMIND_PASS_KEY` varchar(16) NOT NULL DEFAULT '',
+				`REMIND_PASS_VALID_TILL` date NOT NULL DEFAULT '0000-00-00',
+				`A_ADM_COMPANY` varchar(64) NOT NULL DEFAULT '',
+				`A_CLASSIFIED` varchar(64) NOT NULL DEFAULT '',
+				`A_RECORD_CREATE_DATE` datetime NOT NULL,
+				`A_RECORD_CREATE_AUTHOR` varchar(20) NOT NULL DEFAULT '',
+				`A_RECORD_UPDATE_DATE` datetime NOT NULL,
+				`A_RECORD_UPDATE_AUTHOR` varchar(20) NOT NULL DEFAULT '',
+				PRIMARY KEY (`ID`),
+				UNIQUE KEY `COMPANY_LOGIN` (`LOGIN`, `ID_BILLING_USERS`)
+			) ENGINE=MyISAM  DEFAULT CHARSET=latin2 ;
+		");
+		DB::getPDO()->execSql("
+			CREATE TABLE IF NOT EXISTS `PANEL_KLIENTA_BN_AUTH_HIST` (
+				`ID` int(11) NOT NULL AUTO_INCREMENT,
+				`ID_USERS2` int(11) NOT NULL,
+				`ID_BILLING_USERS` varchar(11) NOT NULL DEFAULT 'N/S;',
+				`LOGIN` varchar(255) NOT NULL DEFAULT 'N/S;',
+				`PASSWD` varchar(32) NOT NULL DEFAULT 'N/S;',
+				`REMIND_PASS_KEY` varchar(16) NOT NULL DEFAULT 'N/S;',
+				`REMIND_PASS_VALID_TILL` varchar(10) NOT NULL DEFAULT 'N/S;',
+				`A_ADM_COMPANY` varchar(64) NOT NULL DEFAULT 'N/S;',
+				`A_CLASSIFIED` varchar(64) NOT NULL DEFAULT 'N/S;',
+				`A_RECORD_CREATE_DATE` varchar(10) NOT NULL DEFAULT 'N/S;',
+				`A_RECORD_CREATE_AUTHOR` varchar(20) NOT NULL DEFAULT 'N/S;',
+				`A_RECORD_UPDATE_DATE` varchar(10) NOT NULL DEFAULT 'N/S;',
+				`A_RECORD_UPDATE_AUTHOR` varchar(20) NOT NULL DEFAULT 'N/S;',
+				PRIMARY KEY (`ID`),
+				KEY `ID_USERS2` (`ID_USERS2`)
+			) ENGINE=MyISAM  DEFAULT CHARSET=latin2 ;
+		");
+	}
+
 }

+ 58 - 16
theme/panel_biall_net.php

@@ -1,39 +1,81 @@
 <?php
 
-// TODO: file and class name must have the same name as project
+Lib::loadClass('Router');
 
 class Theme_panel_biall_net extends ThemeDefault {
 
-	// function head() { // TODO: echo 'html tag inside <head>'
+	// function head() { // echo 'html tag inside <head>'
 	// }
 
-	// function top() { // TODO: first tag after body: top menu or header
-	// 	include dirname(__FILE__) . '/Bocian/top.php';
-	// }
+	function top() { // first tag after body: top menu or header
+		include dirname(__FILE__) . '/view/top.php';
+	}
 
-	// function footer() { // TODO: before </body>
-	// 	include dirname(__FILE__) . '/view/footer.php';
-	// }
+	function footer() { // before </body>
+		include dirname(__FILE__) . '/view/footer.php';
+	}
 
-	function login($data) { // TODO: login view
+	function login($data) {
 		if (is_array($data) && !empty($data)) {
 			extract($data);
 		}
+
+		$remindPasswdLink = Router::getRoute('UrlAction_RemindPasswd')->getLink();
+
 		include dirname(__FILE__) . '/view/login.php';
 	}
 
-	function logout($data) { // TODO: logout view
+	function remind($data) {
+		if (is_array($data) && !empty($data)) {
+			extract($data);
+		}
+
+		$loginLink = Request::getPathUri();
+
+		include dirname(__FILE__) . '/view/remind.php';
+	}
+	function remindSent($data = []) {
+		if (is_array($data) && !empty($data)) {
+			extract($data);
+		}
+
+		include dirname(__FILE__) . '/view/remindSent.php';
+	}
+	function remindSetNewPassword($data = []) {
+		if (is_array($data) && !empty($data)) {
+			extract($data);
+		}
+		$loginLink = Request::getPathUri();
+		include dirname(__FILE__) . '/view/remindSetNewPass.php';
+	}
+	function remindNewPasswordSet($data) {
+		if (is_array($data) && !empty($data)) {
+			extract($data);
+		}
+		$loginLink = Request::getPathUri();
+		include dirname(__FILE__) . '/view/remindNewPassSetConfirm.php';
+	}
+
+	function logout($data) {
 		if (is_array($data) && !empty($data)) {
 			extract($data);
 		}
 		include dirname(__FILE__) . '/view/logout.php';
 	}
 
-	// function home($data) { // TODO: home page view
-	// 	if (is_array($data) && !empty($data)) {
-	// 		extract($data);
-	// 	}
-	// 	include dirname(__FILE__) . '/view/home.php';
-	// }
+	function home($data) { // TODO: home page view
+		if (is_array($data) && !empty($data)) {
+			extract($data);
+		}
+
+		$saldo = -123.456;
+		$nr_konta = "123455789 TODO";
+		// // USERS2_WINDYKACJA_STATUS.ACCOUNT_NUMBER
+		// ACCOUNT_NUMBER = Windykacja_FunkcjeL1::bankowy_make_nrach($company['NR_RACH_MASS_PAY'], $user->ID_BILLING_USERS, 0);
+		// // BILLING_OWNER.NR_RACH_MASS_PAY
+
+
+		include dirname(__FILE__) . '/view/home.php';
+	}
 
 }

+ 18 - 0
theme/view/footer.php

@@ -0,0 +1,18 @@
+<?php
+
+// $version = (file_exists(APP_PATH_ROOT . '/VERSION'))? file_get_contents(APP_PATH_ROOT . '/VERSION') : null;
+// if ($version) {
+//     echo '<div style="' . UI::fixFooterPosition('footer_style') . 'border-top:1px solid #ddd; margin-top:10px; padding:0 30px; font-size:xx-small; color:#888">';
+//     if ($version) echo 'version: '.$version . ' ';
+//     echo '</div>';
+// }
+// if (User::logged() && '1' === V::get('TEST_FEEDBACK', '', $_GET)) {
+//     echo UI::h('script', [ 'type' => "text/javascript", 'src' => "https://cdnjs.cloudflare.com/ajax/libs/html2canvas/0.4.1/html2canvas.min.js" ]);
+//     UI::inlineJS(APP_PATH_ROOT . '/static/p5UI/feedback.js');
+// }
+?>
+<div style="margin-top:32px; padding-top:6px; border-top:1px solid #ddd">
+    <div class="container" style="line-height:1.6em; font-size:12px; color:#888">
+        Copyright &copy; 1995-<?= date("Y"); ?> Biall-Net
+    </div>
+</div>

+ 15 - 0
theme/view/home.php

@@ -0,0 +1,15 @@
+<div class="container" style="padding-top:32px; padding-bottom:32px; text-align:left; font-size: 18px; line-height: 2em">
+    <p>Twoje saldo: <b><?= UI::price($saldo); ?> PLN</b></p>
+    <p>Numer rachunku do wpłat: <b><?= $nr_konta; ?></b></p>
+</div>
+
+<div class="container">
+    <p>TODO: Faktury
+        <br>- NUMER FAKTURY
+        <br>- DATA WYSTAWIENIA
+        <br>- STATUS
+        <br>- WARTOŚĆ NETTO
+        <br>- WARTOŚĆ BRUTTO
+        <br>- AKCJA
+    </p>
+</div>

+ 10 - 9
theme/view/login.php

@@ -9,32 +9,33 @@
 	<form name="LOGIN" action="" method="post" class="form-horizontal" style="width:574px; margin:0 auto;">
 		<fieldset>
 			<div class="form-group">
-				<label class="col-sm-3 control-label" for="ADM_ACCOUNT">Użytkownik:</label>
+				<label class="col-sm-3 control-label" for="ADM_ACCOUNT">Adres email:</label>
 				<div class="col-sm-6">
 					<input type="text" name="ADM_ACCOUNT" value="" id="username" class="form-control">
 				</div>
 			</div>
 			<div class="form-group">
-				<label class="col-sm-3 control-label" for="ADM_PASSWD">Hasło:</label>
+				<label class="col-sm-3 control-label" for="ADM_PASSWD">Hasło (pesel):</label>
 				<div class="col-sm-6">
 					<input type="password" name="ADM_PASSWD" class="form-control"><br>
 				</div>
 			</div>
 			<?php if (!empty($errors)) : ?>
 				<div class="form-group">
-					<div class="col-sm-9">
+					<div class="col-sm-9 col-sm-offset-3">
 						<div class="alert alert-danger"><?php echo implode('<br>', $errors); ?></div>
 					</div>
 				</div>
 			<?php endif; ?>
 			<div class="form-group">
 				<div class="col-sm-9 col-sm-offset-3">
-					<!--
-					<label class="checkbox">
-						<input name="NOPREINIT" type="checkbox"> Szybkie logowanie bez inicjalizacji kolumn
-					</label>
-					-->
-					<input name="LOGIN" type="SUBMIT" value="LOGIN" class="btn btn-primary">
+					<input name="LOGIN" type="hidden" value="LOGIN">
+					<button type="submit" class="btn btn-primary">Zaloguj się</button>
+				</div>
+			</div>
+			<div class="form-group">
+				<div class="col-sm-9 col-sm-offset-3" style="padding-top:12px">
+					<a href="<?= $remindPasswdLink ?>" style="font-size:14px">Nie pamiętasz hasła?</a>
 				</div>
 			</div>
 		</fieldset>

+ 49 - 0
theme/view/remind.php

@@ -0,0 +1,49 @@
+<div class="container">
+
+	<?php // UI::loadTemplate('apple-menu'); ?>
+
+	<div style="text-align:center; padding:36px">
+		<img src="<?= $this->asset("assets/logo-biall-net.png"); ?>">
+	</div>
+
+	<form action="" method="post" class="form-horizontal" style="width:574px; margin:0 auto;">
+		<fieldset>
+			<div class="form-group">
+				<div class="col-sm-9 col-sm-offset-3">
+					<div class="alert alert-info">Proszę wprowadzić adres email. Odnośnik pozwalający na utworzenie nowego hasła zostanie wysłany emailem.</div>
+				</div>
+			</div>
+			<div class="form-group">
+				<label class="col-sm-3 control-label" for="ADM_ACCOUNT">Adres email:</label>
+				<div class="col-sm-6">
+					<input type="text" name="ADM_ACCOUNT" value="" id="username" class="form-control">
+				</div>
+			</div>
+			<?php if (!empty($errors)) : ?>
+				<div class="form-group">
+					<div class="col-sm-9 col-sm-offset-3">
+						<div class="alert alert-danger"><?= implode('<br>', $errors); ?></div>
+					</div>
+				</div>
+			<?php endif; ?>
+			<div class="form-group">
+				<div class="col-sm-9 col-sm-offset-3" style="padding-top:12px">
+					<input name="_postTask" type="hidden" value="remind">
+					<button type="submit" class="btn btn-primary">Zdobądź nowe hasło</button>
+				</div>
+			</div>
+			<div class="form-group">
+				<div class="col-sm-9 col-sm-offset-3" style="padding-top:12px">
+					<a href="<?= $loginLink ?>" style="font-size:14px">Zaloguj się</a>
+				</div>
+			</div>
+		</fieldset>
+	</form>
+
+	<script>
+		jQuery(document).ready(function(){
+			document.getElementById('username').focus();
+		});
+	</script>
+
+</div>

+ 30 - 0
theme/view/remindNewPassSetConfirm.php

@@ -0,0 +1,30 @@
+<div class="container">
+
+	<?php // UI::loadTemplate('apple-menu'); ?>
+
+	<div style="text-align:center; padding:36px">
+		<img src="<?= $this->asset("assets/logo-biall-net.png"); ?>">
+	</div>
+
+	<form action="" method="post" class="form-horizontal" style="width:574px; margin:0 auto;">
+		<fieldset>
+			<div class="form-group">
+				<div class="col-sm-9 col-sm-offset-3">
+					<div class="alert alert-info"><?= ($msg) ? $msg : "Twoje nowe hasło zostało zapisane."; ?></div>
+				</div>
+			</div>
+			<?php if (!empty($errors)) : ?>
+				<div class="form-group">
+					<div class="col-sm-9 col-sm-offset-3">
+						<div class="alert alert-danger"><?= implode('<br>', $errors); ?></div>
+					</div>
+				</div>
+			<?php endif; ?>
+			<div class="form-group">
+				<div class="col-sm-9 col-sm-offset-3">
+					<a href="<?= $loginLink; ?>" class="btn btn-primary">Zaloguj się</a>
+				</div>
+			</div>
+		</fieldset>
+	</form>
+</div>

+ 50 - 0
theme/view/remindSent.php

@@ -0,0 +1,50 @@
+<div class="container">
+
+	<?php // UI::loadTemplate('apple-menu'); ?>
+
+	<div style="text-align:center; padding:36px">
+		<img src="<?= $this->asset("assets/logo-biall-net.png"); ?>">
+	</div>
+
+	<form name="LOGIN" action="" method="post" class="form-horizontal" style="width:574px; margin:0 auto;">
+		<fieldset>
+			<div class="form-group">
+				<div class="col-sm-9 col-sm-offset-3">
+					<div class="alert alert-info">Odnośnik potwierdzający został wysłany emailem.</div>
+				</div>
+			</div>
+			<div class="form-group">
+				<label class="col-sm-3 control-label" for="ADM_ACCOUNT">Adres email:</label>
+				<div class="col-sm-6">
+					<input type="text" name="ADM_ACCOUNT" value="" id="username" class="form-control">
+				</div>
+			</div>
+			<div class="form-group">
+				<label class="col-sm-3 control-label" for="ADM_PASSWD">Hasło (pesel):</label>
+				<div class="col-sm-6">
+					<input type="password" name="ADM_PASSWD" class="form-control"><br>
+				</div>
+			</div>
+			<?php if (!empty($errors)) : ?>
+				<div class="form-group">
+					<div class="col-sm-9 col-sm-offset-3">
+						<div class="alert alert-danger"><?php echo implode('<br>', $errors); ?></div>
+					</div>
+				</div>
+			<?php endif; ?>
+			<div class="form-group">
+				<div class="col-sm-9 col-sm-offset-3">
+					<input name="LOGIN" type="hidden" value="LOGIN">
+					<button type="submit" class="btn btn-primary">Zaloguj się</button>
+				</div>
+			</div>
+		</fieldset>
+	</form>
+
+	<script>
+		jQuery(document).ready(function(){
+			document.getElementById('username').focus();
+		});
+	</script>
+
+</div>

+ 46 - 0
theme/view/remindSetNewPass.php

@@ -0,0 +1,46 @@
+<div class="container">
+
+	<?php // UI::loadTemplate('apple-menu'); ?>
+
+	<div style="text-align:center; padding:36px">
+		<img src="<?= $this->asset("assets/logo-biall-net.png"); ?>">
+	</div>
+
+	<form action="" method="post" class="form-horizontal" style="width:574px; margin:0 auto;">
+		<fieldset>
+			<div class="form-group">
+				<div class="col-sm-9 col-sm-offset-3">
+					<div class="alert alert-info">Poniżej wprowadź swoje nowe hasło.</div>
+				</div>
+			</div>
+			<div class="form-group">
+				<label class="col-sm-3 control-label" for="ADM_PASSWD">Nowe hasło:</label>
+				<div class="col-sm-6">
+					<input type="password" id="user_passwd" name="ADM_PASSWD" class="form-control"><br>
+				</div>
+			</div>
+			<?php if (!empty($errors)) : ?>
+				<div class="form-group">
+					<div class="col-sm-9 col-sm-offset-3">
+						<div class="alert alert-danger"><?php echo implode('<br>', $errors); ?></div>
+					</div>
+				</div>
+			<?php endif; ?>
+			<div class="form-group">
+				<div class="col-sm-9 col-sm-offset-3">
+					<input type="hidden" name="_postTask" value="set">
+					<input type="hidden" name="ADM_ACCOUNT" value="<?= $login ; ?>">
+					<input type="hidden" name="REMIND_KEY" value="<?= $key ; ?>">
+					<button type="submit" class="btn btn-primary">Zapisz nowe hasło</button>
+				</div>
+			</div>
+		</fieldset>
+	</form>
+
+	<script>
+		jQuery(document).ready(function(){
+			document.getElementById('user_passwd').focus();
+		});
+	</script>
+
+</div>

+ 53 - 0
theme/view/top.php

@@ -0,0 +1,53 @@
+<?php
+
+$listMenu = [];
+// $listMenu[] = [ 'label' => "Faktury", 'url' => "index.php?_route=ViewTableAjax&namespace=default_db/api_produkty_103075_view", 'ns' => "default_db/api_produkty_103075_view" ];
+
+$activeViewTableNS = ('ViewTableAjax' === V::get('_route', '', $_GET)) ? V::get('namespace', '', $_GET) : '';
+
+?>
+<nav class="navbar navbar-inverse" style="border-radius:0">
+    <div class="container-fluid">
+        <div class="navbar-header">
+            <a href="index.php" class="navbar-brand" style="padding:2px">
+                <img src="<?= $this->asset("assets/logo-biall-net.png"); ?>" alt="BIALL-NET" style="height:46px"/>
+            </a>
+        </div>
+        <div class="collapse navbar-collapse">
+
+            <?= UI::h('ul', [ 'class' => "nav navbar-nav" ], array_map(function ($itemMenu) use ($activeViewTableNS) {
+                $ns = $itemMenu['ns'];
+                return UI::h('li', array_merge(
+                    [],
+                    (!empty($activeViewTableNS) && $ns === $activeViewTableNS) ? [ 'class' => "active" ] : []
+                ), [
+                    UI::h('a', [ 'href' => $itemMenu['url'] ], $itemMenu['label']),
+                ]);
+            }, $listMenu)); ?>
+
+            <div class="navbar-form navbar-right">
+                <div class="btn-group">
+                    <button type="button" class="btn btn-link" style="margin:0; padding:6px 8px 4px 8px;"><?php S::show_session_timer(); ?></button>
+                    <!-- <a href="index.php?_route=UserMsgs" class="btn btn-link" style="margin:0; padding:6px 8px 0 8px; font-size:20px; line-height:24px;"><i class="glyphicon glyphicon-envelope"></i></a> -->
+                    <div class="btn-group">
+                        <button id="ProcesMenuLoginDropdownLink" type="button" class="btn btn-link dropdown-toggle" data-toggle="dropdown" aria-expanded="false"><?= User::getName(); ?> <span class="caret"></span></button>
+                        <ul class="dropdown-menu" role="menu">
+                            <li><a href="index.php?_route=UrlAction_ChangePassword"><i class="glyphicon glyphicon-lock"></i> Zmień hasło</a></li>
+                            <li class="divider"></li>
+
+                            <!-- <li><a href="index.php?_route=UserMsgs" title="Wiadomości systemowe"><i class="glyphicon glyphicon-envelope"></i> Wiadomości</a></li> -->
+                            <!-- <li><a href="index.php?_route=Notify" title="Powiadomienia"><i class="glyphicon glyphicon-bell"></i> Powiadomienia</a></li> -->
+                            <!-- <li><a href="index.php?_route=Users&amp;_task=reloadPerms" title="Przeładuj uprawnienia"><i class="glyphicon glyphicon-refresh"></i> Przeładuj uprawnienia</a></li> -->
+                            <!-- <li class="divider"></li> -->
+                            <li><a href="index.php?LOGIN=LOGOUT"><i class="glyphicon glyphicon-off"></i> Wyloguj</a></li>
+                        </ul>
+                    </div>
+                    <div class="btn-group">
+                        <a class="btn btn-link" href="index.php?LOGIN=LOGOUT"><i class="glyphicon glyphicon-off"></i> Wyloguj</a>
+                    </div>
+                </div>
+            </div>
+
+        </div>
+    </div>
+</nav>

+ 162 - 0
tools/RemindPasswd.php

@@ -0,0 +1,162 @@
+<?php
+
+Lib::loadClass('RouteToolBase');
+Lib::loadClass('UI');
+Lib::loadClass('Response');
+Lib::loadClass('Theme');
+
+require_once dirname(__FILE__) . '/../auth.php'; // Theme_Auth_panel_biall_net
+
+// class name must have the same name as file
+// index.php?_route=UrlAction_RemindPasswd  - uruchamia defaultAction
+class RouteTool_RemindPasswd extends RouteToolBase {
+
+	function handleAuth() {
+		// return (!User::logged())
+		// ? $this->remindPasswdAction()
+		// : $this->sendAlreadyLoggedIn()
+		// ;
+		$task = V::get('_task', '', $_GET);
+		switch ($task) {
+			case 'rp': return $this->rpAction();
+			default: return $this->remindPasswdAction();
+		}
+	}
+
+	function remindPasswdAction() {
+		if ('remind' == V::get('_postTask', '', $_POST)) {
+			try {
+				$email = V::get('ADM_ACCOUNT', '', $_POST);
+				$this->remindPasswd($email);
+			} catch (Exception $e) {
+				$this->sendRemindPasswdForm([ 'errors' => [ $e->getMessage() ] ]);
+			}
+			return $this->sendRemindPasswdSent();
+		}
+		$this->sendRemindPasswdForm();
+		exit;
+	}
+	function remindPasswd($email) {
+		if (empty($email)) throw new Exception("Proszę podać adres email");
+		if (!filter_var($email, FILTER_VALIDATE_EMAIL)) throw new Exception("Proszę podać poprawny adres email");
+
+		// BŁĄD: Brak zarejestrowanego użytkownika o wprowadzonym adresie email.
+
+		$item = Theme_Auth_panel_biall_net::fetchUser($email);
+		$remindKey = Theme_Auth_panel_biall_net::generateRemindKey($email);
+		{
+			$resetLink = $this->getLink('rp', [ 'login' => $email, 'key' => $remindKey ]);
+
+			$recipient = "piotrl86+bn-test-remind@gmail.com"; // TODO: $email
+
+			$headers = "MIME-Version: 1.0\n";
+			$headers .= "Content-Type: text/plain; charset=\"utf-8\"\n";
+			//$headers .= 'Bcc: pawel.ratajczak@biall.com.pl' . "\r\n";
+			$headers .= 'From: Panel klienta BIALL-NET <noreply@biall-net.pl>' . "\r\n";
+			$headers .= 'Bcc: piotrl86@gmail.com' . "\r\n";
+	
+			$subject = "Panel BIALL-NET: Ustawianie nowego hasła";
+
+			$body = implode("\r\n\r\n", [
+				"Ktoś poprosił o wygenerowanie nowego hasła dla następującego konta:",
+				"Nazwa witryny: Panel klienta BIALL-NET",
+				"Nazwa użytkownika: {$email}",
+				"Jeśli to pomyłka po prostu zignoruj tego maila i nic się nie stanie.",
+				"Aby zresetować hasło, przejdź tutaj:",
+				"{$resetLink}",
+			]);
+
+			mail($recipient, $subject, $body, $headers);
+		}
+	}
+
+	function rpAction() {
+		if ('set' == V::get('_postTask', '', $_POST)) {
+			try {
+				$email = V::get('ADM_ACCOUNT', '', $_POST);
+				$remindKey = V::get('REMIND_KEY', '', $_POST);
+				$newPasswd = V::get('ADM_PASSWD', '', $_POST);
+				Theme_Auth_panel_biall_net::setPasswd($email, $newPasswd, $remindKey);
+			} catch (Exception $e) {
+				$this->sendNewPasswdForm(array_merge($_GET, [ 'errors' => [ $e->getMessage() ] ]));
+			}
+			return $this->sendRemindPasswdSet();
+		}
+		$this->sendNewPasswdForm($_GET);
+		exit;
+	}
+	function sendNewPasswdForm($args = []) {
+		UI::gora();
+		UI::tryCatchView([ $this, 'setNewPassForm' ], [ 'args' => $args ]);
+		UI::dol();
+		exit;
+	}
+	function sendRemindPasswdSet() {
+		UI::gora();
+		Theme::remindNewPasswordSet($data = [ 'msg' => "Twoje nowe hasło zostało zapisane." ]);
+		UI::dol();
+		exit;
+	}
+
+	function setNewPassForm($args) {
+		$login = V::get('login', '', $args);
+		$remindKey = V::get('key', '', $args);
+		if (empty($login)) throw new Exception("Missing login!");
+		if (empty($remindKey)) throw new Exception("Missing key!");
+
+		Theme::remindSetNewPassword($args);
+	}
+
+	function sendRemindPasswdForm($data = []) {
+		UI::gora();
+		Theme::remind($data);
+		UI::dol();
+		exit;
+	}
+
+	function sendRemindPasswdSent() {
+		UI::gora();
+		Theme::remindSent($data = []);
+		UI::dol();
+		exit;
+	}
+
+	function sendAlreadyLoggedIn() {
+		UI::gora();
+		// Theme::top();
+		echo UI::h('h1', [], "TODO: Already logged in");
+		UI::dol();
+		exit;
+	}
+
+	function defaultAction() {
+		UI::gora();
+		Theme::top();
+		echo '<h1>ReminPasswd Tool</h1>';
+		// UI::inlineJS(__FILE__ . '.example.js', [
+		// 	'URL_TEST_AJAX_ACTION' => $this->getLink('testAjax'),
+		// ]);
+		UI::dol();
+	}
+
+	// function testAjaxAction() {
+	// 	Response::sendTryCatchJson(array($this, 'testAjax'), $_REQUEST); // args from request
+	// 	// Response::sendTryCatchJson(array($this, 'testAjax'), $args = 'JSON_FROM_REQUEST_BODY'); // args from json request
+	// }
+	// function testAjax($args) { // args given by sendTryCatchJson
+	// 	$items = [
+	// 		[ 'ID' => 1, 'name' => 'x', 'desc' => 'a' ],
+	// 		[ 'ID' => 2, 'name' => 'y', 'desc' => 'b' ],
+	// 		[ 'ID' => 3, 'name' => 'z',  'desc' => 'c' ],
+	// 	];
+
+	// 	return [
+	// 		'type' => 'success',
+	// 		'msg' => 'OK',
+	// 		'body' => [
+	// 			'items' => $items,
+	// 		]
+	// 	];
+	// }
+
+}