generated from mirzaev/pot
разработана аутентификация и регистрация аккаунта
This commit is contained in:
@@ -4,9 +4,6 @@ declare(strict_types=1);
|
||||
|
||||
namespace mirzaev\site\account\models;
|
||||
|
||||
// Файлы проекта
|
||||
use mirzaev\site\account\models\vk;
|
||||
|
||||
// Фреймворк ArangoDB
|
||||
use mirzaev\arangodb\collection,
|
||||
mirzaev\arangodb\document;
|
||||
@@ -31,19 +28,162 @@ final class account extends core
|
||||
public const COLLECTION = 'account';
|
||||
|
||||
/**
|
||||
* Инстанция в базе данных
|
||||
* Инстанция документа аккаунта в базе данных
|
||||
*/
|
||||
public ?_document $instance;
|
||||
public ?_document $document;
|
||||
|
||||
/**
|
||||
* Прочитать
|
||||
* Конструктор
|
||||
*
|
||||
* 1. Проверяет связь сессии с аккаунтом
|
||||
* 1.1. Если найдена связь, то возвращает связанный аккаунт (выход)
|
||||
* 2. [authenticate === true] Проверяет наличие данных в буфере сессии
|
||||
* 2.1 Если найден входной псевдоним и пароли совпадают, то аутентифицирует (выход)
|
||||
* 2.2 [register === true] Если найдены данные для регистрации, то регистрирует (выход)
|
||||
*
|
||||
* @param ?session $session Инстанция сессии
|
||||
* @param bool $authenticate Аутентифицировать аккаунт?
|
||||
* @param bool $register Регистрировать аккаунт?
|
||||
* @param array &$errors Реестр ошибок
|
||||
*
|
||||
* @return static Инстанция аккаунта
|
||||
*/
|
||||
public function __construct(?session $session = null, bool $authenticate = false, bool $register = false, array &$errors = [])
|
||||
{
|
||||
try {
|
||||
if (isset($session)) {
|
||||
// Получена инстанция сессии
|
||||
|
||||
if ($account = $session->account()) {
|
||||
// Найден связанный с сессией аккаунт
|
||||
|
||||
// Инициализация инстанции документа аккаунта в базе данных
|
||||
$this->document = $account->document;
|
||||
|
||||
// Связь сессии с аккаунтом
|
||||
$session->connect($this, $errors);
|
||||
|
||||
return $this;
|
||||
} else {
|
||||
// Не найден связанный с сессией аккаунт
|
||||
|
||||
if ($authenticate) {
|
||||
// Запрошена аутентификация
|
||||
|
||||
if (!empty($session->buffer['entry'])) {
|
||||
// Найдены данные для идентификации в буфере сессии
|
||||
|
||||
if (!empty($session->buffer['entry']['login'])) {
|
||||
// Найдены входной псевдоним в буфере сессии
|
||||
|
||||
if (($account = self::login($session->buffer['entry']['login'])) instanceof self) {
|
||||
// Найден аккаунт (игнорируются ошибки)
|
||||
|
||||
if (isset($account->password) && $account->password === '') {
|
||||
// Не имеет пароля аккаунт
|
||||
|
||||
// Проверка отсутствия переданного пароля
|
||||
if (isset($session->buffer['entry']['password']) && $session->buffer['entry']['password'] !== '') throw new exception('Неправильный пароль');
|
||||
|
||||
// Инициализация инстанции документа аккаунта в базе данных
|
||||
$this->document = $account->document;
|
||||
|
||||
// Связь сессии с аккаунтом
|
||||
$session->connect($this, $errors);
|
||||
|
||||
// Удаление использованных данных из буфера сессии
|
||||
$session->write(['entry' => ['password' => null]]);
|
||||
|
||||
return $this;
|
||||
} else if (!empty($session->buffer['entry']['password'])) {
|
||||
// Найден пароль в буфере сессии
|
||||
|
||||
if (sodium_crypto_pwhash_str_verify($account->password, $session->buffer['entry']['password'])) {
|
||||
// Аутентифицирован аккаунт (прошёл проверку пароль, либо аккаунт не имеет пароля)
|
||||
|
||||
// Инициализация инстанции документа аккаунта в базе данных
|
||||
$this->document = $account->document;
|
||||
|
||||
// Связь сессии с аккаунтом
|
||||
$session->connect($this, $errors);
|
||||
|
||||
// Удаление использованных данных из буфера сессии
|
||||
$session->write(['entry' => ['password' => null]]);
|
||||
|
||||
return $this;
|
||||
} else throw new exception('Неправильный пароль');
|
||||
} throw new exception('Неправильный пароль');
|
||||
} else {
|
||||
// Не найден аккаунт
|
||||
|
||||
if ($register) {
|
||||
// Запрошена регистрация
|
||||
|
||||
if (!empty($session->buffer['entry']['invite'])) {
|
||||
// Найден ключ приглашения в буфере сессии
|
||||
|
||||
// Проверка наличия переданного пароля
|
||||
if (!isset($session->buffer['entry']['password'])) throw new exception('Не найден пароль в буфере сессии');
|
||||
|
||||
if (self::create(
|
||||
[
|
||||
'login' => $session->buffer['entry']['login'],
|
||||
'password' => $session->buffer['entry']['password'] === ''
|
||||
? ''
|
||||
: sodium_crypto_pwhash_str(
|
||||
$session->buffer['entry']['password'],
|
||||
SODIUM_CRYPTO_PWHASH_OPSLIMIT_SENSITIVE,
|
||||
SODIUM_CRYPTO_PWHASH_MEMLIMIT_SENSITIVE
|
||||
)
|
||||
],
|
||||
$errors
|
||||
)) {
|
||||
// Зарегистрирован аккаунт
|
||||
|
||||
if (($account = self::login($session->buffer['entry']['login'], $errors)) instanceof self) {
|
||||
// Найден аккаунт
|
||||
|
||||
// Инициализация инстанции документа аккаунта в базе данных
|
||||
$this->document = $account->document;
|
||||
|
||||
// Связь сессии с аккаунтом
|
||||
$session->connect($this, $errors);
|
||||
|
||||
// Удаление использованных данных из буфера сессии
|
||||
$session->write(['entry' => ['password' => null, 'invite' => null]]);
|
||||
|
||||
return $this;
|
||||
} else throw new exception('Не удалось аутентифицировать аккаунт после его регистрации');
|
||||
} else throw new exception('Не удалось зарегистрировать аккаунт');
|
||||
} else throw new exception('Не найден ключ приглашения в буфере сессии');
|
||||
}
|
||||
}
|
||||
} else throw new exception('Не найден входной псевдоним в буфере сессии');
|
||||
} else throw new exception('Не найдены данные для идентификации');
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (exception $e) {
|
||||
// Запись в реестр ошибок
|
||||
$errors[] = [
|
||||
'text' => $e->getMessage(),
|
||||
'file' => $e->getFile(),
|
||||
'line' => $e->getLine(),
|
||||
'stack' => $e->getTrace()
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Найти по входному псевдониму
|
||||
*
|
||||
* @param string $login Входной псевдоним
|
||||
* @param array &$errors Журнал ошибок
|
||||
* @param array &$errors Реестр ошибок
|
||||
*
|
||||
* @return ?self Инстанция аккаунта, если найден
|
||||
* @return ?self Инстанция аккаунта, если аутентифицирован
|
||||
*/
|
||||
public static function read(string $login, array &$errors = []): ?self
|
||||
public static function login(string $login, array &$errors = []): ?self
|
||||
{
|
||||
try {
|
||||
if (collection::init(static::$db->session, self::COLLECTION)) {
|
||||
@@ -52,26 +192,25 @@ final class account extends core
|
||||
// Инициализация инстанции аккаунта
|
||||
$instance = new self;
|
||||
|
||||
// Поиск аккаунта
|
||||
$instance->instance = collection::search(
|
||||
// Поиск инстанции аккаунта в базе данных
|
||||
$instance->document = collection::search(
|
||||
static::$db->session,
|
||||
sprintf(
|
||||
<<<AQL
|
||||
<<<'AQL'
|
||||
FOR d IN %s
|
||||
FILTER d.login == '%s'
|
||||
RETURN d
|
||||
FILTER d.login == '%s'
|
||||
RETURN d
|
||||
AQL,
|
||||
self::COLLECTION,
|
||||
$login
|
||||
)
|
||||
);
|
||||
|
||||
return $instance;
|
||||
}
|
||||
|
||||
throw new exception('Не удалось инициализировать коллекцию');
|
||||
if ($instance->document instanceof _document) return $instance;
|
||||
else throw new exception('Не удалось найти инстанцию аккаунта в базе данных');
|
||||
} else throw new exception('Не удалось инициализировать коллекцию');
|
||||
} catch (exception $e) {
|
||||
// Запись в журнал ошибок
|
||||
// Запись в реестр ошибок
|
||||
$errors[] = [
|
||||
'text' => $e->getMessage(),
|
||||
'file' => $e->getFile(),
|
||||
@@ -86,75 +225,20 @@ final class account extends core
|
||||
/**
|
||||
* Создать
|
||||
*
|
||||
* @param array &$errors Журнал ошибок
|
||||
* @param array $data Данные аккаунта
|
||||
* @param array &$errors Реестр ошибок
|
||||
*
|
||||
* @return ?_document Инстанция аккаунта, если удалось создать
|
||||
* @return bool Создан аккаунт?
|
||||
*/
|
||||
public static function create(array &$errors = []): ?_document
|
||||
public static function create(array $data = [], array &$errors = []): bool
|
||||
{
|
||||
try {
|
||||
if (collection::init(static::$db->session, self::COLLECTION)) {
|
||||
// Инициализирована коллекция
|
||||
|
||||
// Запись аккаунта в базу данных
|
||||
$_id = document::write(static::$db->session, self::COLLECTION);
|
||||
|
||||
if ($account = collection::search(static::$db->session, sprintf(
|
||||
<<<AQL
|
||||
FOR d IN %s
|
||||
FILTER d._id == '$_id'
|
||||
RETURN d
|
||||
AQL,
|
||||
self::COLLECTION
|
||||
))) {
|
||||
// Найден созданный аккаунт
|
||||
|
||||
return $account;
|
||||
} else throw new exception('Не удалось создать аккаунт');
|
||||
} else throw new exception('Не удалось инициализировать коллекцию');
|
||||
if (collection::init(static::$db->session, self::COLLECTION))
|
||||
if (document::write(static::$db->session, self::COLLECTION, $data)) return true;
|
||||
else throw new exception('Не удалось создать аккаунт');
|
||||
else throw new exception('Не удалось инициализировать коллекцию');
|
||||
} catch (exception $e) {
|
||||
// Запись в журнал ошибок
|
||||
$errors[] = [
|
||||
'text' => $e->getMessage(),
|
||||
'file' => $e->getFile(),
|
||||
'line' => $e->getLine(),
|
||||
'stack' => $e->getTrace()
|
||||
];
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Связь аккаунта с аккаунтом ВКонтакте
|
||||
*
|
||||
* @param _document $account Инстанция аккаунта
|
||||
* @param _document $vk Инстанция аккаунта ВКонтакте
|
||||
* @param array &$errors Журнал ошибок
|
||||
*
|
||||
* @return bool Статус выполнения
|
||||
*/
|
||||
public static function connect(_document $account, _document $vk, array &$errors = []): bool
|
||||
{
|
||||
try {
|
||||
if (
|
||||
collection::init(static::$db->session, self::COLLECTION)
|
||||
&& collection::init(static::$db->session, vk::COLLECTION)
|
||||
&& collection::init(static::$db->session, self::COLLECTION . '_edge_' . vk::COLLECTION, true)
|
||||
) {
|
||||
// Инициализированы коллекции
|
||||
|
||||
if (document::write(static::$db->session, self::COLLECTION . '_edge_' . vk::COLLECTION, [
|
||||
'_from' => $account->getId(),
|
||||
'_to' => $vk->getId()
|
||||
])) {
|
||||
// Создано ребро: account -> vk
|
||||
|
||||
return true;
|
||||
} else throw new exception('Не удалось создать ребро: account -> vk');
|
||||
} else throw new exception('Не удалось инициализировать коллекцию');
|
||||
} catch (exception $e) {
|
||||
// Запись в журнал ошибок
|
||||
// Запись в реестр ошибок
|
||||
$errors[] = [
|
||||
'text' => $e->getMessage(),
|
||||
'file' => $e->getFile(),
|
||||
@@ -167,56 +251,72 @@ final class account extends core
|
||||
}
|
||||
|
||||
/**
|
||||
* Поиск связанного аккаунта ВКонтакте
|
||||
* Записать
|
||||
*
|
||||
* @param _document $account Инстанция аккаунта
|
||||
* @param array &$errors Журнал ошибок
|
||||
* Записывает свойство в инстанцию документа аккаунта из базы данных
|
||||
*
|
||||
* @return ?_document Инстанция аккаунта, если удалось найти
|
||||
* @param string $name Название
|
||||
* @param mixed $value Содержимое
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public static function vk(_document $account, array &$errors = []): ?_document
|
||||
public function __set(string $name, mixed $value = null): void
|
||||
{
|
||||
try {
|
||||
if (
|
||||
collection::init(static::$db->session, self::COLLECTION)
|
||||
&& collection::init(static::$db->session, vk::COLLECTION)
|
||||
&& collection::init(static::$db->session, self::COLLECTION . '_edge_' . vk::COLLECTION, true)
|
||||
) {
|
||||
// Инициализирована коллекция
|
||||
$this->document->{$name} = $value;
|
||||
}
|
||||
|
||||
if ($vk = collection::search(static::$db->session, sprintf(
|
||||
<<<AQL
|
||||
FOR document IN %s
|
||||
LET edge = (
|
||||
FOR edge IN %s
|
||||
FILTER edge._from == '%s'
|
||||
SORT edge._key DESC
|
||||
LIMIT 1
|
||||
RETURN edge
|
||||
)
|
||||
FILTER document._id == edge[0]._to
|
||||
LIMIT 1
|
||||
RETURN document
|
||||
AQL,
|
||||
vk::COLLECTION,
|
||||
self::COLLECTION . '_edge_' . vk::COLLECTION,
|
||||
$account->getId()
|
||||
))) {
|
||||
// Найден аккаунт ВКонтакте
|
||||
/**
|
||||
* Прочитать
|
||||
*
|
||||
* Читает свойство из инстанции документа аккаунта из базы данных
|
||||
*
|
||||
* @param string $name Название
|
||||
*
|
||||
* @return mixed Данные свойства инстанции аккаунта или инстанции документа аккаунта из базы данных
|
||||
*/
|
||||
public function __get(string $name): mixed
|
||||
{
|
||||
return $this->document->{$name};
|
||||
}
|
||||
|
||||
return $vk;
|
||||
} else throw new exception('Не удалось найти аккаунт ВКонтакте');
|
||||
} else throw new exception('Не удалось инициализировать коллекцию');
|
||||
} catch (exception $e) {
|
||||
// Запись в журнал ошибок
|
||||
$errors[] = [
|
||||
'text' => $e->getMessage(),
|
||||
'file' => $e->getFile(),
|
||||
'line' => $e->getLine(),
|
||||
'stack' => $e->getTrace()
|
||||
];
|
||||
}
|
||||
/**
|
||||
* Проверить инициализированность
|
||||
*
|
||||
* Проверяет инициализированность свойства в инстанции документа аккаунта из базы данных
|
||||
*
|
||||
* @param string $name Название
|
||||
*
|
||||
* @return bool Свойство инициализировано?
|
||||
*/
|
||||
public function __isset(string $name): bool
|
||||
{
|
||||
return isset($this->document->{$name});
|
||||
}
|
||||
|
||||
return null;
|
||||
/**
|
||||
* Удалить
|
||||
*
|
||||
* Деинициализировать свойство в инстанции документа аккаунта из базы данных
|
||||
*
|
||||
* @param string $name Название
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __unset(string $name): void
|
||||
{
|
||||
unset($this->document->{$name});
|
||||
}
|
||||
|
||||
/**
|
||||
* Выполнить метод
|
||||
*
|
||||
* Выполнить метод в инстанции документа аккаунта из базы данных
|
||||
*
|
||||
* @param string $name Название
|
||||
* @param array $arguments Аргументы
|
||||
*/
|
||||
public function __call(string $name, array $arguments = [])
|
||||
{
|
||||
if (method_exists($this->document, $name)) return $this->document->{$name}($arguments);
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user