Change design

This commit is contained in:
2026-09-04 11:09:34 +02:00
parent 28e1616c94
commit 78c1d8e844
36 changed files with 355 additions and 263 deletions
+12 -12
View File
@@ -1,6 +1,6 @@
<?php
namespace Franzz\MyThoughts;
namespace Franzz\Daydream;
use Franzz\Objects\PhpObject;
use Franzz\Objects\ToolBox;
@@ -28,7 +28,7 @@ class Controller extends PhpObject {
'logout'
];
private MyThoughts $oMyThoughts;
private Daydream $oDaydream;
private array $asReq = [];
private string $sCsrfToken = '';
@@ -64,32 +64,32 @@ class Controller extends PhpObject {
//Authentication and CSRF protection share the same server-side session.
$this->initCsrfToken();
$this->oMyThoughts = new MyThoughts($sProcessPage, $this->asReq['t']);
$this->oDaydream = new Daydream($sProcessPage, $this->asReq['t']);
//Validate CSRF, then release the session lock before long-running work.
$bValidMutationRequest = $this->validateMutationRequest($sAction);
if(!$bValidMutationRequest || !in_array($sAction, self::SESSION_WRITING_ACTIONS, true)) $this->closeSession();
if(!$bValidMutationRequest) $sResult = MyThoughts::getJsonResult(false, MyThoughts::UNAUTHORIZED);
else $sResult = ($sAction == '') ? $this->oMyThoughts->getAppMainPage($this->getCsrfToken()) : $this->dispatch($sAction);
if(!$bValidMutationRequest) $sResult = Daydream::getJsonResult(false, Daydream::UNAUTHORIZED);
else $sResult = ($sAction == '') ? $this->oDaydream->getAppMainPage($this->getCsrfToken()) : $this->dispatch($sAction);
//Clean errors
$sDebug = ob_get_clean();
if($sDebug != '') $this->oMyThoughts->addUncaughtError($sDebug);
if($sDebug != '') $this->oDaydream->addUncaughtError($sDebug);
$this->closeSession();
return $sResult;
}
private function dispatch(string $sAction): string {
$oJournal = $this->oMyThoughts->getJournal();
$oJournal = $this->oDaydream->getJournal();
return match($sAction) {
/* Account */
'signup' => $this->oMyThoughts->signup($this->asReq['name'], $this->asReq['email'], $this->asReq['password'], $this->asReq['t']),
'login' => $this->oMyThoughts->login($this->asReq['email'], $this->asReq['password'], $this->asReq['t'], $this->asReq['remember']),
'logout' => $this->oMyThoughts->logout(),
'account' => $this->oMyThoughts->updateAccount($this->asReq['field'], $this->asReq['value']),
'signup' => $this->oDaydream->signup($this->asReq['name'], $this->asReq['email'], $this->asReq['password'], $this->asReq['t']),
'login' => $this->oDaydream->login($this->asReq['email'], $this->asReq['password'], $this->asReq['t'], $this->asReq['remember']),
'logout' => $this->oDaydream->logout(),
'account' => $this->oDaydream->updateAccount($this->asReq['field'], $this->asReq['value']),
/* Reading the book */
'book' => $oJournal->getBook(),
@@ -102,7 +102,7 @@ class Controller extends PhpObject {
'close_entry' => $oJournal->closeEntry($this->asReq['id'], $this->asReq['content'], $this->asReq['has_content']),
'delete_entry' => $oJournal->deleteEntry($this->asReq['id']),
default => MyThoughts::getJsonResult(false, MyThoughts::NOT_FOUND)
default => Daydream::getJsonResult(false, Daydream::NOT_FOUND)
};
}
+3 -3
View File
@@ -1,6 +1,6 @@
<?php
namespace Franzz\MyThoughts;
namespace Franzz\Daydream;
use Franzz\Objects\Db;
use Franzz\Objects\Main;
@@ -16,8 +16,8 @@ use Settings;
* page stamped with the local time of the moment it was written - and the
* client formats from a UNIX timestamp, never from a preformatted string.
*/
class MyThoughts extends Main {
public const PROJECT_NAME = 'MyThoughts';
class Daydream extends Main {
public const PROJECT_NAME = 'Daydream';
public const DEFAULT_LANG = 'en';
/**
+28 -28
View File
@@ -1,6 +1,6 @@
<?php
namespace Franzz\MyThoughts;
namespace Franzz\Daydream;
use Franzz\Objects\Db;
use Franzz\Objects\PhpObject;
@@ -47,13 +47,13 @@ class Journal extends PhpObject {
* the calendar. Bookmarks stay cheap - id and timestamp only, no content.
*/
public function getBook(): string {
if(!$this->oUser->isLoggedIn()) return MyThoughts::getJsonResult(false, MyThoughts::UNAUTHORIZED);
if(!$this->oUser->isLoggedIn()) return Daydream::getJsonResult(false, Daydream::UNAUTHORIZED);
$this->sealStaleEntries();
$asEntries = $this->getEntryWindow();
return MyThoughts::getJsonResult(true, '', [
return Daydream::getJsonResult(true, '', [
'entries' => $asEntries,
'bookmarks' => $this->getBookmarks(),
'has_older' => $this->hasOlderThan($asEntries[0]['id'] ?? 0),
@@ -62,7 +62,7 @@ class Journal extends PhpObject {
}
public function getEntries(string $sDirection, int $iCursorId): string {
if(!$this->oUser->isLoggedIn()) return MyThoughts::getJsonResult(false, MyThoughts::UNAUTHORIZED);
if(!$this->oUser->isLoggedIn()) return Daydream::getJsonResult(false, Daydream::UNAUTHORIZED);
$asEntries = match($sDirection) {
'before' => $this->getEntryWindow($iCursorId, 'before'),
@@ -71,9 +71,9 @@ class Journal extends PhpObject {
default => null
};
if($asEntries === null) return MyThoughts::getJsonResult(false, MyThoughts::NOT_FOUND);
if($asEntries === null) return Daydream::getJsonResult(false, Daydream::NOT_FOUND);
return MyThoughts::getJsonResult(true, '', [
return Daydream::getJsonResult(true, '', [
'entries' => $asEntries,
'has_older' => $this->hasOlderThan($asEntries[0]['id'] ?? 0),
'has_newer' => $this->hasNewerThan(end($asEntries)['id'] ?? 0)
@@ -86,18 +86,18 @@ class Journal extends PhpObject {
* everything after it is blank.
*/
public function getEntryIdAtDate(string $sDate): string {
if(!$this->oUser->isLoggedIn()) return MyThoughts::getJsonResult(false, MyThoughts::UNAUTHORIZED);
if(!$this->oUser->isLoggedIn()) return Daydream::getJsonResult(false, Daydream::UNAUTHORIZED);
$oDate = \DateTime::createFromFormat('Y-m-d', $sDate);
if(!$oDate) return MyThoughts::getJsonResult(false, MyThoughts::NOT_FOUND);
if(!$oDate) return Daydream::getJsonResult(false, Daydream::NOT_FOUND);
$sDate = $oDate->format('Y-m-d');
$sMidnight = $sDate.' 00:00:00';
$iEntryId = $this->selectFirstId(['started_on' => $sMidnight], ['started_on' => ' >= '], 'ASC');
if(!$iEntryId) $iEntryId = $this->selectFirstId(['started_on' => $sMidnight], ['started_on' => ' < '], 'DESC');
if(!$iEntryId) return MyThoughts::getJsonResult(false, 'book.no_entry_yet');
if(!$iEntryId) return Daydream::getJsonResult(false, 'book.no_entry_yet');
return MyThoughts::getJsonResult(true, '', ['id' => (int) $iEntryId]);
return Daydream::getJsonResult(true, '', ['id' => (int) $iEntryId]);
}
/* Writing */
@@ -107,7 +107,7 @@ class Journal extends PhpObject {
* open from a reload a minute ago, or a fresh one stamped with now.
*/
public function openEntry(): string {
if(!$this->oUser->isLoggedIn()) return MyThoughts::getJsonResult(false, MyThoughts::UNAUTHORIZED);
if(!$this->oUser->isLoggedIn()) return Daydream::getJsonResult(false, Daydream::UNAUTHORIZED);
$this->sealStaleEntries();
@@ -119,27 +119,27 @@ class Journal extends PhpObject {
'content' => '',
'status' => self::STATUS_OPEN,
'started_on' => date(Db::TIMESTAMP_FORMAT),
'closed_on' => MyThoughts::ZERO_TIMESTAMP,
'closed_on' => Daydream::ZERO_TIMESTAMP,
'timezone' => date_default_timezone_get()
]);
if($iEntryId <= 0) return MyThoughts::getJsonResult(false, 'error.commit_db');
if($iEntryId <= 0) return Daydream::getJsonResult(false, 'error.commit_db');
}
return MyThoughts::getJsonResult(true, '', ['entry' => $this->getEntryById($iEntryId)]);
return Daydream::getJsonResult(true, '', ['entry' => $this->getEntryById($iEntryId)]);
}
public function saveEntry(int $iEntryId, string $sContent): string {
if(!$this->oUser->isLoggedIn()) return MyThoughts::getJsonResult(false, MyThoughts::UNAUTHORIZED);
if(!$this->ownsEntry($iEntryId)) return MyThoughts::getJsonResult(false, MyThoughts::NOT_FOUND);
if(!$this->oUser->isLoggedIn()) return Daydream::getJsonResult(false, Daydream::UNAUTHORIZED);
if(!$this->ownsEntry($iEntryId)) return Daydream::getJsonResult(false, Daydream::NOT_FOUND);
$sContent = self::normaliseContent($sContent);
if($this->oDb->updateRow(self::ENTRY_TABLE, $iEntryId, ['content' => $sContent]) === false) {
return MyThoughts::getJsonResult(false, 'error.commit_db');
return Daydream::getJsonResult(false, 'error.commit_db');
}
return MyThoughts::getJsonResult(true, '', ['id' => $iEntryId, 'saved_at' => time()]);
return Daydream::getJsonResult(true, '', ['id' => $iEntryId, 'saved_at' => time()]);
}
/**
@@ -147,11 +147,11 @@ class Journal extends PhpObject {
* nobody actually wrote in is dropped rather than left as a blank page.
*/
public function closeEntry(int $iEntryId, string $sContent = '', bool $bHasContent = false): string {
if(!$this->oUser->isLoggedIn()) return MyThoughts::getJsonResult(false, MyThoughts::UNAUTHORIZED);
if(!$this->ownsEntry($iEntryId)) return MyThoughts::getJsonResult(false, MyThoughts::NOT_FOUND);
if(!$this->oUser->isLoggedIn()) return Daydream::getJsonResult(false, Daydream::UNAUTHORIZED);
if(!$this->ownsEntry($iEntryId)) return Daydream::getJsonResult(false, Daydream::NOT_FOUND);
$asResult = $this->sealEntry($iEntryId, $bHasContent ? $sContent : null);
return MyThoughts::getJsonResult($asResult['result'], $asResult['desc_lang_id'], $asResult['data']);
return Daydream::getJsonResult($asResult['result'], $asResult['desc_lang_id'], $asResult['data']);
}
/**
@@ -169,23 +169,23 @@ class Journal extends PhpObject {
if(trim($sStored) === '') {
$this->oDb->deleteRow(self::ENTRY_TABLE, $iEntryId);
return MyThoughts::getResult(true, '', ['id' => $iEntryId, 'discarded' => true]);
return Daydream::getResult(true, '', ['id' => $iEntryId, 'discarded' => true]);
}
if($this->oDb->updateRow(self::ENTRY_TABLE, $iEntryId, $asData) === false) {
return MyThoughts::getResult(false, 'error.commit_db');
return Daydream::getResult(false, 'error.commit_db');
}
return MyThoughts::getResult(true, '', ['entry' => $this->getEntryById($iEntryId), 'discarded' => false]);
return Daydream::getResult(true, '', ['entry' => $this->getEntryById($iEntryId), 'discarded' => false]);
}
public function deleteEntry(int $iEntryId): string {
if(!$this->oUser->isLoggedIn()) return MyThoughts::getJsonResult(false, MyThoughts::UNAUTHORIZED);
if(!$this->ownsEntry($iEntryId)) return MyThoughts::getJsonResult(false, MyThoughts::NOT_FOUND);
if(!$this->oUser->isLoggedIn()) return Daydream::getJsonResult(false, Daydream::UNAUTHORIZED);
if(!$this->ownsEntry($iEntryId)) return Daydream::getJsonResult(false, Daydream::NOT_FOUND);
if(!$this->oDb->deleteRow(self::ENTRY_TABLE, $iEntryId)) return MyThoughts::getJsonResult(false, 'error.commit_db');
if(!$this->oDb->deleteRow(self::ENTRY_TABLE, $iEntryId)) return Daydream::getJsonResult(false, 'error.commit_db');
return MyThoughts::getJsonResult(true, 'book.entry_deleted', ['id' => $iEntryId]);
return Daydream::getJsonResult(true, 'book.entry_deleted', ['id' => $iEntryId]);
}
/* Internals */
+21 -21
View File
@@ -1,6 +1,6 @@
<?php
namespace Franzz\MyThoughts;
namespace Franzz\Daydream;
use Franzz\Objects\Db;
use Franzz\Objects\PhpObject;
@@ -26,13 +26,13 @@ class User extends PhpObject {
'email' => '',
'language' => '',
'timezone' => '',
'hand' => MyThoughts::DEFAULT_HAND,
'hand' => Daydream::DEFAULT_HAND,
'clearance' => self::CLEARANCE_USER
];
//Session & Cookie
private const SESSION_ID_USER = 'id_user';
private const COOKIE_TOKEN = 'mythoughts';
private const COOKIE_TOKEN = 'daydream';
private const COOKIE_DURATION = 60 * 60 * 24 * 90; //3 months
private Db $oDb;
@@ -101,14 +101,14 @@ class User extends PhpObject {
$sEmail = mb_strtolower(trim($sEmail));
$sName = mb_substr(trim($sName), 0, self::MAX_NAME_LENGTH);
if($sName === '') return MyThoughts::getResult(false, 'account.name_required');
if(!filter_var($sEmail, FILTER_VALIDATE_EMAIL)) return MyThoughts::getResult(false, 'account.invalid_email');
if(mb_strlen($sPassword) < self::MIN_PASSWORD_LENGTH) return MyThoughts::getResult(false, 'account.password_too_short', [], [self::MIN_PASSWORD_LENGTH]);
if($sName === '') return Daydream::getResult(false, 'account.name_required');
if(!filter_var($sEmail, FILTER_VALIDATE_EMAIL)) return Daydream::getResult(false, 'account.invalid_email');
if(mb_strlen($sPassword) < self::MIN_PASSWORD_LENGTH) return Daydream::getResult(false, 'account.password_too_short', [], [self::MIN_PASSWORD_LENGTH]);
//Taken emails must not be distinguishable from a wrong password, so the
//message stays the same one login gives - no account enumeration here.
if($this->oDb->selectId(self::USER_TABLE, ['email' => $sEmail]) > 0) {
return MyThoughts::getResult(false, 'account.invalid_credentials');
return Daydream::getResult(false, 'account.invalid_credentials');
}
$iUserId = $this->oDb->insertRow(self::USER_TABLE, [
@@ -117,14 +117,14 @@ class User extends PhpObject {
'password' => password_hash($sPassword, PASSWORD_DEFAULT),
'language' => $sLang,
'timezone' => $sTimezone,
'hand' => MyThoughts::DEFAULT_HAND,
'hand' => Daydream::DEFAULT_HAND,
'clearance' => self::CLEARANCE_USER
]);
if($iUserId <= 0) return MyThoughts::getResult(false, 'error.commit_db');
if($iUserId <= 0) return Daydream::getResult(false, 'error.commit_db');
$this->openSessionFor($iUserId, true);
return MyThoughts::getResult(true, 'account.welcome', ['user' => $this->getUserInfo()]);
return Daydream::getResult(true, 'account.welcome', ['user' => $this->getUserInfo()]);
}
public function login(string $sEmail, string $sPassword, string $sTimezone, bool $bRemember): array {
@@ -142,14 +142,14 @@ class User extends PhpObject {
$sHash = $asDbUser['password'] ?? '';
$bValid = ($sHash !== '') ? password_verify($sPassword, $sHash) : password_verify($sPassword, '$2y$10$'.str_repeat('.', 53));
if($iUserId <= 0 || !$bValid) return MyThoughts::getResult(false, 'account.invalid_credentials');
if($iUserId <= 0 || !$bValid) return Daydream::getResult(false, 'account.invalid_credentials');
if($sTimezone !== '' && $sTimezone !== ($asDbUser['timezone'] ?? '')) {
$this->oDb->updateRow(self::USER_TABLE, $iUserId, ['timezone' => $sTimezone]);
}
$this->openSessionFor($iUserId, $bRemember);
return MyThoughts::getResult(true, 'account.logged_in', ['user' => $this->getUserInfo()]);
return Daydream::getResult(true, 'account.logged_in', ['user' => $this->getUserInfo()]);
}
public function logout(): array {
@@ -159,24 +159,24 @@ class User extends PhpObject {
if(session_status() === PHP_SESSION_ACTIVE) session_regenerate_id(true);
$this->setUserId(0);
return MyThoughts::getResult(true, 'account.logged_out');
return Daydream::getResult(true, 'account.logged_out');
}
public function updateSettings(string $sField, string $sValue): array {
if(!$this->isLoggedIn()) return MyThoughts::getResult(false, MyThoughts::UNAUTHORIZED);
if(!in_array($sField, ['name', 'language', 'timezone', 'hand'], true)) return MyThoughts::getResult(false, MyThoughts::NOT_FOUND);
if(!$this->isLoggedIn()) return Daydream::getResult(false, Daydream::UNAUTHORIZED);
if(!in_array($sField, ['name', 'language', 'timezone', 'hand'], true)) return Daydream::getResult(false, Daydream::NOT_FOUND);
$sValue = mb_substr(trim($sValue), 0, self::MAX_NAME_LENGTH);
if($sField === 'name' && $sValue === '') return MyThoughts::getResult(false, 'account.name_required');
if($sField === 'timezone' && !in_array($sValue, \DateTimeZone::listIdentifiers(), true)) return MyThoughts::getResult(false, MyThoughts::NOT_FOUND);
if($sField === 'hand' && !in_array($sValue, MyThoughts::getHandIds(), true)) return MyThoughts::getResult(false, MyThoughts::NOT_FOUND);
if($sField === 'name' && $sValue === '') return Daydream::getResult(false, 'account.name_required');
if($sField === 'timezone' && !in_array($sValue, \DateTimeZone::listIdentifiers(), true)) return Daydream::getResult(false, Daydream::NOT_FOUND);
if($sField === 'hand' && !in_array($sValue, Daydream::getHandIds(), true)) return Daydream::getResult(false, Daydream::NOT_FOUND);
if(!$this->oDb->updateRow(self::USER_TABLE, $this->iUserId, [$sField => $sValue])) {
return MyThoughts::getResult(false, 'error.commit_db');
return Daydream::getResult(false, 'error.commit_db');
}
$this->setUserId($this->iUserId);
return MyThoughts::getResult(true, 'account.saved', ['user' => $this->getUserInfo()]);
return Daydream::getResult(true, 'account.saved', ['user' => $this->getUserInfo()]);
}
/* Session plumbing */
@@ -255,7 +255,7 @@ class User extends PhpObject {
private function clearTokenCookie(): void {
if($this->isLoggedIn()) {
$this->oDb->updateRow(self::USER_TABLE, $this->iUserId, ['token' => '', 'token_exp' => MyThoughts::ZERO_TIMESTAMP]);
$this->oDb->updateRow(self::USER_TABLE, $this->iUserId, ['token' => '', 'token_exp' => Daydream::ZERO_TIMESTAMP]);
}
$this->writeCookie('', time() - 3600);