parent
b1d1a09254
commit
c17f89bc96
@ -0,0 +1,86 @@ |
|||||||
|
<?php |
||||||
|
|
||||||
|
declare(strict_types=1); |
||||||
|
|
||||||
|
/** |
||||||
|
* @author Robert Strutts |
||||||
|
* @copyright (c) 2026, Robert Strutts |
||||||
|
* @license MIT |
||||||
|
*/ |
||||||
|
|
||||||
|
namespace Project\Classes\Logic; |
||||||
|
|
||||||
|
use \IOcornerstone\Framework\Uuids\UuidV7; |
||||||
|
use \IOcornerstone\Framework\Configure; |
||||||
|
use \Project\Classes\Models\HomeLoginModel; |
||||||
|
|
||||||
|
/** |
||||||
|
* Description of IndexLogin |
||||||
|
* |
||||||
|
* @author Robert Strutts |
||||||
|
*/ |
||||||
|
class IndexLogin |
||||||
|
{ |
||||||
|
|
||||||
|
private static function allowLogin(string $dbHash): bool |
||||||
|
{ |
||||||
|
$uuid = $_POST['token'] ?? false; |
||||||
|
$suuid = $_SESSION['token'] ?? false; |
||||||
|
$pwd = $_POST['pwd'] ?? false; |
||||||
|
if ($pwd === false || empty($pwd) || $uuid === false || $suuid === false) { |
||||||
|
return false; |
||||||
|
} |
||||||
|
$ts = UuidV7::getTimestampFromUuidV7($uuid); |
||||||
|
$ts2 = UuidV7::getTimestampFromUuidV7($suuid); |
||||||
|
$d = UuidV7::getFormatedDate($ts); |
||||||
|
$d2 = UuidV7::getFormatedDate($ts2); |
||||||
|
|
||||||
|
$diffInSeconds = abs(strtotime($d) - strtotime($d2)); |
||||||
|
if ($diffInSeconds > 600) { // 600 seconds = 10 minutes |
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
// $dbHash = password_hash($pwd, PASSWORD_ARGON2ID); |
||||||
|
|
||||||
|
$allow = password_verify($pwd, $dbHash); |
||||||
|
if (!$allow) { |
||||||
|
return false; |
||||||
|
} |
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
public static function doLogin(): bool |
||||||
|
{ |
||||||
|
$login = $_POST['login'] ?? false; |
||||||
|
if ($login === false) { |
||||||
|
$token = UuidV7::generateUuidV7(); |
||||||
|
$_SESSION['token'] = $token; |
||||||
|
return false; // IE Show Login |
||||||
|
} |
||||||
|
|
||||||
|
$pdo = Configure::get('db'); |
||||||
|
$model = new HomeLoginModel($pdo); |
||||||
|
|
||||||
|
$dbHash = $model->getLogin($login); |
||||||
|
$allow = self::allowLogin($dbHash); |
||||||
|
if ($allow) { |
||||||
|
|
||||||
|
$level = $_SESSION['accessLevel'] ?? 0; |
||||||
|
$user = match ($level) { |
||||||
|
1 => "User", |
||||||
|
2 => "Moderator", |
||||||
|
3 => "Admin", |
||||||
|
default => "Error", |
||||||
|
}; |
||||||
|
|
||||||
|
if ($user === "User") { |
||||||
|
header("Location: /App/Home/Index.html"); |
||||||
|
} |
||||||
|
if ($user === "Admin") { |
||||||
|
header("Location: /Admin/Home/Index.html"); |
||||||
|
} |
||||||
|
} |
||||||
|
return $allow; |
||||||
|
} |
||||||
|
} |
||||||
@ -0,0 +1,51 @@ |
|||||||
|
<?php |
||||||
|
|
||||||
|
declare(strict_types=1); |
||||||
|
|
||||||
|
/** |
||||||
|
* @author Robert Strutts |
||||||
|
* @copyright (c) 2026, Robert Strutts |
||||||
|
* @license MIT |
||||||
|
*/ |
||||||
|
|
||||||
|
namespace Project\Classes\Models; |
||||||
|
|
||||||
|
/** |
||||||
|
* Description of HomeLoginModel |
||||||
|
* Do Login... |
||||||
|
* @author Robert Strutts |
||||||
|
*/ |
||||||
|
class HomeLoginModel |
||||||
|
{ |
||||||
|
|
||||||
|
public function __construct(private \PDO $pdo) |
||||||
|
{ |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
public function getLogin(string $emailAddress): string |
||||||
|
{ |
||||||
|
try { |
||||||
|
$sqlEmail = "SELECT id, first_name FROM emails WHERE is_active=1 AND email=? LIMIT 1"; |
||||||
|
$stmtEmail = $this->pdo->prepare($sqlEmail); |
||||||
|
$stmtEmail->execute([$emailAddress]); |
||||||
|
$email_row = $stmtEmail->fetch(\PDO::FETCH_ASSOC); |
||||||
|
|
||||||
|
$sqlUser = "SELECT pwd, access_level FROM users WHERE email_id=? LIMIT 1"; |
||||||
|
$stmtUser = $this->pdo->prepare($sqlEmail); |
||||||
|
$stmtUser->execute([$emailAddress]); |
||||||
|
$user_row = $stmtUser->fetch(\PDO::FETCH_ASSOC); |
||||||
|
|
||||||
|
$accessLevel = $user_row['access_level'] ?? 0; |
||||||
|
$_SESSION['accessLevel'] = $accessLevel; |
||||||
|
|
||||||
|
$name = $email_row['first_name'] ?? ""; |
||||||
|
$_SESSION['first_name'] = $name; |
||||||
|
|
||||||
|
return $user_row['pwd']; |
||||||
|
} catch (\PDOException $e) { |
||||||
|
echo $e->getMessage(); |
||||||
|
} |
||||||
|
return ""; |
||||||
|
} |
||||||
|
} |
||||||
@ -0,0 +1,28 @@ |
|||||||
|
<?php |
||||||
|
|
||||||
|
declare(strict_types=1); |
||||||
|
|
||||||
|
/** |
||||||
|
* @author Robert Strutts |
||||||
|
* @copyright (c) 2026, Robert Strutts |
||||||
|
* @license MIT |
||||||
|
*/ |
||||||
|
|
||||||
|
?> |
||||||
|
<form method="POST"> |
||||||
|
<input type="hidden" name="token" value="<?= $token ?>">
|
||||||
|
<center> |
||||||
|
<fieldset style="width: 300px;"><legend><?= $html->getTitle() ?> - Log In</legend>
|
||||||
|
<table border="0"> |
||||||
|
<tr> |
||||||
|
<th><label for="login">Email:</label></th> |
||||||
|
<td><input type="text" name="login"></td> |
||||||
|
</tr><tr> |
||||||
|
<th><label for="pwd">Password:</label></th> |
||||||
|
<td><input type="password" name="pwd"></td> |
||||||
|
</tr> |
||||||
|
</table> |
||||||
|
<input type="submit" value="Login"> |
||||||
|
</fieldset> |
||||||
|
</center> |
||||||
|
</form> |
||||||
@ -0,0 +1,31 @@ |
|||||||
|
/* Style the list */ |
||||||
|
ul.breadcrumb { |
||||||
|
padding: 10px 16px; |
||||||
|
list-style: none; |
||||||
|
background-color: #eee; |
||||||
|
} |
||||||
|
|
||||||
|
/* Display list items side by side */ |
||||||
|
ul.breadcrumb li { |
||||||
|
display: inline; |
||||||
|
font-size: 18px; |
||||||
|
} |
||||||
|
|
||||||
|
/* Add a slash symbol (/) before/behind each list item */ |
||||||
|
ul.breadcrumb li+li:before { |
||||||
|
padding: 8px; |
||||||
|
color: black; |
||||||
|
content: "/\00a0"; |
||||||
|
} |
||||||
|
|
||||||
|
/* Add a color to all links inside the list */ |
||||||
|
ul.breadcrumb li a { |
||||||
|
color: #0275d8; |
||||||
|
text-decoration: none; |
||||||
|
} |
||||||
|
|
||||||
|
/* Add a color on mouse-over */ |
||||||
|
ul.breadcrumb li a:hover { |
||||||
|
color: #01447e; |
||||||
|
text-decoration: underline; |
||||||
|
} |
||||||
@ -0,0 +1,39 @@ |
|||||||
|
button{ |
||||||
|
background:#4CAF50; |
||||||
|
color:#fff; |
||||||
|
border:none; |
||||||
|
padding:10px; |
||||||
|
border-radius:6px; |
||||||
|
cursor:pointer |
||||||
|
} |
||||||
|
button:hover{ |
||||||
|
background:#45a049 |
||||||
|
} |
||||||
|
.btn { |
||||||
|
padding: 12px 24px; |
||||||
|
font-size: 16px; |
||||||
|
border: none; |
||||||
|
border-radius: 6px; |
||||||
|
cursor: pointer; |
||||||
|
transition: all 0.3s ease; |
||||||
|
text-decoration: none; |
||||||
|
color: white; |
||||||
|
} |
||||||
|
|
||||||
|
.login-btn { |
||||||
|
background: #3498db; |
||||||
|
} |
||||||
|
|
||||||
|
.login-btn:hover { |
||||||
|
background: #2980b9; |
||||||
|
transform: translateY(-2px); |
||||||
|
} |
||||||
|
|
||||||
|
.register-btn { |
||||||
|
background: #2ecc71; |
||||||
|
} |
||||||
|
|
||||||
|
.register-btn:hover { |
||||||
|
background: #27ae60; |
||||||
|
transform: translateY(-2px); |
||||||
|
} |
||||||
@ -1,44 +1,58 @@ |
|||||||
body {font-family:Arial;background:#f4f6f9;margin:0} |
body { |
||||||
.container {max-width:900px;margin:30px auto;background:#fff;padding:20px;border-radius:10px;box-shadow:0 4px 12px rgba(0,0,0,.1)} |
font-family:Arial; |
||||||
input,textarea{width:100%;padding:10px;margin:8px 0;border-radius:6px;border:1px solid #ccc} |
background:#f4f6f9; |
||||||
button{background:#4CAF50;color:#fff;border:none;padding:10px;border-radius:6px;cursor:pointer} |
margin:0 |
||||||
button:hover{background:#45a049} |
|
||||||
.goal-item{padding:10px;border-bottom:1px solid #eee} |
|
||||||
.advice-box{border:1px solid #ddd;border-radius:8px;padding:15px;margin-top:15px;background:#fafafa} |
|
||||||
.vote{background:#eee;padding:5px 10px;border-radius:6px;display:inline-block} |
|
||||||
.comment{margin-left:20px;border-left:2px solid #ccc;padding-left:8px;margin-top:5px} |
|
||||||
.tag{display:inline-block;background:#3498db;color:#fff;padding:3px 8px;border-radius:5px;margin:2px;font-size:12px;cursor:pointer} |
|
||||||
|
|
||||||
.auth-container { |
|
||||||
display: flex; |
|
||||||
gap: 20px; |
|
||||||
} |
} |
||||||
|
.container { |
||||||
.btn { |
max-width:900px; |
||||||
padding: 12px 24px; |
margin:30px auto; |
||||||
font-size: 16px; |
background:#fff; |
||||||
border: none; |
padding:20px; |
||||||
|
border-radius:10px; |
||||||
|
box-shadow:0 4px 12px rgba(0,0,0,.1) |
||||||
|
} |
||||||
|
input,textarea{ |
||||||
|
width:100%; |
||||||
|
padding:10px; |
||||||
|
margin:8px 0; |
||||||
border-radius:6px; |
border-radius:6px; |
||||||
cursor: pointer; |
border:1px solid #ccc |
||||||
transition: all 0.3s ease; |
|
||||||
text-decoration: none; |
|
||||||
color: white; |
|
||||||
} |
} |
||||||
|
.goal-item{ |
||||||
.login-btn { |
padding:10px; |
||||||
background: #3498db; |
border-bottom:1px solid #eee |
||||||
} |
} |
||||||
|
.advice-box{ |
||||||
.login-btn:hover { |
border:1px solid #ddd; |
||||||
background: #2980b9; |
border-radius:8px; |
||||||
transform: translateY(-2px); |
padding:15px; |
||||||
|
margin-top:15px; |
||||||
|
background:#fafafa |
||||||
} |
} |
||||||
|
.vote{ |
||||||
.register-btn { |
background:#eee; |
||||||
background: #2ecc71; |
padding:5px 10px; |
||||||
|
border-radius:6px; |
||||||
|
display:inline-block |
||||||
|
} |
||||||
|
.comment{ |
||||||
|
margin-left:20px; |
||||||
|
border-left:2px solid #ccc; |
||||||
|
padding-left:8px; |
||||||
|
margin-top:5px |
||||||
|
} |
||||||
|
.tag{ |
||||||
|
display:inline-block; |
||||||
|
background:#3498db; |
||||||
|
color:#fff; |
||||||
|
padding:3px 8px; |
||||||
|
border-radius:5px; |
||||||
|
margin:2px; |
||||||
|
font-size:12px; |
||||||
|
cursor:pointer |
||||||
} |
} |
||||||
|
|
||||||
.register-btn:hover { |
.auth-container { |
||||||
background: #27ae60; |
display: flex; |
||||||
transform: translateY(-2px); |
gap: 20px; |
||||||
} |
} |
||||||
@ -0,0 +1,24 @@ |
|||||||
|
body { |
||||||
|
font-family: Arial; |
||||||
|
background:#f5f5f5; |
||||||
|
} |
||||||
|
.container { |
||||||
|
width: 230px; |
||||||
|
margin: 50px auto; |
||||||
|
padding: 20px; |
||||||
|
background: white; |
||||||
|
border-radius: 8px; |
||||||
|
} |
||||||
|
input, button { |
||||||
|
margin: 8px 0; |
||||||
|
padding: 10px; |
||||||
|
} |
||||||
|
.hidden { |
||||||
|
display:none; |
||||||
|
} |
||||||
|
.error { |
||||||
|
color: red; |
||||||
|
} |
||||||
|
.mysuccess { |
||||||
|
color: green; |
||||||
|
} |
||||||
@ -0,0 +1,43 @@ |
|||||||
|
document.getElementById("myForm").addEventListener('submit', async function (e) { |
||||||
|
e.preventDefault(); |
||||||
|
|
||||||
|
const formData = new FormData(e.target); |
||||||
|
|
||||||
|
/* Log all form data |
||||||
|
for (let [key, value] of formData.entries()) { |
||||||
|
console.log(key + ': ' + value); |
||||||
|
} |
||||||
|
*/ |
||||||
|
|
||||||
|
const formObject = Object.fromEntries(formData.entries()); |
||||||
|
// console.log('Form object:', formObject);
|
||||||
|
|
||||||
|
try { |
||||||
|
const response = await fetch('/Data/RegPost/Save.html', { |
||||||
|
method: 'POST', |
||||||
|
headers: {"Content-Type": "application/json"}, |
||||||
|
body: JSON.stringify(formObject) |
||||||
|
}); |
||||||
|
|
||||||
|
const result = await response.json(); |
||||||
|
|
||||||
|
// Multiple ways to check success
|
||||||
|
if (response.status === 200 && result.success === true) { |
||||||
|
console.log('Success:', result); |
||||||
|
document.getElementById("success").classList.remove("hidden"); |
||||||
|
document.getElementById("errors").textContent = ""; |
||||||
|
document.getElementById("reg").disabled = true; |
||||||
|
|
||||||
|
//} else if (result.success) {
|
||||||
|
// console.log('Success:', result);
|
||||||
|
// } else if (result.error === false) {
|
||||||
|
// console.log('Success:', result);
|
||||||
|
} else { |
||||||
|
document.getElementById("errors").textContent = result.errors; |
||||||
|
console.error('Failed:', result); |
||||||
|
} |
||||||
|
} catch (error) { |
||||||
|
document.getElementById("errors").textContent = error; |
||||||
|
console.error('Error:', error); |
||||||
|
} |
||||||
|
}); |
||||||
Loading…
Reference in new issue