Documents and Documentation (beta 1) #23
|
@ -5,7 +5,7 @@
|
|||
use BitBadger\Documents\SQLite\Configuration;
|
||||
use FeedReaderCentral\Data;
|
||||
|
||||
const FRC_VERSION = '1.0.0-alpha7';
|
||||
const FRC_VERSION = '1.0.0-beta1';
|
||||
|
||||
/**
|
||||
* Drop .0 or .0.0 from the end of the version to format it for display
|
||||
|
@ -24,15 +24,6 @@ function display_version(): string {
|
|||
}
|
||||
|
||||
require __DIR__ . '/vendor/autoload.php';
|
||||
//spl_autoload_register(function ($class) {
|
||||
// $file = implode(DIRECTORY_SEPARATOR, [__DIR__, 'lib', "$class.php"]);
|
||||
// if (file_exists($file)) {
|
||||
// require $file;
|
||||
// return true;
|
||||
// }
|
||||
// return false;
|
||||
//});
|
||||
|
||||
require 'user-config.php';
|
||||
|
||||
Configuration::useDbFileName(implode(DIRECTORY_SEPARATOR, [__DIR__, 'data', DATABASE_NAME]));
|
||||
|
|
20
src/composer.lock
generated
20
src/composer.lock
generated
|
@ -12,10 +12,16 @@
|
|||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://git.bitbadger.solutions/bit-badger/documents-common",
|
||||
"reference": "30d3ad0621485d0797f2483424a6199ab0021c97"
|
||||
"reference": "4aecbfe3e8030fe7ddc0391ee715d6766cbb9c6e"
|
||||
},
|
||||
"type": "library",
|
||||
"time": "2024-06-01T02:26:15+00:00"
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"BitBadger\\Documents\\": "./",
|
||||
"BitBadger\\Documents\\Query\\": "./Query"
|
||||
}
|
||||
},
|
||||
"time": "2024-06-02T02:11:21+00:00"
|
||||
},
|
||||
{
|
||||
"name": "bit-badger/documents-sqlite",
|
||||
|
@ -23,14 +29,20 @@
|
|||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://git.bitbadger.solutions/bit-badger/documents-sqlite",
|
||||
"reference": "009ea77b7510fd13936ec4927e2390bccd5d5e70"
|
||||
"reference": "ac34dbf481287526b6d044fd7699568e0ee92805"
|
||||
},
|
||||
"require": {
|
||||
"bit-badger/documents-common": "dev-conversion",
|
||||
"ext-sqlite3": "*"
|
||||
},
|
||||
"type": "library",
|
||||
"time": "2024-06-01T02:28:46+00:00"
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"BitBadger\\Documents\\SQLite\\": "./",
|
||||
"BitBadger\\Documents\\SQLite\\Query\\": "./Query"
|
||||
}
|
||||
},
|
||||
"time": "2024-06-02T02:18:12+00:00"
|
||||
}
|
||||
],
|
||||
"packages-dev": [],
|
||||
|
|
|
@ -14,18 +14,8 @@ use SQLite3;
|
|||
/**
|
||||
* A centralized place for data access for the application
|
||||
*/
|
||||
class Data {
|
||||
|
||||
/**
|
||||
* Obtain a new connection to the database
|
||||
* @return SQLite3 A new connection to the database
|
||||
*/
|
||||
public static function getConnection(): SQLite3 {
|
||||
$db = new SQLite3(implode(DIRECTORY_SEPARATOR, [__DIR__, '..', 'data', DATABASE_NAME]));
|
||||
$db->exec('PRAGMA foreign_keys = ON;');
|
||||
return $db;
|
||||
}
|
||||
|
||||
class Data
|
||||
{
|
||||
/**
|
||||
* Create the search index and synchronization triggers for the item table
|
||||
*
|
||||
|
@ -71,51 +61,17 @@ class Data {
|
|||
{
|
||||
$tables = Custom::array("SELECT name FROM sqlite_master WHERE type = 'table'", [], new StringMapper('name'));
|
||||
$db = Configuration::dbConn();
|
||||
// $tables = array();
|
||||
// $tableQuery = $db->query("SELECT name FROM sqlite_master WHERE type = 'table'");
|
||||
// while ($table = $tableQuery->fetchArray(SQLITE3_NUM)) $tables[] = $table[0];
|
||||
if (!in_array(Table::USER, $tables)) {
|
||||
Definition::ensureTable(Table::USER, $db);
|
||||
Definition::ensureFieldIndex(Table::USER, 'email', ['email'], $db);
|
||||
// $db->exec(<<<'SQL'
|
||||
// CREATE TABLE frc_user (
|
||||
// id INTEGER NOT NULL PRIMARY KEY,
|
||||
// email TEXT NOT NULL,
|
||||
// password TEXT NOT NULL)
|
||||
// SQL);
|
||||
// $db->exec('CREATE INDEX idx_user_email ON frc_user (email)');
|
||||
}
|
||||
if (!in_array(Table::FEED, $tables)) {
|
||||
Definition::ensureTable(Table::FEED, $db);
|
||||
Definition::ensureFieldIndex(Table::FEED, 'user', ['user_id'], $db);
|
||||
// $db->exec(<<<'SQL'
|
||||
// CREATE TABLE feed (
|
||||
// id INTEGER NOT NULL PRIMARY KEY,
|
||||
// user_id INTEGER NOT NULL,
|
||||
// url TEXT NOT NULL,
|
||||
// title TEXT,
|
||||
// updated_on TEXT,
|
||||
// checked_on TEXT,
|
||||
// FOREIGN KEY (user_id) REFERENCES frc_user (id))
|
||||
// SQL);
|
||||
}
|
||||
if (!in_array(Table::ITEM, $tables)) {
|
||||
Definition::ensureTable(Table::ITEM, $db);
|
||||
Definition::ensureFieldIndex(Table::ITEM, 'feed', ['feed_id', 'item_link'], $db);
|
||||
// $db->exec(<<<'SQL'
|
||||
// CREATE TABLE item (
|
||||
// id INTEGER NOT NULL PRIMARY KEY,
|
||||
// feed_id INTEGER NOT NULL,
|
||||
// title TEXT NOT NULL,
|
||||
// item_guid TEXT NOT NULL,
|
||||
// item_link TEXT NOT NULL,
|
||||
// published_on TEXT NOT NULL,
|
||||
// updated_on TEXT,
|
||||
// content TEXT NOT NULL,
|
||||
// is_read BOOLEAN NOT NULL DEFAULT 0,
|
||||
// is_bookmarked BOOLEAN NOT NULL DEFAULT 0,
|
||||
// FOREIGN KEY (feed_id) REFERENCES feed (id))
|
||||
// SQL);
|
||||
self::createSearchIndex($db);
|
||||
}
|
||||
$db->close();
|
||||
|
@ -127,21 +83,12 @@ class Data {
|
|||
* @param ?string $value The date/time to be parsed and formatted
|
||||
* @return string|null The date/time in `DateTimeInterface::ATOM` format, or `null` if the input cannot be parsed
|
||||
*/
|
||||
public static function formatDate(?string $value): ?string {
|
||||
public static function formatDate(?string $value): ?string
|
||||
{
|
||||
try {
|
||||
return $value ? (new DateTimeImmutable($value))->format(DateTimeInterface::ATOM) : null;
|
||||
} catch (Exception) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the last SQLite error message as a result array
|
||||
*
|
||||
* @param SQLite3 $db The database connection on which the error has occurred
|
||||
* @return string[] ['error' => message] for last SQLite error message
|
||||
*/
|
||||
public static function error(SQLite3 $db): array {
|
||||
return ['error' => 'SQLite error: ' . $db->lastErrorMsg()];
|
||||
}
|
||||
}
|
||||
|
|
|
@ -33,25 +33,19 @@ class Feed
|
|||
/** @var int Purge items in number greater than the specified number of items to keep */
|
||||
public const int PURGE_BY_COUNT = 3;
|
||||
|
||||
// ***** PROPERTIES *****
|
||||
|
||||
/** @var int The ID of the feed */
|
||||
public int $id = 0;
|
||||
|
||||
/** @var int The ID of the user to whom this subscription belongs */
|
||||
public int $user_id = 0;
|
||||
|
||||
/** @var string The URL of the feed */
|
||||
public string $url = '';
|
||||
|
||||
/** @var string|null The title of this feed */
|
||||
public ?string $title = null;
|
||||
|
||||
/** @var string|null The date/time items in this feed were last updated */
|
||||
public ?string $updated_on = null;
|
||||
|
||||
/** @var string|null The date/time this feed was last checked */
|
||||
public ?string $checked_on = null;
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param int $id The ID of the feed
|
||||
* @param int $user_id The ID of the user to whom this subscription belongs
|
||||
* @param string $url The URL of the feed
|
||||
* @param string|null $title The title of this feed
|
||||
* @param string|null $updated_on The date/time items in this feed were last updated
|
||||
* @param string|null $checked_on The date/time this feed was last checked
|
||||
*/
|
||||
public function __construct(public int $id = 0, public int $user_id = 0, public string $url = '',
|
||||
public ?string $title = null, public ?string $updated_on = null,
|
||||
public ?string $checked_on = null) { }
|
||||
|
||||
// ***** STATIC FUNCTIONS *****
|
||||
|
||||
|
|
|
@ -14,35 +14,24 @@ use BitBadger\Documents\SQLite\Parameters;
|
|||
*/
|
||||
class Item
|
||||
{
|
||||
/** @var int The ID of this item in the Feed Reader Central database */
|
||||
public int $id = 0;
|
||||
|
||||
/** @var int The ID of the feed to which this item belongs */
|
||||
public int $feed_id = 0;
|
||||
|
||||
/** @var string The title of this item */
|
||||
public string $title = '';
|
||||
|
||||
/** @var string The Globally Unique ID (GUID) for this item (an attribute in the feed XML) */
|
||||
public string $item_guid = '';
|
||||
|
||||
/** @var string The link to the item on its original site */
|
||||
public string $item_link = '';
|
||||
|
||||
/** @var string The date/time this item was published */
|
||||
public string $published_on = '';
|
||||
|
||||
/** @var string|null The date/time this item was last updated */
|
||||
public ?string $updated_on = null;
|
||||
|
||||
/** @var string The content for this item */
|
||||
public string $content = '';
|
||||
|
||||
/** @var int 1 if the item has been read, 0 if not */
|
||||
public int $is_read = 0;
|
||||
|
||||
/** @var int 1 if the item is bookmarked, 0 if not */
|
||||
public int $is_bookmarked = 0;
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param int $id The ID of this item in the Feed Reader Central database
|
||||
* @param int $feed_id The ID of the feed to which this item belongs
|
||||
* @param string $title The title of this item
|
||||
* @param string $item_guid The Globally Unique ID (GUID) for this item (an attribute in the feed XML)
|
||||
* @param string $item_link The link to the item on its original site
|
||||
* @param string $published_on The date/time this item was published
|
||||
* @param string|null $updated_on The date/time this item was last updated
|
||||
* @param string $content The content for this item
|
||||
* @param int $is_read 1 if the item has been read, 0 if not
|
||||
* @param int $is_bookmarked 1 if the item is bookmarked, 0 if not
|
||||
*/
|
||||
public function __construct(public int $id = 0, public int $feed_id = 0, public string $title = '',
|
||||
public string $item_guid = '', public string $item_link = '',
|
||||
public string $published_on = '', public ?string $updated_on = null,
|
||||
public string $content = '', public int $is_read = 0, public int $is_bookmarked = 0) { }
|
||||
|
||||
/**
|
||||
* Has the item been read?
|
||||
|
@ -73,16 +62,14 @@ class Item
|
|||
*/
|
||||
public static function fromFeedItem(int $feedId, ParsedItem $item): static
|
||||
{
|
||||
$it = new static();
|
||||
$it->feed_id = $feedId;
|
||||
$it->item_guid = $item->guid;
|
||||
$it->item_link = $item->link;
|
||||
$it->title = $item->title;
|
||||
$it->published_on = $item->publishedOn;
|
||||
$it->updated_on = $item->updatedOn;
|
||||
$it->content = $item->content;
|
||||
|
||||
return $it;
|
||||
return new static(
|
||||
feed_id: $feedId,
|
||||
title: $item->title,
|
||||
item_guid: $item->guid,
|
||||
item_link: $item->link,
|
||||
published_on: $item->publishedOn,
|
||||
updated_on: $item->updatedOn,
|
||||
content: $item->content);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -48,7 +48,7 @@ class ItemList {
|
|||
{
|
||||
$result = $query->execute();
|
||||
if (!$result) {
|
||||
$this->error = Data::error($db)['error'];
|
||||
$this->error = 'SQLite error: ' . $db->lastErrorMsg();
|
||||
} else {
|
||||
$this->items = $result;
|
||||
}
|
||||
|
|
|
@ -4,13 +4,12 @@ namespace FeedReaderCentral;
|
|||
use BitBadger\Documents\DocumentException;
|
||||
use BitBadger\Documents\Field;
|
||||
use BitBadger\Documents\SQLite\Patch;
|
||||
use SQLite3;
|
||||
|
||||
/**
|
||||
* Security functions
|
||||
*/
|
||||
class Security {
|
||||
|
||||
class Security
|
||||
{
|
||||
/** @var int Run as a single user requiring no password */
|
||||
public const int SINGLE_USER = 0;
|
||||
|
||||
|
@ -35,17 +34,16 @@ class Security {
|
|||
* @param User $user The user information retrieved from the database
|
||||
* @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): 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);
|
||||
Patch::byId(Table::USER, $user->id, ['password' => password_hash($password, self::PW_ALGORITHM)]);
|
||||
}
|
||||
$_SESSION[Key::USER_ID] = $user['id'];
|
||||
$_SESSION[Key::USER_EMAIL] = $user['email'];
|
||||
$_SESSION[Key::USER_ID] = $user->id;
|
||||
$_SESSION[Key::USER_EMAIL] = $user->email;
|
||||
frc_redirect($returnTo ?? '/');
|
||||
}
|
||||
}
|
||||
|
@ -56,10 +54,9 @@ class Security {
|
|||
* @param string $email The e-mail address for the user (cannot be the single-user mode user)
|
||||
* @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 {
|
||||
public static function logOnUser(string $email, string $password, ?string $returnTo): void {
|
||||
if (SECURITY_MODEL == self::SINGLE_USER_WITH_PASSWORD) {
|
||||
$dbEmail = self::SINGLE_USER_EMAIL;
|
||||
} else {
|
||||
|
@ -70,7 +67,7 @@ class Security {
|
|||
$dbEmail = $email;
|
||||
}
|
||||
$user = User::findByEmail($dbEmail);
|
||||
if ($user) self::verifyPassword($user, $password, $returnTo, $db);
|
||||
if ($user) self::verifyPassword($user, $password, $returnTo);
|
||||
add_error('Invalid credentials; log on unsuccessful');
|
||||
}
|
||||
|
||||
|
@ -79,40 +76,37 @@ 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 {
|
||||
public static function updatePassword(string $email, string $password): void {
|
||||
Patch::byFields(Table::USER, [Field::EQ('email', $email)],
|
||||
['password' => password_hash($password, self::PW_ALGORITHM)], $db);
|
||||
['password' => password_hash($password, self::PW_ALGORITHM)]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 {
|
||||
private static function logOnSingleUser(): void {
|
||||
$user = User::findByEmail(self::SINGLE_USER_EMAIL);
|
||||
if (!$user) {
|
||||
User::add(self::SINGLE_USER_EMAIL, self::SINGLE_USER_PASSWORD, $db);
|
||||
User::add(self::SINGLE_USER_EMAIL, self::SINGLE_USER_PASSWORD);
|
||||
$user = User::findByEmail(self::SINGLE_USER_EMAIL);
|
||||
}
|
||||
self::verifyPassword($user, self::SINGLE_USER_PASSWORD, $_GET['returnTo'], $db);
|
||||
self::verifyPassword($user, self::SINGLE_USER_PASSWORD, $_GET['returnTo']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify that user is logged on
|
||||
*
|
||||
* @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 {
|
||||
public static function verifyUser(bool $redirectIfAnonymous = true): void {
|
||||
if (key_exists(Key::USER_ID, $_SESSION)) return;
|
||||
|
||||
if (SECURITY_MODEL == self::SINGLE_USER) self::logOnSingleUser($db);
|
||||
if (SECURITY_MODEL == self::SINGLE_USER) self::logOnSingleUser();
|
||||
|
||||
if (SECURITY_MODEL != self::SINGLE_USER_WITH_PASSWORD && SECURITY_MODEL != self::MULTI_USER) {
|
||||
die('Unrecognized security model (' . SECURITY_MODEL . ')');
|
||||
|
|
|
@ -3,8 +3,12 @@ namespace FeedReaderCentral;
|
|||
|
||||
use BitBadger\Documents\DocumentException;
|
||||
use BitBadger\Documents\Field;
|
||||
use BitBadger\Documents\Query;
|
||||
use BitBadger\Documents\SQLite\Custom;
|
||||
use BitBadger\Documents\SQLite\Document;
|
||||
use BitBadger\Documents\SQLite\Find;
|
||||
use BitBadger\Documents\SQLite\Parameters;
|
||||
use BitBadger\Documents\SQLite\Results;
|
||||
use SQLite3;
|
||||
|
||||
/**
|
||||
|
@ -12,14 +16,14 @@ use SQLite3;
|
|||
*/
|
||||
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 = '';
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param int $id The ID of the user
|
||||
* @param string $email The e-mail address for the user
|
||||
* @param string $password The password for the user
|
||||
*/
|
||||
public function __construct(public int $id = 0, public string $email = '', public string $password = '') { }
|
||||
|
||||
/**
|
||||
* Find a user by their e=mail address
|
||||
|
@ -38,15 +42,34 @@ class 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
|
||||
public static function add(string $email, string $password): void
|
||||
{
|
||||
$user = new User();
|
||||
$user->email = $email;
|
||||
$user->password = $password;
|
||||
Document::insert(Table::USER, $user, $db);
|
||||
Document::insert(Table::USER, new User(email: $email, password: $password));
|
||||
}
|
||||
|
||||
/**
|
||||
* Does this user have any bookmarked items?
|
||||
* @return bool True if the user has any bookmarked items, false if not
|
||||
* @throws DocumentException If any is encountered
|
||||
*/
|
||||
public static function hasBookmarks(): bool
|
||||
{
|
||||
$userField = Field::EQ('user_id', $_SESSION[Key::USER_ID], '@user');
|
||||
$userField->qualifier = Table::FEED;
|
||||
$bookField = Field::EQ('is_bookmarked', 1, '@book');
|
||||
$bookField->qualifier = Table::ITEM;
|
||||
$fields = [$userField, $bookField];
|
||||
|
||||
$item = Table::ITEM;
|
||||
$feed = Table::FEED;
|
||||
$where = Query::whereByFields($fields);
|
||||
return Custom::scalar(<<<SQL
|
||||
SELECT EXISTS (
|
||||
SELECT 1
|
||||
FROM $item INNER JOIN $feed ON $item.data->>'feed_id' = $feed.data->>'id'
|
||||
WHERE $where)
|
||||
SQL, Parameters::addFields($fields, []), Results::toExists(...));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,9 +7,9 @@
|
|||
*/
|
||||
|
||||
use BitBadger\Documents\DocumentException;
|
||||
use BitBadger\Documents\SQLite\Configuration;
|
||||
use BitBadger\Documents\SQLite\Find;
|
||||
use BitBadger\Documents\SQLite\Patch;
|
||||
use FeedReaderCentral\Data;
|
||||
use FeedReaderCentral\Item;
|
||||
use FeedReaderCentral\Key;
|
||||
use FeedReaderCentral\Security;
|
||||
|
@ -17,12 +17,12 @@ use FeedReaderCentral\Table;
|
|||
|
||||
include '../start.php';
|
||||
|
||||
$db = Data::getConnection();
|
||||
Security::verifyUser($db);
|
||||
Security::verifyUser();
|
||||
|
||||
$id = $_GET['id'];
|
||||
|
||||
// TODO: adapt query once "by fields" is available
|
||||
$db = Configuration::dbConn();
|
||||
$existsQuery = $db->prepare(
|
||||
'SELECT item.id FROM item INNER JOIN feed ON feed.id = item.feed_id WHERE item.id = :id AND feed.user_id = :user');
|
||||
$existsQuery->bindValue(':id', $id);
|
||||
|
|
|
@ -1,12 +1,8 @@
|
|||
<?php
|
||||
|
||||
use FeedReaderCentral\Data;
|
||||
use FeedReaderCentral\Security;
|
||||
|
||||
include '../../start.php';
|
||||
|
||||
$db = Data::getConnection();
|
||||
Security::verifyUser($db, redirectIfAnonymous: false);
|
||||
FeedReaderCentral\Security::verifyUser(redirectIfAnonymous: false);
|
||||
|
||||
page_head('Feeds | Documentation'); ?>
|
||||
<h1>Feeds</h1>
|
||||
|
@ -75,4 +71,3 @@ php-cli util/refresh.php all</pre>
|
|||
add <code>nice -n 1</code> (with a trailing space) before the path to the script.
|
||||
</article><?php
|
||||
page_foot();
|
||||
$db->close();
|
||||
|
|
|
@ -1,12 +1,8 @@
|
|||
<?php
|
||||
|
||||
use FeedReaderCentral\Data;
|
||||
use FeedReaderCentral\Security;
|
||||
|
||||
include '../../start.php';
|
||||
|
||||
$db = Data::getConnection();
|
||||
Security::verifyUser($db, redirectIfAnonymous: false);
|
||||
FeedReaderCentral\Security::verifyUser(redirectIfAnonymous: false);
|
||||
|
||||
page_head('Documentation'); ?>
|
||||
<h1>Documentation Home</h1>
|
||||
|
@ -35,4 +31,3 @@ page_head('Documentation'); ?>
|
|||
that can be performed via its command line interface.
|
||||
</article><?php
|
||||
page_foot();
|
||||
$db->close();
|
||||
|
|
|
@ -1,12 +1,8 @@
|
|||
<?php
|
||||
|
||||
use FeedReaderCentral\Data;
|
||||
use FeedReaderCentral\Security;
|
||||
|
||||
include '../../start.php';
|
||||
|
||||
$db = Data::getConnection();
|
||||
Security::verifyUser($db, redirectIfAnonymous: false);
|
||||
FeedReaderCentral\Security::verifyUser(redirectIfAnonymous: false);
|
||||
|
||||
page_head('Items | Documentation'); ?>
|
||||
<h1>Items</h1>
|
||||
|
@ -70,4 +66,3 @@ page_head('Items | Documentation'); ?>
|
|||
others; if the items seem to move around in the list after a refresh, this is likely the cause.
|
||||
</article><?php
|
||||
page_foot();
|
||||
$db->close();
|
||||
|
|
|
@ -1,12 +1,8 @@
|
|||
<?php
|
||||
|
||||
use FeedReaderCentral\Data;
|
||||
use FeedReaderCentral\Security;
|
||||
|
||||
include '../../start.php';
|
||||
|
||||
$db = Data::getConnection();
|
||||
Security::verifyUser($db, redirectIfAnonymous: false);
|
||||
FeedReaderCentral\Security::verifyUser(redirectIfAnonymous: false);
|
||||
|
||||
page_head('Security Modes | Documentation'); ?>
|
||||
<h1>Configuring Security Modes</h1>
|
||||
|
@ -63,4 +59,3 @@ page_head('Security Modes | Documentation'); ?>
|
|||
<p><code>php-cli util/user.php reset-single-password</code>
|
||||
</article><?php
|
||||
page_foot();
|
||||
$db->close();
|
||||
|
|
|
@ -1,12 +1,8 @@
|
|||
<?php
|
||||
|
||||
use FeedReaderCentral\Data;
|
||||
use FeedReaderCentral\Security;
|
||||
|
||||
include '../../start.php';
|
||||
|
||||
$db = Data::getConnection();
|
||||
Security::verifyUser($db, redirectIfAnonymous: false);
|
||||
FeedReaderCentral\Security::verifyUser(redirectIfAnonymous: false);
|
||||
|
||||
page_head('About the CLI | Documentation'); ?>
|
||||
<h1>About the CLI</h1>
|
||||
|
@ -25,4 +21,3 @@ page_head('About the CLI | Documentation'); ?>
|
|||
<p><code>php-cli util/some-process.php command option1 option2</code>
|
||||
</article><?php
|
||||
page_foot();
|
||||
$db->close();
|
||||
|
|
|
@ -7,24 +7,23 @@
|
|||
|
||||
use BitBadger\Documents\DocumentException;
|
||||
use BitBadger\Documents\Field;
|
||||
use BitBadger\Documents\SQLite\Configuration;
|
||||
use BitBadger\Documents\SQLite\Delete;
|
||||
use FeedReaderCentral\Data;
|
||||
use FeedReaderCentral\Feed;
|
||||
use FeedReaderCentral\Security;
|
||||
use FeedReaderCentral\Table;
|
||||
|
||||
include '../../start.php';
|
||||
|
||||
$db = Data::getConnection();
|
||||
Security::verifyUser($db);
|
||||
Security::verifyUser();
|
||||
|
||||
$feedId = $_GET['id'] ?? '';
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] == 'DELETE') {
|
||||
try {
|
||||
if (!($feed = Feed::retrieveById($feedId))) not_found();
|
||||
Delete::byFields(Table::ITEM, [Field::EQ('feed_id', $feed->id)], $db);
|
||||
Delete::byId(Table::FEED, $feed->id, $db);
|
||||
Delete::byFields(Table::ITEM, [Field::EQ('feed_id', $feed->id)]);
|
||||
Delete::byId(Table::FEED, $feed->id);
|
||||
add_info('Feed “' . htmlentities($feed->title) . '” deleted successfully');
|
||||
$db->close();
|
||||
frc_redirect('/feeds');
|
||||
|
@ -33,6 +32,7 @@ if ($_SERVER['REQUEST_METHOD'] == 'DELETE') {
|
|||
}
|
||||
}
|
||||
|
||||
$db = Configuration::dbConn();
|
||||
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
|
||||
try {
|
||||
$isNew = $_POST['id'] == 'new';
|
||||
|
|
|
@ -5,18 +5,18 @@
|
|||
* Lists items in a given feed (all, unread, or bookmarked)
|
||||
*/
|
||||
|
||||
use FeedReaderCentral\Data;
|
||||
use BitBadger\Documents\SQLite\Configuration;
|
||||
use FeedReaderCentral\Feed;
|
||||
use FeedReaderCentral\ItemList;
|
||||
use FeedReaderCentral\Security;
|
||||
|
||||
include '../../start.php';
|
||||
|
||||
$db = Data::getConnection();
|
||||
Security::verifyUser($db);
|
||||
Security::verifyUser();
|
||||
|
||||
if (!($feed = Feed::retrieveById($_GET['id']))) not_found();
|
||||
|
||||
$db = Configuration::dbConn();
|
||||
$list = match (true) {
|
||||
key_exists('unread', $_GET) => ItemList::unreadForFeed($feed->id, $db),
|
||||
key_exists('bookmarked', $_GET) => ItemList::bookmarkedForFeed($feed->id, $db),
|
||||
|
|
|
@ -10,7 +10,6 @@ use BitBadger\Documents\Field;
|
|||
use BitBadger\Documents\JsonMapper;
|
||||
use BitBadger\Documents\Query;
|
||||
use BitBadger\Documents\SQLite\Custom;
|
||||
use FeedReaderCentral\Data;
|
||||
use FeedReaderCentral\Feed;
|
||||
use FeedReaderCentral\Key;
|
||||
use FeedReaderCentral\Security;
|
||||
|
@ -18,8 +17,7 @@ use FeedReaderCentral\Table;
|
|||
|
||||
include '../start.php';
|
||||
|
||||
$db = Data::getConnection();
|
||||
Security::verifyUser($db);
|
||||
Security::verifyUser();
|
||||
|
||||
// TODO: adapt query when document list is done
|
||||
$field = Field::EQ('user_id', $_SESSION[Key::USER_ID], '@user');
|
||||
|
@ -52,4 +50,3 @@ page_head('Your Feeds'); ?>
|
|||
}); ?>
|
||||
</article><?php
|
||||
page_foot();
|
||||
$db->close();
|
||||
|
|
|
@ -5,16 +5,16 @@
|
|||
* Displays a list of unread or bookmarked items for the current user
|
||||
*/
|
||||
|
||||
use FeedReaderCentral\Data;
|
||||
use BitBadger\Documents\SQLite\Configuration;
|
||||
use FeedReaderCentral\Feed;
|
||||
use FeedReaderCentral\ItemList;
|
||||
use FeedReaderCentral\Security;
|
||||
|
||||
include '../start.php';
|
||||
|
||||
$db = Data::getConnection();
|
||||
Security::verifyUser($db);
|
||||
Security::verifyUser();
|
||||
|
||||
$db = Configuration::dbConn();
|
||||
if (key_exists('refresh', $_GET)) {
|
||||
$refreshResult = Feed::refreshAll($db);
|
||||
if (key_exists('ok', $refreshResult)) {
|
||||
|
|
|
@ -7,9 +7,9 @@
|
|||
*/
|
||||
|
||||
use BitBadger\Documents\DocumentException;
|
||||
use BitBadger\Documents\SQLite\Configuration;
|
||||
use BitBadger\Documents\SQLite\Delete;
|
||||
use BitBadger\Documents\SQLite\Patch;
|
||||
use FeedReaderCentral\Data;
|
||||
use FeedReaderCentral\Item;
|
||||
use FeedReaderCentral\Key;
|
||||
use FeedReaderCentral\Security;
|
||||
|
@ -17,16 +17,14 @@ use FeedReaderCentral\Table;
|
|||
|
||||
include '../start.php';
|
||||
|
||||
$db = Data::getConnection();
|
||||
Security::verifyUser($db);
|
||||
Security::verifyUser();
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
|
||||
try {
|
||||
// "Keep as New" button sends a POST request to reset the is_read flag before going back to the item list
|
||||
if (Item::retrieveByIdForUser($_POST['id'])) {
|
||||
Patch::byId(Table::ITEM, $_POST['id'], ['is_read' => 0], $db);
|
||||
Patch::byId(Table::ITEM, $_POST['id'], ['is_read' => 0]);
|
||||
}
|
||||
$db->close();
|
||||
frc_redirect($_POST['from']);
|
||||
} catch (DocumentException $ex) {
|
||||
add_error("$ex");
|
||||
|
@ -38,16 +36,16 @@ $from = $_GET['from'] ?? '/';
|
|||
if ($_SERVER['REQUEST_METHOD'] == 'DELETE') {
|
||||
try {
|
||||
if (Item::retrieveByIdForUser($_GET['id'])) {
|
||||
Delete::byId(Table::ITEM, $_GET['id'], $db);
|
||||
Delete::byId(Table::ITEM, $_GET['id']);
|
||||
}
|
||||
} catch (DocumentException $ex) {
|
||||
add_error("$ex");
|
||||
}
|
||||
$db->close();
|
||||
frc_redirect($from);
|
||||
}
|
||||
|
||||
// TODO: convert this query
|
||||
$db = Configuration::dbConn();
|
||||
$query = $db->prepare(<<<'SQL'
|
||||
SELECT item.title AS item_title, item.item_link, item.published_on, item.updated_on, item.content,
|
||||
feed.title AS feed_title
|
||||
|
|
|
@ -6,18 +6,18 @@
|
|||
* Search for items across all feeds
|
||||
*/
|
||||
|
||||
use FeedReaderCentral\Data;
|
||||
use BitBadger\Documents\SQLite\Configuration;
|
||||
use FeedReaderCentral\ItemList;
|
||||
use FeedReaderCentral\Security;
|
||||
|
||||
include '../start.php';
|
||||
|
||||
$db = Data::getConnection();
|
||||
Security::verifyUser($db);
|
||||
Security::verifyUser();
|
||||
|
||||
$search = $_GET['search'] ?? '';
|
||||
$items = $_GET['items'] ?? 'all';
|
||||
|
||||
$db = Configuration::dbConn();
|
||||
if ($search != '') {
|
||||
$list = ItemList::matchingSearch($search, $items == 'bookmarked', $db);
|
||||
}
|
||||
|
|
|
@ -1,18 +1,16 @@
|
|||
<?php
|
||||
include '../../start.php';
|
||||
|
||||
use FeedReaderCentral\Data;
|
||||
use FeedReaderCentral\Key;
|
||||
use FeedReaderCentral\Security;
|
||||
|
||||
$db = Data::getConnection();
|
||||
Security::verifyUser($db, redirectIfAnonymous: false);
|
||||
Security::verifyUser(redirectIfAnonymous: false);
|
||||
|
||||
// Users already logged on have no need of this page
|
||||
if (key_exists(Key::USER_ID, $_SESSION)) frc_redirect('/');
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
|
||||
Security::logOnUser($_POST['email'] ?? '', $_POST['password'], $_POST['returnTo'] ?? null, $db);
|
||||
Security::logOnUser($_POST['email'] ?? '', $_POST['password'], $_POST['returnTo'] ?? null);
|
||||
// If we're still here, something didn't work; preserve the returnTo parameter
|
||||
$_GET['returnTo'] = $_POST['returnTo'];
|
||||
}
|
||||
|
@ -41,4 +39,3 @@ page_head('Log On'); ?>
|
|||
</form>
|
||||
</article><?php
|
||||
page_foot();
|
||||
$db->close();
|
||||
|
|
|
@ -1,8 +1,15 @@
|
|||
<?php
|
||||
|
||||
use BitBadger\Documents\Field;
|
||||
use BitBadger\Documents\Query;
|
||||
use BitBadger\Documents\SQLite\Custom;
|
||||
use BitBadger\Documents\SQLite\Parameters;
|
||||
use BitBadger\Documents\SQLite\Results;
|
||||
use FeedReaderCentral\Data;
|
||||
use FeedReaderCentral\Key;
|
||||
use FeedReaderCentral\Security;
|
||||
use FeedReaderCentral\Table;
|
||||
use FeedReaderCentral\User;
|
||||
|
||||
require 'app-config.php';
|
||||
|
||||
|
@ -69,28 +76,14 @@ function title_bar(): void
|
|||
<div><a href=/ class=title>Feed Reader Central</a><span class=version><?=$version?></span></div>
|
||||
<nav><?php
|
||||
if (key_exists(Key::USER_ID, $_SESSION)) {
|
||||
$db = Data::getConnection();
|
||||
try {
|
||||
$bookQuery = $db->prepare(<<<'SQL'
|
||||
SELECT EXISTS(
|
||||
SELECT 1
|
||||
FROM item INNER JOIN feed ON item.feed_id = feed.id
|
||||
WHERE feed.user_id = :id AND item.is_bookmarked = 1)
|
||||
SQL);
|
||||
$bookQuery->bindValue(':id', $_SESSION[Key::USER_ID]);
|
||||
$bookResult = $bookQuery->execute();
|
||||
$hasBookmarks = $bookResult && $bookResult->fetchArray(SQLITE3_NUM)[0];
|
||||
nav_link(hx_get('/feeds', 'Feeds'), true);
|
||||
if ($hasBookmarks) nav_link(hx_get('/?bookmarked', 'Bookmarked'));
|
||||
if (User::hasBookmarks()) nav_link(hx_get('/?bookmarked', 'Bookmarked'));
|
||||
nav_link(hx_get('/search', 'Search'));
|
||||
nav_link(hx_get('/docs/', 'Docs'));
|
||||
nav_link('<a href=/user/log-off>Log Off</a>');
|
||||
if ($_SESSION[Key::USER_EMAIL] != Security::SINGLE_USER_EMAIL) {
|
||||
nav_link($_SESSION[Key::USER_EMAIL]);
|
||||
}
|
||||
} finally {
|
||||
$db->close();
|
||||
}
|
||||
} else {
|
||||
nav_link(hx_get('/user/log-on', 'Log On'), true);
|
||||
nav_link(hx_get('/docs/', 'Docs'));
|
||||
|
|
120
src/util/db-update.php
Normal file
120
src/util/db-update.php
Normal file
|
@ -0,0 +1,120 @@
|
|||
<?php
|
||||
|
||||
use BitBadger\Documents\ArrayMapper;
|
||||
use BitBadger\Documents\DocumentException;
|
||||
use BitBadger\Documents\SQLite\Configuration;
|
||||
use BitBadger\Documents\SQLite\Custom;
|
||||
use BitBadger\Documents\SQLite\Document;
|
||||
use FeedReaderCentral\Data;
|
||||
use FeedReaderCentral\Feed;
|
||||
use FeedReaderCentral\Item;
|
||||
use FeedReaderCentral\Table;
|
||||
use FeedReaderCentral\User;
|
||||
|
||||
require __DIR__ . '/../cli-start.php';
|
||||
|
||||
cli_title('DATABASE UPDATE');
|
||||
|
||||
if ($argc < 2) display_help();
|
||||
|
||||
switch ($argv[1]) {
|
||||
case 'check':
|
||||
check_status();
|
||||
break;
|
||||
case 'run':
|
||||
run_update();
|
||||
break;
|
||||
default:
|
||||
printfn('Unrecognized option "%s"', $argv[1]);
|
||||
display_help();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Display the options for this utility and exit
|
||||
*/
|
||||
function display_help(): never
|
||||
{
|
||||
printfn('Options:');
|
||||
printfn(' - check');
|
||||
printfn(' Check to see if the configured database has been updated');
|
||||
printfn(' - run');
|
||||
printfn(' Run the beta1 database storage update');
|
||||
exit(0);
|
||||
}
|
||||
|
||||
function json_column_exists(): bool
|
||||
{
|
||||
try {
|
||||
$table = Custom::single("SELECT sql FROM sqlite_master WHERE tbl_name='frc_user'", [], new ArrayMapper());
|
||||
return $table && substr_compare(strtolower($table['sql']), 'data text not null', 0) >= 0;
|
||||
} catch (DocumentException $ex) {
|
||||
printfn("ERR $ex");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function check_status(): void
|
||||
{
|
||||
if (json_column_exists()) {
|
||||
printfn('The database has already been updated');
|
||||
} else {
|
||||
printfn('The database has yet to be updated');
|
||||
}
|
||||
}
|
||||
|
||||
function run_update(): void
|
||||
{
|
||||
try {
|
||||
$db = Configuration::dbConn();
|
||||
} catch (DocumentException $ex) {
|
||||
printfn("ERR: Cannot obtain a connection to the database\n $ex");
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
printfn('Removing search index...');
|
||||
Custom::nonQuery('DROP TRIGGER item_ai', [], $db);
|
||||
Custom::nonQuery('DROP TRIGGER item_au', [], $db);
|
||||
Custom::nonQuery('DROP TRIGGER item_ad', [], $db);
|
||||
Custom::nonQuery('DROP TABLE item_search', [], $db);
|
||||
printfn('Moving old tables...');
|
||||
Custom::nonQuery('ALTER TABLE item RENAME TO old_item', [], $db);
|
||||
Custom::nonQuery('ALTER TABLE feed RENAME TO old_feed', [], $db);
|
||||
Custom::nonQuery('ALTER TABLE frc_user RENAME TO old_user', [], $db);
|
||||
printfn('Creating new tables...');
|
||||
Data::ensureDb();
|
||||
printfn('Migrating users...');
|
||||
$users = $db->query('SELECT * FROM old_user');
|
||||
if (!$users) throw new DocumentException('Could not retrieve users');
|
||||
while ($user = $users->fetchArray(SQLITE3_ASSOC)) {
|
||||
Document::insert(Table::USER, new User($user['id'], $user['email'], $user['password']), $db);
|
||||
}
|
||||
printfn('Migrating feeds...');
|
||||
$feeds = $db->query('SELECT * FROM old_feed');
|
||||
if (!$feeds) throw new DocumentException('Could not retrieve feeds');
|
||||
while ($feed = $feeds->fetchArray(SQLITE3_ASSOC)) {
|
||||
Document::insert(Table::FEED,
|
||||
new Feed($feed['id'], $feed['user_id'], $feed['url'], $feed['title'], $feed['updated_on'],
|
||||
$feed['checked_on']), $db);
|
||||
}
|
||||
printfn('Migrating items...');
|
||||
$items = $db->query('SELECT * FROM old_item');
|
||||
if (!$items) throw new DocumentException('Could not retrieve items');
|
||||
while ($item = $items->fetchArray(SQLITE3_ASSOC)) {
|
||||
Document::insert(Table::ITEM,
|
||||
new Item($item['id'], $item['feed_id'], $item['title'], $item['item_guid'], $item['item_link'],
|
||||
$item['published_on'], $item['updated_on'], $item['content'], $item['is_read'],
|
||||
$item['is_bookmarked']), $db);
|
||||
}
|
||||
printfn('Dropping old tables...');
|
||||
Custom::nonQuery('DROP TABLE old_item', [], $db);
|
||||
Custom::nonQuery('DROP TABLE old_feed', [], $db);
|
||||
Custom::nonQuery('DROP TABLE old_user', [], $db);
|
||||
printfn(PHP_EOL. 'Migration complete!');
|
||||
} catch (DocumentException $ex) {
|
||||
printfn("ERR $ex");
|
||||
} finally {
|
||||
$db->close();
|
||||
}
|
||||
}
|
|
@ -1,6 +1,7 @@
|
|||
<?php
|
||||
|
||||
use BitBadger\Documents\DocumentException;
|
||||
use BitBadger\Documents\SQLite\Configuration;
|
||||
use BitBadger\Documents\SQLite\Find;
|
||||
use FeedReaderCentral\Data;
|
||||
use FeedReaderCentral\Feed;
|
||||
|
@ -36,7 +37,12 @@ function display_help(): never
|
|||
|
||||
function refresh_all(): void
|
||||
{
|
||||
$db = Data::getConnection();
|
||||
try {
|
||||
$db = Configuration::dbConn();
|
||||
} catch (DocumentException $ex) {
|
||||
printfn("ERR: Cannot obtain a connection to the database\n $ex");
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
$users = [];
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
<?php
|
||||
|
||||
use BitBadger\Documents\DocumentException;
|
||||
use BitBadger\Documents\SQLite\Configuration;
|
||||
use BitBadger\Documents\SQLite\Custom;
|
||||
use BitBadger\Documents\SQLite\Results;
|
||||
use FeedReaderCentral\Data;
|
||||
|
@ -37,7 +38,12 @@ function display_help(): never
|
|||
*/
|
||||
function rebuild_index(): void
|
||||
{
|
||||
$db = Data::getConnection();
|
||||
try {
|
||||
$db = Configuration::dbConn();
|
||||
} catch (DocumentException $ex) {
|
||||
printfn("ERR: Cannot obtain a connection to the database\n $ex");
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
$hasIndex = Custom::scalar("SELECT COUNT(*) FROM sqlite_master WHERE name = 'item_ai'", [],
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
use BitBadger\Documents\DocumentException;
|
||||
use BitBadger\Documents\Field;
|
||||
use BitBadger\Documents\SQLite\Configuration;
|
||||
use BitBadger\Documents\SQLite\Count;
|
||||
use BitBadger\Documents\SQLite\Delete;
|
||||
use BitBadger\Documents\SQLite\Patch;
|
||||
|
@ -96,8 +97,6 @@ function add_user(): void
|
|||
{
|
||||
global $argv;
|
||||
|
||||
$db = Data::getConnection();
|
||||
|
||||
try {
|
||||
// Ensure there is not already a user with this e-mail address
|
||||
$user = User::findByEmail($argv[2]);
|
||||
|
@ -106,13 +105,11 @@ function add_user(): void
|
|||
return;
|
||||
}
|
||||
|
||||
User::add($argv[2], $argv[3], $db);
|
||||
User::add($argv[2], $argv[3]);
|
||||
|
||||
printfn('User "%s" with password "%s" added successfully', $argv[2], $argv[3]);
|
||||
} catch (DocumentException $ex) {
|
||||
printfn("$ex");
|
||||
} finally {
|
||||
$db->close();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -132,7 +129,6 @@ function display_user(string $email): string
|
|||
*/
|
||||
function set_password(string $email, string $password): void
|
||||
{
|
||||
$db = Data::getConnection();
|
||||
try {
|
||||
$displayUser = display_user($email);
|
||||
|
||||
|
@ -143,15 +139,13 @@ function set_password(string $email, string $password): void
|
|||
return;
|
||||
}
|
||||
|
||||
Security::updatePassword($email, $password, $db);
|
||||
Security::updatePassword($email, $password);
|
||||
|
||||
$msg = $email == Security::SINGLE_USER_EMAIL && $password == Security::SINGLE_USER_PASSWORD
|
||||
? 'reset' : sprintf('set to "%s"', $password);
|
||||
printfn('%s password %s successfully', init_cap($displayUser), $msg);
|
||||
} catch (DocumentException $ex) {
|
||||
printfn("$ex");
|
||||
} finally {
|
||||
$db->close();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -162,7 +156,12 @@ function set_password(string $email, string $password): void
|
|||
*/
|
||||
function delete_user(string $email): void
|
||||
{
|
||||
$db = Data::getConnection();
|
||||
try {
|
||||
$db = Configuration::dbConn();
|
||||
} catch (DocumentException $ex) {
|
||||
printfn("ERR: Cannot obtain a connection to the database\n $ex");
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
$displayUser = display_user($email);
|
||||
|
@ -214,7 +213,12 @@ function migrate_single_user(): void
|
|||
{
|
||||
global $argv;
|
||||
|
||||
$db = Data::getConnection();
|
||||
try {
|
||||
$db = Configuration::dbConn();
|
||||
} catch (DocumentException $ex) {
|
||||
printfn("ERR: Cannot obtain a connection to the database\n $ex");
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
if (!$single = User::findByEmail(Security::SINGLE_USER_EMAIL)) {
|
||||
|
|
Loading…
Reference in New Issue
Block a user