Move domain items up to lib

- WIP on converting more complex queries
This commit is contained in:
2024-05-31 22:57:24 -04:00
parent f7f5dba795
commit 610ab67475
16 changed files with 189 additions and 167 deletions

View File

@@ -9,7 +9,6 @@ use BitBadger\Documents\StringMapper;
use DateTimeImmutable;
use DateTimeInterface;
use Exception;
use FeedReaderCentral\Domain\Table;
use SQLite3;
/**

View File

@@ -1,17 +0,0 @@
<?php
namespace FeedReaderCentral\Domain;
/**
* A user of Feed Reader Central
*/
class User
{
/** @var int The ID of the user */
public int $id = 0;
/** @var string The e-mail address for the user */
public string $email = '';
/** @var string The password for the user */
public string $password = '';
}

View File

@@ -12,8 +12,6 @@ use BitBadger\Documents\SQLite\Exists;
use BitBadger\Documents\SQLite\Find;
use BitBadger\Documents\SQLite\Patch;
use DateTimeInterface;
use FeedReaderCentral\Domain\Item;
use FeedReaderCentral\Domain\Table;
use SQLite3;
/**

View File

@@ -1,7 +1,13 @@
<?php
namespace FeedReaderCentral\Domain;
namespace FeedReaderCentral;
use FeedReaderCentral\ParsedItem;
use BitBadger\Documents\DocumentException;
use BitBadger\Documents\Field;
use BitBadger\Documents\JsonMapper;
use BitBadger\Documents\Query;
use BitBadger\Documents\SQLite\Configuration;
use BitBadger\Documents\SQLite\Custom;
use BitBadger\Documents\SQLite\Parameters;
/**
* An item from a feed
@@ -78,4 +84,27 @@ class Item
return $it;
}
/**
* Retrieve an item by its ID, ensuring that its owner matches the current user
*
* @param int $id The ID of the item to retrieve
* @return Item|false The item if it exists and is owned by the current user, false if not
* @throws DocumentException If any is encountered
*/
public static function retrieveByIdForUser(int $id): Item|false
{
$idField = Field::EQ(Configuration::idField(), $id, '@id');
$idField->qualifier = Table::ITEM;
$userField = Field::EQ('user_id', $_SESSION[Key::USER_ID], '@user');
$userField->qualifier = Table::FEED;
$fields = [$idField, $userField];
$where = Query::whereByFields($fields);
$item = Table::ITEM;
$feed = Table::FEED;
return Custom::single(
"SELECT $item.data FROM $item INNER JOIN $feed ON $item.data->>'feed_id' = $feed.data->>'id' WHERE $where",
Parameters::addFields($fields, []), new JsonMapper(Item::class));
}
}

View File

@@ -5,8 +5,6 @@ namespace FeedReaderCentral;
use BitBadger\Documents\JsonMapper;
use BitBadger\Documents\Mapper;
use FeedReaderCentral\Domain\Feed;
use FeedReaderCentral\Domain\Item;
use FeedReaderCentral\Domain\Table;
/**
* A combined item and feed (used for lists)

View File

@@ -1,12 +1,9 @@
<?php
namespace FeedReaderCentral;
use BitBadger\Documents\DocumentException;
use BitBadger\Documents\Field;
use BitBadger\Documents\SQLite\Document;
use BitBadger\Documents\SQLite\Find;
use BitBadger\Documents\SQLite\Patch;
use FeedReaderCentral\Domain\Table;
use FeedReaderCentral\Domain\User;
use SQLite3;
/**
@@ -32,39 +29,6 @@ class Security {
/** @var string The password algorithm to use for our passwords */
public const string PW_ALGORITHM = PASSWORD_DEFAULT;
/**
* Find a user by their ID
*
* @param string $email The e-mail address of the user to retrieve
* @param SQLite3 $db The data connection to use to retrieve the user
* @return User|false The user information, or null if the user is not found
*/
public static function findUserByEmail(string $email, SQLite3 $db): User|false {
return Find::firstByField(Table::USER, Field::EQ('email', $email), User::class, $db);
// $query = $db->prepare('SELECT * FROM frc_user WHERE email = :email');
// $query->bindValue(':email', $email);
// $result = $query->execute();
// return $result ? $result->fetchArray(SQLITE3_ASSOC) : false;
}
/**
* Add a user
*
* @param string $email The e-mail address for the user
* @param string $password The user's password
* @param SQLite3 $db The data connection to use to add the user
*/
public static function addUser(string $email, string $password, SQLite3 $db): void {
$user = new User();
$user->email = $email;
$user->password = $password;
Document::insert(Table::USER, $user, $db);
// $query = $db->prepare('INSERT INTO frc_user (email, password) VALUES (:email, :password)');
// $query->bindValue(':email', $email);
// $query->bindValue(':password', password_hash($password, self::PW_ALGORITHM));
// $query->execute();
}
/**
* Verify a user's password
*
@@ -72,15 +36,13 @@ class Security {
* @param string $password The password provided by the user
* @param string|null $returnTo The URL to which the user should be redirected
* @param SQLite3 $db The database connection to use to verify the user's credentials
* @throws DocumentException if any is encountered
*/
private static function verifyPassword(User $user, string $password, ?string $returnTo, SQLite3 $db): void {
private static function verifyPassword(User $user, string $password, ?string $returnTo, SQLite3 $db): void
{
if (password_verify($password, $user->password)) {
if (password_needs_rehash($user->password, self::PW_ALGORITHM)) {
Patch::byId(Table::USER, $user->id, ['password' => password_hash($password, self::PW_ALGORITHM)], $db);
// $rehash = $db->prepare('UPDATE frc_user SET password = :hash WHERE id = :id');
// $rehash->bindValue(':hash', password_hash($password, self::PW_ALGORITHM));
// $rehash->bindValue(':id', $user['id']);
// $rehash->execute();
}
$_SESSION[Key::USER_ID] = $user['id'];
$_SESSION[Key::USER_EMAIL] = $user['email'];
@@ -95,6 +57,7 @@ class Security {
* @param string $password The password provided by the user
* @param string|null $returnTo The URL to which the user should be redirected
* @param SQLite3 $db The database connection to use to verify the user's credentials
* @throws DocumentException If any is encountered
*/
public static function logOnUser(string $email, string $password, ?string $returnTo, SQLite3 $db): void {
if (SECURITY_MODEL == self::SINGLE_USER_WITH_PASSWORD) {
@@ -106,7 +69,7 @@ class Security {
}
$dbEmail = $email;
}
$user = self::findUserByEmail($dbEmail, $db);
$user = User::findByEmail($dbEmail);
if ($user) self::verifyPassword($user, $password, $returnTo, $db);
add_error('Invalid credentials; log on unsuccessful');
}
@@ -117,26 +80,24 @@ class Security {
* @param string $email The e-mail address of the user whose password should be updated
* @param string $password The new password for this user
* @param SQLite3 $db The database connection to use in updating the password
* @throws DocumentException If any is encountered
*/
public static function updatePassword(string $email, string $password, SQLite3 $db): void {
Patch::byField(Table::USER, Field::EQ('email', $email),
Patch::byFields(Table::USER, [Field::EQ('email', $email)],
['password' => password_hash($password, self::PW_ALGORITHM)], $db);
// $query = $db->prepare('UPDATE frc_user SET password = :password WHERE email = :email');
// $query->bindValue(':password', password_hash($password, self::PW_ALGORITHM));
// $query->bindValue(':email', $email);
// $query->execute();
}
/**
* Log on the single user
*
* @param SQLite3 $db The data connection to use to retrieve the user
* @throws DocumentException If any is encountered
*/
private static function logOnSingleUser(SQLite3 $db): void {
$user = self::findUserByEmail(self::SINGLE_USER_EMAIL, $db);
$user = User::findByEmail(self::SINGLE_USER_EMAIL);
if (!$user) {
self::addUser(self::SINGLE_USER_EMAIL, self::SINGLE_USER_PASSWORD, $db);
$user = self::findUserByEmail(self::SINGLE_USER_EMAIL, $db);
User::add(self::SINGLE_USER_EMAIL, self::SINGLE_USER_PASSWORD, $db);
$user = User::findByEmail(self::SINGLE_USER_EMAIL);
}
self::verifyPassword($user, self::SINGLE_USER_PASSWORD, $_GET['returnTo'], $db);
}
@@ -146,6 +107,7 @@ class Security {
*
* @param SQLite3 $db The data connection to use if required
* @param bool $redirectIfAnonymous Whether to redirect the request if there is no user logged on
* @throws DocumentException If any is encountered
*/
public static function verifyUser(SQLite3 $db, bool $redirectIfAnonymous = true): void {
if (key_exists(Key::USER_ID, $_SESSION)) return;

View File

@@ -1,5 +1,5 @@
<?php
namespace FeedReaderCentral\Domain;
namespace FeedReaderCentral;
/**
* Constants to use when accessing tables

52
src/lib/User.php Normal file
View File

@@ -0,0 +1,52 @@
<?php
namespace FeedReaderCentral;
use BitBadger\Documents\DocumentException;
use BitBadger\Documents\Field;
use BitBadger\Documents\SQLite\Document;
use BitBadger\Documents\SQLite\Find;
use SQLite3;
/**
* A user of Feed Reader Central
*/
class User
{
/** @var int The ID of the user */
public int $id = 0;
/** @var string The e-mail address for the user */
public string $email = '';
/** @var string The password for the user */
public string $password = '';
/**
* Find a user by their e=mail address
*
* @param string $email The e-mail address of the user to retrieve
* @return User|false The user information, or null if the user is not found
* @throws DocumentException If any is encountered
*/
public static function findByEmail(string $email): User|false
{
return Find::firstByFields(Table::USER, [Field::EQ('email', $email)], User::class);
}
/**
* Add a user
*
* @param string $email The e-mail address for the user
* @param string $password The user's password
* @param SQLite3 $db The data connection to use to add the user
* @throws DocumentException If any is encountered
*/
public static function add(string $email, string $password, SQLite3 $db): void
{
$user = new User();
$user->email = $email;
$user->password = $password;
Document::insert(Table::USER, $user, $db);
}
}