Robert 2 hours ago
parent b1d1a09254
commit c17f89bc96
  1. 6
      protected/src/Classes/Logic/IndexAuthContainer.php
  2. 86
      protected/src/Classes/Logic/IndexLogin.php
  3. 51
      protected/src/Classes/Models/HomeLoginModel.php
  4. 4
      protected/src/Configs/on_HTML.php
  5. 45
      protected/src/Controllers/App/HomeController.php
  6. 6
      protected/src/Templates/main.php
  7. 2
      protected/src/Views/Common/App/Home/Index.php
  8. 28
      protected/src/Views/Common/App/Home/Login.php
  9. 86
      protected/src/Views/Common/App/Reg/Form.php
  10. 31
      public/assets/css/breadcrumbs.css
  11. 39
      public/assets/css/buttons.css
  12. 88
      public/assets/css/index.css
  13. 24
      public/assets/css/registration.css
  14. 43
      public/assets/js/registration.js
  15. 12
      public/index.php

@ -16,7 +16,7 @@ namespace Project\Classes\Logic;
*/
class IndexAuthContainer
{
public static function Logins(): string
public static function Logins(object $local): void
{
$auth = '<div class="auth-container">';
$loggedin = $_SESSION['email'] ?? false;
@ -27,6 +27,8 @@ class IndexAuthContainer
$auth .= '<a href="/App/Home/Logout.html" class="btn login-btn">Logout</a>';
}
$auth .= '</div>';
return $auth;
$local->view->set("Auth", $auth);
$local->html->addCss("css/buttons.css");
}
}

@ -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 "";
}
}

@ -12,9 +12,9 @@ use IOcornerstone\Framework\Configure;
Configure::set('html', array(
'author' => 'Robert Strutts',
'title' => 'StickingToGoal.com',
'title' => 'StickingToGoals.com',
// 'javascript' => ['js/analytics.js'=>'project''],
'css' => ['css/index.css'=>'project'],
'css' => ['css/breadcrumbs.css'=>'project'],
'robots' => 'noindex',
'keywords' => 'goal, setting',
'description' => 'Goals site',

@ -14,6 +14,7 @@ use Project\Classes\{
BaseController,
Logic\HomeSearch,
Logic\IndexAuthContainer,
Logic\IndexLogin,
Models\HomeFetchModel
};
use IOcornerstone\Framework\{
@ -35,6 +36,9 @@ class HomeController extends BaseController
{
Security::initSessions();
$this->html->setActiveCrumb("Main Page");
$this->html->addCss("css/index.css");
$this->html->addToJavascript("function filterTag(tag){ \r\n window.location='?tag='+encodeURIComponent(tag); \r\n }");
$pdo = Configure::get('db');
@ -50,8 +54,7 @@ class HomeController extends BaseController
$goals = $model->GetGoals($inputs);
$this->view->set("Goals", $goals);
$auth = IndexAuthContainer::Logins();
$this->view->set("Auth", $auth);
IndexAuthContainer::Logins($this);
$uid = HomeSearch::MyUUID();
$this->view->set("Uid", $uid);
@ -66,22 +69,51 @@ class HomeController extends BaseController
public function Register(): ResponseInterface
{
$this->html->setActiveCrumb("Registion");
$this->html->setBreadcrumbs(['/App/Home/Index.html'=>"Main Page"]);
$this->html->addCss("css/registration.css");
$this->html->addJS("js/registration.js");
$this->html->setTitleAndHeader("Register");
$this->view->set('html', $this->html);
$this->view->setPhpTemplate('main');
$this->view->setView("App/Reg/Form");
$this->view->setView("App/Home/TOS");
$myView = $this->view->fetch($this);
$myView .= "</body>" . PHP_EOL . "</html>";
return $this->returnResponse($myView);
}
public function Login(): ResponseInterface
{
$this->html->setActiveCrumb("LogIn");
$this->html->setBreadcrumbs(['/App/Home/Index.html'=>"Main Page"]);
Security::initSessions();
return $this->returnResponse("");
$login = IndexLogin::doLogin();
if ($login === false) {
$this->view->set('html', $this->html);
$this->view->setPhpTemplate('main');
$this->view->set("token", $_SESSION['token']);
$this->view->setView("App/Home/Login");
$myView = $this->view->fetch($this);
} else {
$myView = "";
}
return $this->returnResponse($myView);
}
public function Logout(): ResponseInterface
{
$this->html->setActiveCrumb("LogOut");
$this->html->setBreadcrumbs(['/App/Home/Index.html'=>"Main Page"]);
$this->html->setTitleAndHeader("Logged Out");
Security::initSessions();
$_SESSION = [];
@ -89,8 +121,11 @@ class HomeController extends BaseController
session_destroy();
$html = '<html><head><title>Logged Out</title></head><body><h1>Logged Out!</h1></body></html>';
return $this->returnResponse($html);
$this->view->set('html', $this->html);
$this->view->setPhpTemplate('main');
$myView = $this->view->fetch($this);
return $this->returnResponse($myView);
}
}

@ -12,7 +12,7 @@ declare(strict_types=1);
<html lang="en-US">
<head>
<meta charset="utf-8">
<base href="<?= PROJECT_ASSETS_BASE_REF; ?>/">
<base href="<?= PROJECT_BASE_REF; ?>/">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="keywords" content="<?= $html->getKeywords(); ?>">
<meta name="description" content="<?= $html->getDescription(); ?>">
@ -35,7 +35,9 @@ declare(strict_types=1);
</head>
<body <?= $html->getBody(); ?>>
<?= $local->pageOutput ?>
<?= $html->getBreadcrumbsAuto(); ?>
<?= $local->pageOutput; ?>
<?= $html->getFooter(); ?>

@ -17,7 +17,7 @@ function end_of_the_line(): void
<?= $Auth ?>
<div class="container">
<h1>🎯 StickingToGoals.com</h1>
<h1>🎯<?= $html->getTitle(); ?></h1>
<form method="GET">
<input name="search" placeholder="Search">
<button>Search</button>

@ -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>

@ -8,43 +8,8 @@ declare(strict_types=1);
*/
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Register</title>
<style>
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;
}
</style>
</head>
<body>
<div class="container">
<h2>Register</h2>
<div class="container">
<h2><?= $html->getHeader(); ?></h2>
<div id="success" class="hidden mysuccess">
<p>Registration successful! Check your email to verify.</p>
@ -78,49 +43,4 @@ declare(strict_types=1);
</table>
<button type="submit" id="reg">Register</button>
</form>
</div>
<script>
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);
}
});
</script>
</div>

@ -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}
.container {max-width:900px;margin:30px auto;background:#fff;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:1px solid #ccc}
button{background:#4CAF50;color:#fff;border:none;padding:10px;border-radius:6px;cursor:pointer}
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;
body {
font-family:Arial;
background:#f4f6f9;
margin:0
}
.btn {
padding: 12px 24px;
font-size: 16px;
border: none;
border-radius: 6px;
cursor: pointer;
transition: all 0.3s ease;
text-decoration: none;
color: white;
.container {
max-width:900px;
margin:30px auto;
background:#fff;
padding:20px;
border-radius:10px;
box-shadow:0 4px 12px rgba(0,0,0,.1)
}
.login-btn {
background: #3498db;
input,textarea{
width:100%;
padding:10px;
margin:8px 0;
border-radius:6px;
border:1px solid #ccc
}
.login-btn:hover {
background: #2980b9;
transform: translateY(-2px);
.goal-item{
padding:10px;
border-bottom:1px solid #eee
}
.register-btn {
background: #2ecc71;
.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
}
.register-btn:hover {
background: #27ae60;
transform: translateY(-2px);
.auth-container {
display: flex;
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);
}
});

@ -3,18 +3,6 @@
declare(strict_types=1);
define("BaseDir", dirname(__DIR__)); // Project DIR
define("PROJECT_ASSETS_DIR", BaseDir . DIRECTORY_SEPARATOR . "public" . DIRECTORY_SEPARATOR . "assets" . DIRECTORY_SEPARATOR);
$server_port = $_SERVER['SERVER_PORT'] ?? 80;
$secure_port_on = $_SERVER['HTTPS'] ?? "off";
$use_secure = ($server_port == "443" || $secure_port_on == "on");
$protocol = ($use_secure) ? "https://" : "http://";
$domain_name = $_SERVER['HTTP_HOST'] ?? "";
define("HTTP_PROT", $protocol);
define("PROJECT_ASSETS_BASE_REF", $protocol . $domain_name ."/assets");
define("ASSETS_DIR", PROJECT_ASSETS_DIR);
define('ASSETS_BASE_REF', $protocol . $domain_name . "/assets");
const IO_CORNERSTONE_PROJECT = BaseDir . DIRECTORY_SEPARATOR . "protected". DIRECTORY_SEPARATOR. "src" . DIRECTORY_SEPARATOR;

Loading…
Cancel
Save