mirror of
https://git.friendi.ca/friendica/friendica.git
synced 2025-06-07 12:34:39 +02:00
Merge 02fb800d12
into 415e7b5f8b
This commit is contained in:
commit
71b6334828
17 changed files with 663 additions and 45 deletions
|
@ -11,6 +11,8 @@ use Friendica\Core\Cache\Capability\ICanCache;
|
|||
use Friendica\Core\Cache\Enum;
|
||||
use Friendica\Core\Cache\Exception\CachePersistenceException;
|
||||
use Friendica\Database\Database;
|
||||
use Friendica\DI;
|
||||
use Friendica\Repository\CacheRepository;
|
||||
use Friendica\Util\DateTimeFormat;
|
||||
|
||||
/**
|
||||
|
@ -25,11 +27,16 @@ class DatabaseCache extends AbstractCache implements ICanCache
|
|||
*/
|
||||
private $dba;
|
||||
|
||||
private CacheRepository $cacheRepo;
|
||||
|
||||
public function __construct(string $hostname, Database $dba)
|
||||
{
|
||||
parent::__construct($hostname);
|
||||
|
||||
$this->dba = $dba;
|
||||
|
||||
// #TODO: Replace this with constuctor injection
|
||||
$this->cacheRepo = DI::databaseService()->getCacheRepository();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -41,27 +48,14 @@ class DatabaseCache extends AbstractCache implements ICanCache
|
|||
{
|
||||
try {
|
||||
if (empty($prefix)) {
|
||||
$where = ['`expires` >= ?', DateTimeFormat::utcNow()];
|
||||
$keys = $this->cacheRepo->getAllKeysValidUntil(DateTimeFormat::utcNow());
|
||||
} else {
|
||||
$where = ['`expires` >= ? AND `k` LIKE CONCAT(?, \'%\')', DateTimeFormat::utcNow(), $prefix];
|
||||
$keys = $this->cacheRepo->getAllKeysValidUntilWithPrefix(DateTimeFormat::utcNow(), $prefix);
|
||||
}
|
||||
|
||||
$stmt = $this->dba->select('cache', ['k'], $where);
|
||||
} catch (\Exception $exception) {
|
||||
throw new CachePersistenceException(sprintf('Cannot fetch all keys with prefix %s', $prefix), $exception);
|
||||
}
|
||||
|
||||
try {
|
||||
$keys = [];
|
||||
while ($key = $this->dba->fetch($stmt)) {
|
||||
array_push($keys, $key['k']);
|
||||
}
|
||||
} catch (\Exception $exception) {
|
||||
$this->dba->close($stmt);
|
||||
throw new CachePersistenceException(sprintf('Cannot fetch all keys with prefix %s', $prefix), $exception);
|
||||
}
|
||||
|
||||
$this->dba->close($stmt);
|
||||
return $keys;
|
||||
}
|
||||
|
||||
|
|
|
@ -80,6 +80,11 @@ abstract class DI
|
|||
return self::$dice->create(AppHelper::class);
|
||||
}
|
||||
|
||||
public static function databaseService(): Database\DatabaseService
|
||||
{
|
||||
return self::$dice->create(Database\DatabaseService::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Database\Database
|
||||
*/
|
||||
|
|
|
@ -62,15 +62,15 @@ class Database
|
|||
protected $server_info = '';
|
||||
/** @var PDO|mysqli|null */
|
||||
protected $connection;
|
||||
protected $driver = '';
|
||||
protected $pdo_emulate_prepares = false;
|
||||
private $error = '';
|
||||
private $errorno = 0;
|
||||
private $affected_rows = 0;
|
||||
protected $in_transaction = false;
|
||||
protected $in_retrial = false;
|
||||
protected $testmode = false;
|
||||
private $relation = [];
|
||||
protected $driver = '';
|
||||
protected $pdo_emulate_prepares = false;
|
||||
private $error = '';
|
||||
private $errorno = 0;
|
||||
private $affected_rows = 0;
|
||||
protected $in_transaction = false;
|
||||
protected $in_retrial = false;
|
||||
private bool $throwExceptionsOnErrors = false;
|
||||
private $relation = [];
|
||||
/** @var DbaDefinition */
|
||||
protected $dbaDefinition;
|
||||
/** @var ViewDefinition */
|
||||
|
@ -205,9 +205,18 @@ class Database
|
|||
return $this->connected;
|
||||
}
|
||||
|
||||
public function setTestmode(bool $test)
|
||||
/**
|
||||
* Should errors throwns as exceptions?
|
||||
*
|
||||
* @return bool returns the previous value
|
||||
*/
|
||||
public function throwExceptionsOnErrors(bool $throwExceptions): bool
|
||||
{
|
||||
$this->testmode = $test;
|
||||
$prev = $this->throwExceptionsOnErrors;
|
||||
|
||||
$this->throwExceptionsOnErrors = $throwExceptions;
|
||||
|
||||
return $prev;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -672,7 +681,7 @@ class Database
|
|||
$error = $this->error;
|
||||
$errorno = $this->errorno;
|
||||
|
||||
if ($this->testmode) {
|
||||
if ($this->throwExceptionsOnErrors) {
|
||||
throw new DatabaseException($error, $errorno, $this->replaceParameters($sql, $args));
|
||||
}
|
||||
|
||||
|
@ -779,7 +788,7 @@ class Database
|
|||
$error = $this->error;
|
||||
$errorno = $this->errorno;
|
||||
|
||||
if ($this->testmode) {
|
||||
if ($this->throwExceptionsOnErrors) {
|
||||
throw new DatabaseException($error, $errorno, $this->replaceParameters($sql, $params));
|
||||
}
|
||||
|
||||
|
|
36
src/Database/DatabaseService.php
Normal file
36
src/Database/DatabaseService.php
Normal file
|
@ -0,0 +1,36 @@
|
|||
<?php
|
||||
|
||||
// Copyright (C) 2010-2024, the Friendica project
|
||||
// SPDX-FileCopyrightText: 2010-2024 the Friendica project
|
||||
//
|
||||
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Friendica\Database;
|
||||
|
||||
use Friendica\Database\Database;
|
||||
use Friendica\Database\Repository\CacheTableRepository;
|
||||
use Friendica\Database\Repository\UserdTableRepository;
|
||||
use Friendica\Repository\CacheRepository;
|
||||
use Friendica\Repository\DeletedUserRepository;
|
||||
|
||||
final class DatabaseService
|
||||
{
|
||||
private Database $database;
|
||||
|
||||
public function __construct(Database $database)
|
||||
{
|
||||
$this->database = $database;
|
||||
}
|
||||
|
||||
public function getDeletedUserRepository(): DeletedUserRepository
|
||||
{
|
||||
return new UserdTableRepository($this->database);
|
||||
}
|
||||
|
||||
public function getCacheRepository(): CacheRepository
|
||||
{
|
||||
return new CacheTableRepository($this->database);
|
||||
}
|
||||
}
|
83
src/Database/Model/CacheModel.php
Normal file
83
src/Database/Model/CacheModel.php
Normal file
|
@ -0,0 +1,83 @@
|
|||
<?php
|
||||
|
||||
// Copyright (C) 2010-2024, the Friendica project
|
||||
// SPDX-FileCopyrightText: 2010-2024 the Friendica project
|
||||
//
|
||||
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Friendica\Database\Model;
|
||||
|
||||
use Exception;
|
||||
use Friendica\Database\DBA;
|
||||
use Friendica\Entity\CacheEntity;
|
||||
|
||||
/**
|
||||
* Model for a row in the cache table
|
||||
*/
|
||||
final class CacheModel implements CacheEntity
|
||||
{
|
||||
/**
|
||||
* Validates the row array and creates the entity
|
||||
*
|
||||
* @throws Exception If $data['v'] contains invalid data that could not unserialize.
|
||||
*/
|
||||
public static function createFromArray(array $data): self
|
||||
{
|
||||
$rawValue = array_key_exists('v', $data) ? (string) $data['v'] : '';
|
||||
$value = @unserialize($rawValue);
|
||||
|
||||
// Only return a value if the serialized value is valid.
|
||||
// We also check if the db entry is a serialized
|
||||
// boolean 'false' value (which we want to return).
|
||||
if ($value === false && $rawValue !== 'b:0;' ) {
|
||||
throw new Exception(sprintf('Invalid value data for cache object.'));
|
||||
}
|
||||
|
||||
$entity = new self();
|
||||
array_key_exists('k', $data) ?? $entity->k = (string) $data['k'];
|
||||
$entity->v = $rawValue;
|
||||
$entity->value = $value;
|
||||
array_key_exists('expired', $data) ?? $entity->expired = (string) $data['expired'];
|
||||
array_key_exists('updated', $data) ?? $entity->updated = (string) $data['updated'];
|
||||
|
||||
return $entity;
|
||||
}
|
||||
|
||||
/**
|
||||
* cache key
|
||||
*/
|
||||
private string $k = '';
|
||||
|
||||
/**
|
||||
* cached serialized value
|
||||
*/
|
||||
private string $v = '';
|
||||
|
||||
/**
|
||||
*
|
||||
* @var mixed $value cached unserialized value
|
||||
*/
|
||||
private $value;
|
||||
|
||||
/**
|
||||
* datetime of cache expiration
|
||||
*/
|
||||
private string $expired = DBA::NULL_DATETIME;
|
||||
|
||||
/**
|
||||
* datetime of cache insertion
|
||||
*/
|
||||
private string $updated = DBA::NULL_DATETIME;
|
||||
|
||||
private function __construct() {}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getValue()
|
||||
{
|
||||
return $this->value;
|
||||
}
|
||||
}
|
135
src/Database/Repository/CacheTableRepository.php
Normal file
135
src/Database/Repository/CacheTableRepository.php
Normal file
|
@ -0,0 +1,135 @@
|
|||
<?php
|
||||
|
||||
// Copyright (C) 2010-2024, the Friendica project
|
||||
// SPDX-FileCopyrightText: 2010-2024 the Friendica project
|
||||
//
|
||||
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Friendica\Database\Repository;
|
||||
|
||||
use Friendica\Database\Database;
|
||||
use Friendica\Database\DatabaseException;
|
||||
use Friendica\Database\Model\CacheModel;
|
||||
use Friendica\Entity\CacheEntity;
|
||||
use Friendica\Repository\CacheRepository;
|
||||
use Throwable;
|
||||
|
||||
/**
|
||||
* Repository for cache table
|
||||
*/
|
||||
final class CacheTableRepository implements CacheRepository
|
||||
{
|
||||
private Database $database;
|
||||
|
||||
public function __construct(Database $database)
|
||||
{
|
||||
$this->database = $database;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws DatabaseException
|
||||
*
|
||||
* @return array<string>
|
||||
*/
|
||||
public function getAllKeysValidUntil(string $expires): array
|
||||
{
|
||||
$throw = $this->database->throwExceptionsOnErrors(true);
|
||||
|
||||
try {
|
||||
return $this->getAllKeys($expires, null);
|
||||
} catch (Throwable $th) {
|
||||
if (! $th instanceof DatabaseException) {
|
||||
$th = new DatabaseException('Cannot fetch all keys without prefix', 0, '', $th);
|
||||
}
|
||||
|
||||
throw $th;
|
||||
} finally {
|
||||
$this->database->throwExceptionsOnErrors($throw);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws DatabaseException
|
||||
*
|
||||
* @return array<string>
|
||||
*/
|
||||
public function getAllKeysValidUntilWithPrefix(string $expires, string $prefix): array
|
||||
{
|
||||
$throw = $this->database->throwExceptionsOnErrors(true);
|
||||
|
||||
try {
|
||||
return $this->getAllKeys($expires, $prefix);
|
||||
} catch (Throwable $th) {
|
||||
if (! $th instanceof DatabaseException) {
|
||||
$th = new DatabaseException(sprintf('Cannot fetch all keys with prefix `%s`', $prefix), 0, '', $th);
|
||||
}
|
||||
|
||||
throw $th;
|
||||
} finally {
|
||||
$this->database->throwExceptionsOnErrors($throw);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws DatabaseException
|
||||
*
|
||||
* @return CacheEntity|null
|
||||
*/
|
||||
public function findOneByKeyValidUntil(string $key, string $expires)
|
||||
{
|
||||
$throw = $this->database->throwExceptionsOnErrors(true);
|
||||
|
||||
try {
|
||||
$cacheArray = $this->database->selectFirst(
|
||||
'cache',
|
||||
['v'],
|
||||
['`k` = ? AND (`expires` >= ? OR `expires` = -1)', $key, $expires]
|
||||
);
|
||||
|
||||
if (!$this->database->isResult($cacheArray)) {
|
||||
return null;
|
||||
}
|
||||
} catch (Throwable $th) {
|
||||
if (! $th instanceof DatabaseException) {
|
||||
$th = new DatabaseException(sprintf('Cannot get cache entry with key `%s`', $key), 0, '', $th);
|
||||
}
|
||||
|
||||
throw $th;
|
||||
} finally {
|
||||
$this->database->throwExceptionsOnErrors($throw);
|
||||
}
|
||||
|
||||
try {
|
||||
$entity = CacheModel::createFromArray($cacheArray);
|
||||
} catch (Throwable $th) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $entity;
|
||||
}
|
||||
|
||||
private function getAllKeys(string $expires, ?string $prefix = null): array
|
||||
{
|
||||
if ($prefix === null) {
|
||||
$where = ['`expires` >= ?', $expires];
|
||||
} else {
|
||||
$where = ['`expires` >= ? AND `k` LIKE CONCAT(?, \'%\')', $expires, $prefix];
|
||||
}
|
||||
|
||||
$stmt = $this->database->select('cache', ['k'], $where);
|
||||
|
||||
$keys = [];
|
||||
|
||||
try {
|
||||
while ($key = $this->database->fetch($stmt)) {
|
||||
array_push($keys, $key['k']);
|
||||
}
|
||||
} finally {
|
||||
$this->database->close($stmt);
|
||||
}
|
||||
|
||||
return $keys;
|
||||
}
|
||||
}
|
54
src/Database/Repository/UserdTableRepository.php
Normal file
54
src/Database/Repository/UserdTableRepository.php
Normal file
|
@ -0,0 +1,54 @@
|
|||
<?php
|
||||
|
||||
// Copyright (C) 2010-2024, the Friendica project
|
||||
// SPDX-FileCopyrightText: 2010-2024 the Friendica project
|
||||
//
|
||||
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Friendica\Database\Repository;
|
||||
|
||||
use Exception;
|
||||
use Friendica\Database\Database;
|
||||
use Friendica\Database\DatabaseException;
|
||||
use Friendica\Repository\DeletedUserRepository;
|
||||
|
||||
/**
|
||||
* Repository for userd table
|
||||
*/
|
||||
final class UserdTableRepository implements DeletedUserRepository
|
||||
{
|
||||
private Database $database;
|
||||
|
||||
public function __construct(Database $database)
|
||||
{
|
||||
$this->database = $database;
|
||||
}
|
||||
|
||||
/**
|
||||
* Insert a deleted user by username.
|
||||
*
|
||||
* @throws DatabaseException If the username could not be inserted
|
||||
*/
|
||||
public function insertByUsername(string $username): void
|
||||
{
|
||||
$throw = $this->database->throwExceptionsOnErrors(true);
|
||||
|
||||
try {
|
||||
$this->database->insert('userd', ['username' => $username]);
|
||||
} finally {
|
||||
$this->database->throwExceptionsOnErrors($throw);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a deleted username exists.
|
||||
*
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function existsByUsername(string $username): bool
|
||||
{
|
||||
return $this->database->exists('userd', ['username' => $username]);
|
||||
}
|
||||
}
|
21
src/Entity/CacheEntity.php
Normal file
21
src/Entity/CacheEntity.php
Normal file
|
@ -0,0 +1,21 @@
|
|||
<?php
|
||||
|
||||
// Copyright (C) 2010-2024, the Friendica project
|
||||
// SPDX-FileCopyrightText: 2010-2024 the Friendica project
|
||||
//
|
||||
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Friendica\Entity;
|
||||
|
||||
/**
|
||||
* Entity for a cache entry
|
||||
*/
|
||||
interface CacheEntity
|
||||
{
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getValue();
|
||||
}
|
|
@ -266,10 +266,12 @@ class User
|
|||
return $system_actor_name;
|
||||
}
|
||||
|
||||
$userDeletedRepository = DI::databaseService()->getDeletedUserRepository();
|
||||
|
||||
// List of possible actor names
|
||||
$possible_accounts = ['friendica', 'actor', 'system', 'internal'];
|
||||
foreach ($possible_accounts as $name) {
|
||||
if (!DBA::exists('user', ['nickname' => $name]) && !DBA::exists('userd', ['username' => $name])) {
|
||||
if (!DBA::exists('user', ['nickname' => $name]) && !$userDeletedRepository->existsByUsername($name)) {
|
||||
DI::config()->set('system', 'actor_name', $name);
|
||||
return $name;
|
||||
}
|
||||
|
@ -1299,10 +1301,12 @@ class User
|
|||
throw new Exception(DI::l10n()->t('Your nickname can only contain a-z, 0-9 and _.'));
|
||||
}
|
||||
|
||||
$userDeletedRepository = DI::databaseService()->getDeletedUserRepository();
|
||||
|
||||
// Check existing and deleted accounts for this nickname.
|
||||
if (
|
||||
DBA::exists('user', ['nickname' => $nickname])
|
||||
|| DBA::exists('userd', ['username' => $nickname])
|
||||
|| $userDeletedRepository->existsByUsername($nickname)
|
||||
) {
|
||||
throw new Exception(DI::l10n()->t('Nickname is already registered. Please choose another.'));
|
||||
}
|
||||
|
@ -1812,9 +1816,15 @@ class User
|
|||
|
||||
$user = $hook_data['user'] ?? $user;
|
||||
|
||||
$userDeletedRepository = DI::databaseService()->getDeletedUserRepository();
|
||||
|
||||
// save username (actually the nickname as it is guaranteed
|
||||
// unique), so it cannot be re-registered in the future.
|
||||
DBA::insert('userd', ['username' => $user['nickname']]);
|
||||
try {
|
||||
$userDeletedRepository->insertByUsername($user['nickname']);
|
||||
} catch (\Throwable $th) {
|
||||
DI::logger()->error('Error while inserting username of deleted user.', ['username' => $user['nickname'], 'exception' => $th]);
|
||||
}
|
||||
|
||||
// Remove all personal settings, especially connector settings
|
||||
DBA::delete('pconfig', ['uid' => $uid]);
|
||||
|
|
|
@ -35,6 +35,7 @@ use Friendica\Network\HTTPException;
|
|||
use Friendica\Network\HTTPException\InternalServerErrorException;
|
||||
use Friendica\Profile\ProfileField\Repository\ProfileField;
|
||||
use Friendica\Protocol\ActivityPub;
|
||||
use Friendica\Repository\DeletedUserRepository;
|
||||
use Friendica\Util\DateTimeFormat;
|
||||
use Friendica\Util\Network;
|
||||
use Friendica\Util\Profiler;
|
||||
|
@ -47,6 +48,7 @@ class Profile extends BaseProfile
|
|||
{
|
||||
/** @var Database */
|
||||
private $database;
|
||||
private DeletedUserRepository $deletedUserRepository;
|
||||
/** @var AppHelper */
|
||||
private $appHelper;
|
||||
/** @var IHandleUserSessions */
|
||||
|
@ -66,6 +68,7 @@ class Profile extends BaseProfile
|
|||
IHandleUserSessions $session,
|
||||
AppHelper $appHelper,
|
||||
Database $database,
|
||||
DeletedUserRepository $deletedUserRepository,
|
||||
EventDispatcherInterface $eventDispatcher,
|
||||
L10n $l10n,
|
||||
BaseURL $baseUrl,
|
||||
|
@ -78,13 +81,14 @@ class Profile extends BaseProfile
|
|||
) {
|
||||
parent::__construct($l10n, $baseUrl, $args, $logger, $profiler, $response, $server, $parameters);
|
||||
|
||||
$this->database = $database;
|
||||
$this->appHelper = $appHelper;
|
||||
$this->session = $session;
|
||||
$this->config = $config;
|
||||
$this->page = $page;
|
||||
$this->profileField = $profileField;
|
||||
$this->eventDispatcher = $eventDispatcher;
|
||||
$this->database = $database;
|
||||
$this->deletedUserRepository = $deletedUserRepository;
|
||||
$this->appHelper = $appHelper;
|
||||
$this->session = $session;
|
||||
$this->config = $config;
|
||||
$this->page = $page;
|
||||
$this->profileField = $profileField;
|
||||
$this->eventDispatcher = $eventDispatcher;
|
||||
}
|
||||
|
||||
protected function rawContent(array $request = [])
|
||||
|
@ -102,7 +106,7 @@ class Profile extends BaseProfile
|
|||
}
|
||||
}
|
||||
|
||||
if ($this->database->exists('userd', ['username' => $this->parameters['nickname']])) {
|
||||
if ($this->deletedUserRepository->existsByUsername($this->parameters['nickname'])) {
|
||||
// Known deleted user
|
||||
$data = ActivityPub\Transmitter::getDeletedUser($this->parameters['nickname']);
|
||||
|
||||
|
|
|
@ -7,7 +7,8 @@
|
|||
|
||||
namespace Friendica\Module\User;
|
||||
|
||||
use Friendica\App;
|
||||
use Friendica\App\Arguments;
|
||||
use Friendica\App\BaseURL;
|
||||
use Friendica\Core\Config\Capability\IManageConfigValues;
|
||||
use Friendica\Core\L10n;
|
||||
use Friendica\Core\PConfig\Capability\IManagePersonalConfigValues;
|
||||
|
@ -26,6 +27,7 @@ use Friendica\Navigation\SystemMessages;
|
|||
use Friendica\Network\HTTPException;
|
||||
use Friendica\Object\Image;
|
||||
use Friendica\Protocol\Delivery;
|
||||
use Friendica\Repository\DeletedUserRepository;
|
||||
use Friendica\Security\PermissionSet\Repository\PermissionSet;
|
||||
use Friendica\Util\Profiler;
|
||||
use Friendica\Util\Strings;
|
||||
|
@ -47,20 +49,38 @@ class Import extends \Friendica\BaseModule
|
|||
/** @var Database */
|
||||
private $database;
|
||||
|
||||
private DeletedUserRepository $deletedUserRepository;
|
||||
|
||||
/** @var PermissionSet */
|
||||
private $permissionSet;
|
||||
|
||||
/** @var UserSession */
|
||||
private $session;
|
||||
|
||||
public function __construct(UserSession $session, PermissionSet $permissionSet, IManagePersonalConfigValues $pconfig, Database $database, SystemMessages $systemMessages, IManageConfigValues $config, L10n $l10n, App\BaseURL $baseUrl, App\Arguments $args, LoggerInterface $logger, Profiler $profiler, Response $response, array $server, array $parameters = [])
|
||||
{
|
||||
public function __construct(
|
||||
UserSession $session,
|
||||
PermissionSet $permissionSet,
|
||||
IManagePersonalConfigValues $pconfig,
|
||||
Database $database,
|
||||
DeletedUserRepository $deletedUserRepository,
|
||||
SystemMessages $systemMessages,
|
||||
IManageConfigValues $config,
|
||||
L10n $l10n,
|
||||
BaseURL $baseUrl,
|
||||
Arguments $args,
|
||||
LoggerInterface $logger,
|
||||
Profiler $profiler,
|
||||
Response $response,
|
||||
array $server,
|
||||
array $parameters = []
|
||||
) {
|
||||
parent::__construct($l10n, $baseUrl, $args, $logger, $profiler, $response, $server, $parameters);
|
||||
|
||||
$this->config = $config;
|
||||
$this->pconfig = $pconfig;
|
||||
$this->systemMessages = $systemMessages;
|
||||
$this->database = $database;
|
||||
$this->deletedUserRepository = $deletedUserRepository;
|
||||
$this->permissionSet = $permissionSet;
|
||||
$this->session = $session;
|
||||
}
|
||||
|
@ -213,7 +233,7 @@ class Import extends \Friendica\BaseModule
|
|||
// check for username
|
||||
// check if username matches deleted account
|
||||
if ($this->database->exists('user', ['nickname' => $account['user']['nickname']])
|
||||
|| $this->database->exists('userd', ['username' => $account['user']['nickname']])) {
|
||||
|| $this->deletedUserRepository->existsByUsername($account['user']['nickname'])) {
|
||||
$this->systemMessages->addNotice($this->t("User '%s' already exists on this server!", $account['user']['nickname']));
|
||||
return;
|
||||
}
|
||||
|
|
40
src/Repository/CacheRepository.php
Normal file
40
src/Repository/CacheRepository.php
Normal file
|
@ -0,0 +1,40 @@
|
|||
<?php
|
||||
|
||||
// Copyright (C) 2010-2024, the Friendica project
|
||||
// SPDX-FileCopyrightText: 2010-2024 the Friendica project
|
||||
//
|
||||
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Friendica\Repository;
|
||||
|
||||
use Friendica\Database\DatabaseException;
|
||||
use Friendica\Entity\CacheEntity;
|
||||
|
||||
/**
|
||||
* Interface for a cache repository
|
||||
*/
|
||||
interface CacheRepository
|
||||
{
|
||||
/**
|
||||
* @throws DatabaseException
|
||||
*
|
||||
* @return array<string>
|
||||
*/
|
||||
public function getAllKeysValidUntil(string $expires): array;
|
||||
|
||||
/**
|
||||
* @throws DatabaseException
|
||||
*
|
||||
* @return array<string>
|
||||
*/
|
||||
public function getAllKeysValidUntilWithPrefix(string $expires, string $prefix): array;
|
||||
|
||||
/**
|
||||
* @throws DatabaseException
|
||||
*
|
||||
* @return CacheEntity|null
|
||||
*/
|
||||
public function findOneByKeyValidUntil(string $key, string $expires);
|
||||
}
|
33
src/Repository/DeletedUserRepository.php
Normal file
33
src/Repository/DeletedUserRepository.php
Normal file
|
@ -0,0 +1,33 @@
|
|||
<?php
|
||||
|
||||
// Copyright (C) 2010-2024, the Friendica project
|
||||
// SPDX-FileCopyrightText: 2010-2024 the Friendica project
|
||||
//
|
||||
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Friendica\Repository;
|
||||
|
||||
use Exception;
|
||||
use Friendica\Database\DatabaseException;
|
||||
|
||||
/**
|
||||
* Interface for a repository for deleted users
|
||||
*/
|
||||
interface DeletedUserRepository
|
||||
{
|
||||
/**
|
||||
* Insert a deleted user by username.
|
||||
*
|
||||
* @throws DatabaseException If the username could not be inserted
|
||||
*/
|
||||
public function insertByUsername(string $username): void;
|
||||
|
||||
/**
|
||||
* Check if a deleted username exists.
|
||||
*
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function existsByUsername(string $username): bool;
|
||||
}
|
|
@ -60,7 +60,7 @@ trait FixtureTestTrait
|
|||
|
||||
/** @var Database $dba */
|
||||
$dba = $this->dice->create(Database::class);
|
||||
$dba->setTestmode(true);
|
||||
$dba->throwExceptionsOnErrors(true);
|
||||
|
||||
DBStructure::checkInitialValues();
|
||||
|
||||
|
|
97
tests/Unit/Database/Repository/CacheTableRepositoryTest.php
Normal file
97
tests/Unit/Database/Repository/CacheTableRepositoryTest.php
Normal file
|
@ -0,0 +1,97 @@
|
|||
<?php
|
||||
|
||||
// Copyright (C) 2010-2024, the Friendica project
|
||||
// SPDX-FileCopyrightText: 2010-2024 the Friendica project
|
||||
//
|
||||
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Friendica\Test\Unit\Database\Repository;
|
||||
|
||||
use Friendica\Database\Database;
|
||||
use Friendica\Database\DatabaseException;
|
||||
use Friendica\Database\Repository\CacheTableRepository;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Throwable;
|
||||
|
||||
class CacheTableRepositoryTest extends TestCase
|
||||
{
|
||||
public function testGetAllKeysValidUntilReturnsArray(): void
|
||||
{
|
||||
$stmt = new \stdClass;
|
||||
|
||||
$database = $this->createStub(Database::class);
|
||||
$database->method('select')->willReturnMap([
|
||||
['cache', ['k'], ['`expires` >= ?', '2025-04-16 10:12:01'], [], $stmt],
|
||||
]);
|
||||
$database->method('fetch')->willReturnOnConsecutiveCalls(
|
||||
['k' => 'value1'],
|
||||
['k' => 'value2'],
|
||||
['k' => 'value3'],
|
||||
false
|
||||
);
|
||||
|
||||
$repo = new CacheTableRepository($database);
|
||||
|
||||
$this->assertSame(
|
||||
[
|
||||
'value1',
|
||||
'value2',
|
||||
'value3',
|
||||
],
|
||||
$repo->getAllKeysValidUntil('2025-04-16 10:12:01')
|
||||
);
|
||||
}
|
||||
|
||||
public function testGetAllKeysValidUntilThrowsException(): void
|
||||
{
|
||||
$database = $this->createStub(Database::class);
|
||||
$database->method('select')->willThrowException($this->createStub(Throwable::class));
|
||||
|
||||
$repo = new CacheTableRepository($database);
|
||||
|
||||
$this->expectException(DatabaseException::class);
|
||||
|
||||
$repo->getAllKeysValidUntil('2025-04-16 10:12:01');
|
||||
}
|
||||
|
||||
public function testGetAllKeysValidUntilWithPrefixReturnsArray(): void
|
||||
{
|
||||
$stmt = new \stdClass;
|
||||
|
||||
$database = $this->createStub(Database::class);
|
||||
$database->method('select')->willReturnMap([
|
||||
['cache', ['k'], ['`expires` >= ?', '2025-04-16 10:12:01'], [], $stmt],
|
||||
]);
|
||||
$database->method('fetch')->willReturnOnConsecutiveCalls(
|
||||
['k' => 'value1'],
|
||||
['k' => 'value2'],
|
||||
['k' => 'value3'],
|
||||
false
|
||||
);
|
||||
|
||||
$repo = new CacheTableRepository($database);
|
||||
|
||||
$this->assertSame(
|
||||
[
|
||||
'value1',
|
||||
'value2',
|
||||
'value3',
|
||||
],
|
||||
$repo->getAllKeysValidUntilWithPrefix('2025-04-16 10:12:01', 'prefix')
|
||||
);
|
||||
}
|
||||
|
||||
public function testGetAllKeysValidUntilWithPrefixThrowsException(): void
|
||||
{
|
||||
$database = $this->createStub(Database::class);
|
||||
$database->method('select')->willThrowException($this->createStub(Throwable::class));
|
||||
|
||||
$repo = new CacheTableRepository($database);
|
||||
|
||||
$this->expectException(DatabaseException::class);
|
||||
|
||||
$repo->getAllKeysValidUntilWithPrefix('2025-04-16 10:12:01', 'prefix');
|
||||
}
|
||||
}
|
77
tests/Unit/Database/Repository/UserdTableRepositoryTest.php
Normal file
77
tests/Unit/Database/Repository/UserdTableRepositoryTest.php
Normal file
|
@ -0,0 +1,77 @@
|
|||
<?php
|
||||
|
||||
// Copyright (C) 2010-2024, the Friendica project
|
||||
// SPDX-FileCopyrightText: 2010-2024 the Friendica project
|
||||
//
|
||||
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Friendica\Test\Unit\Database\Repository;
|
||||
|
||||
use Friendica\Database\Database;
|
||||
use Friendica\Database\DatabaseException;
|
||||
use Friendica\Database\Repository\UserdTableRepository;
|
||||
use Friendica\Repository\DeletedUserRepository;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
class UserdTableRepositoryTest extends TestCase
|
||||
{
|
||||
public function testImplementationOfInterfaces(): void
|
||||
{
|
||||
$repo = new UserdTableRepository($this->createMock(Database::class));
|
||||
|
||||
$this->assertInstanceOf(DeletedUserRepository::class, $repo);
|
||||
}
|
||||
|
||||
public function testInsertByUsernameCallsDatabase(): void
|
||||
{
|
||||
$database = $this->createMock(Database::class);
|
||||
$database->expects($this->once())->method('insert')->willReturnMap([
|
||||
['userd', ['username' => 'test'], 0, true],
|
||||
]);
|
||||
|
||||
$repo = new UserdTableRepository($database);
|
||||
|
||||
$repo->insertByUsername('test');
|
||||
}
|
||||
|
||||
public function testInsertByUsernameThrowsException(): void
|
||||
{
|
||||
$database = $this->createMock(Database::class);
|
||||
$database->expects($this->exactly(2))->method('throwExceptionsOnErrors');
|
||||
$database->expects($this->once())->method('insert')->willThrowException(
|
||||
new DatabaseException('An error occured.', 0, 'SQL query')
|
||||
);
|
||||
|
||||
$repo = new UserdTableRepository($database);
|
||||
|
||||
$this->expectException(DatabaseException::class);
|
||||
|
||||
$repo->insertByUsername('test');
|
||||
}
|
||||
|
||||
public function testExistsByUsernameReturnsTrue(): void
|
||||
{
|
||||
$database = $this->createStub(Database::class);
|
||||
$database->method('exists')->willReturnMap([
|
||||
['userd', ['username' => 'test'], true],
|
||||
]);
|
||||
|
||||
$repo = new UserdTableRepository($database);
|
||||
|
||||
$this->assertTrue($repo->existsByUsername('test'));
|
||||
}
|
||||
|
||||
public function testExistsByUsernameReturnsFalse(): void
|
||||
{
|
||||
$database = $this->createStub(Database::class);
|
||||
$database->method('exists')->willReturnMap([
|
||||
['userd', ['username' => 'test'], false],
|
||||
]);
|
||||
|
||||
$repo = new UserdTableRepository($database);
|
||||
|
||||
$this->assertFalse($repo->existsByUsername('test'));
|
||||
}
|
||||
}
|
|
@ -43,7 +43,7 @@ trait CreateDatabaseTrait
|
|||
]));
|
||||
|
||||
$database = new StaticDatabase($config, (new DbaDefinition($this->root->url()))->load(), (new ViewDefinition($this->root->url()))->load());
|
||||
$database->setTestmode(true);
|
||||
$database->throwExceptionsOnErrors(true);
|
||||
|
||||
return $database;
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue