супер попа (обновление)
This commit is contained in:
parent
c8025acc79
commit
30fd8f0ec3
|
@ -36,12 +36,12 @@ final class accounts_controller extends core
|
||||||
public function registration(array $vars = []): ?string
|
public function registration(array $vars = []): ?string
|
||||||
{
|
{
|
||||||
// Инициализация журнала ошибок
|
// Инициализация журнала ошибок
|
||||||
$vars['errors'] = ['account' => []];
|
$vars['errors'] = [];
|
||||||
|
|
||||||
if ($vars['account'] = accounts::registration(email: $vars['email'] ?? null, password: $vars['password'] ?? null, errors: $vars['errors']['account'])) {
|
if ($vars['account'] = accounts::registration(mail: $vars['mail'] ?? null, password: $vars['password'] ?? null, errors: $vars['errors'])) {
|
||||||
// Удалось зарегистрироваться
|
// Удалось зарегистрироваться
|
||||||
|
|
||||||
if ($vars['account'] = accounts::authentication($vars['email'] ?? null, $vars['password'] ?? null, (bool) ($vars['remember'] ?? false), $vars)) {
|
if ($vars['account'] = accounts::authentication($vars['mail'] ?? null, $vars['password'] ?? null, (bool) ($vars['remember'] ?? false), $vars)) {
|
||||||
// Удалось аутентифицироваться
|
// Удалось аутентифицироваться
|
||||||
} else {
|
} else {
|
||||||
// Не удалось аутентифицироваться
|
// Не удалось аутентифицироваться
|
||||||
|
@ -75,9 +75,9 @@ final class accounts_controller extends core
|
||||||
public function authentication(array $vars = []): ?string
|
public function authentication(array $vars = []): ?string
|
||||||
{
|
{
|
||||||
// Инициализация журнала ошибок
|
// Инициализация журнала ошибок
|
||||||
$vars['errors'] = ['account' => []];
|
$vars['errors'] = [];
|
||||||
|
|
||||||
if ($vars['account'] = accounts::authentication($vars['email'] ?? null, $vars['password'] ?? null, (bool) ($vars['remember'] ?? false), errors: $vars['errors']['account'])) {
|
if ($vars['account'] = accounts::authentication($vars['mail'] ?? null, $vars['password'] ?? null, (bool) ($vars['remember'] ?? false), errors: $vars['errors'])) {
|
||||||
// Удалось аутентифицироваться
|
// Удалось аутентифицироваться
|
||||||
} else {
|
} else {
|
||||||
// Не удалось аутентифицироваться
|
// Не удалось аутентифицироваться
|
||||||
|
@ -105,9 +105,9 @@ final class accounts_controller extends core
|
||||||
public function deauthentication(array $vars = []): ?string
|
public function deauthentication(array $vars = []): ?string
|
||||||
{
|
{
|
||||||
// Инициализация журнала ошибок
|
// Инициализация журнала ошибок
|
||||||
$vars['errors'] = ['account' => []];
|
$vars['errors'] = [];
|
||||||
|
|
||||||
if (accounts::deauthentication(errors: $vars['errors']['account'])) {
|
if (accounts::deauthentication(errors: $vars['errors'])) {
|
||||||
// Удалось деаутентифицироваться
|
// Удалось деаутентифицироваться
|
||||||
|
|
||||||
// Деинициализация аккаунта
|
// Деинициализация аккаунта
|
||||||
|
@ -137,21 +137,21 @@ final class accounts_controller extends core
|
||||||
public function data(array $vars = []): ?string
|
public function data(array $vars = []): ?string
|
||||||
{
|
{
|
||||||
// Инициализация журнала ошибок
|
// Инициализация журнала ошибок
|
||||||
$vars['errors'] = ['account' => []];
|
$vars['errors'] = [];
|
||||||
|
|
||||||
if ($account = accounts::read(['id' => $vars['id']], $vars['errors'])) {
|
if ($account = accounts::read(['id' => $vars['id']], $vars['errors'])) {
|
||||||
// Найдены данные запрашиваемого аккаунта
|
// Найдены данные запрашиваемого аккаунта
|
||||||
|
|
||||||
// Инициализация аккаунта
|
// Инициализация аккаунта
|
||||||
$vars['account'] = accounts::account($vars['errors']);
|
$vars['account'] = accounts::init(errors: $vars['errors']);
|
||||||
|
|
||||||
if ($vars['account'] && $vars['account']['permissions']['accounts'] ?? 0 === 1) {
|
if ($vars['account'] && $vars['account']->permissions['accounts'] ?? 0 === 1) {
|
||||||
// Удалось аутентифицироваться и пройдена проверка авторизации
|
// Удалось аутентифицироваться и пройдена проверка авторизации
|
||||||
} else {
|
} else {
|
||||||
// Не удалось аутентифицироваться
|
// Не удалось аутентифицироваться
|
||||||
|
|
||||||
// Удаление запрещённых к публикации полей
|
// Удаление запрещённых к публикации полей
|
||||||
$account['password'] = $account['hash'] = $account['time'] = null;
|
$account->password = $account->hash = $account->time = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Генерация ответа
|
// Генерация ответа
|
||||||
|
|
|
@ -18,29 +18,30 @@ use mirzaev\surikovlib\models\books_model as books;
|
||||||
final class books_controller extends core
|
final class books_controller extends core
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Страница с библеотекой
|
* Страница с книгами (или книгой)
|
||||||
*
|
*
|
||||||
* @param array $vars
|
* @param array $vars
|
||||||
*/
|
*/
|
||||||
public function index(array $vars = []): ?string
|
public function index(array $vars = []): ?string
|
||||||
{
|
{
|
||||||
// Проверка аутентифицированности
|
// Инициализация журнала ошибок
|
||||||
$vars['account'] = accounts::account($vars);
|
$vars['errors'] = [];
|
||||||
|
|
||||||
if (!empty($vars['id'])) {
|
// Проверка аутентифицированности
|
||||||
|
$vars['account'] = accounts::init(errors: $vars['errors']);
|
||||||
|
|
||||||
|
if (isset($vars['id'])) {
|
||||||
// Определённая книга
|
// Определённая книга
|
||||||
|
|
||||||
// Чтение книги
|
// Чтение метаданных книги
|
||||||
$vars['book'] = books::read(['id' => $vars['id']])[0] ?? null;
|
$vars['book'] = books::read(['id' => $vars['id']])[0] ?? null;
|
||||||
|
|
||||||
if (empty($vars['book'])) {
|
// Инициализация страницы
|
||||||
// Не найдена книга
|
if (empty($vars['page']) || $vars['page'] < 0) $vars['page'] = 0;
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Генерация представления
|
// Генерация представления
|
||||||
return $this->view->render(DIRECTORY_SEPARATOR . 'books' . DIRECTORY_SEPARATOR . 'book.html', $vars);
|
return $this->view->render(DIRECTORY_SEPARATOR . 'books' . DIRECTORY_SEPARATOR . 'book.html', $vars);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
// Все книги
|
// Все книги
|
||||||
|
|
||||||
|
@ -52,40 +53,6 @@ final class books_controller extends core
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Обложка
|
|
||||||
*
|
|
||||||
* @param array $vars
|
|
||||||
*
|
|
||||||
* @return string|null Файл, если найден
|
|
||||||
*/
|
|
||||||
public function cover(array $vars = []): ?string
|
|
||||||
{
|
|
||||||
// Проверка входных параметров
|
|
||||||
if (empty($vars['id'])) return null;
|
|
||||||
|
|
||||||
// Инициализация пути до файла
|
|
||||||
$file = \STORAGE . DIRECTORY_SEPARATOR . 'books' . DIRECTORY_SEPARATOR . $vars['id'] . DIRECTORY_SEPARATOR . '0.jpg';
|
|
||||||
|
|
||||||
if (file_exists($file)) {
|
|
||||||
// Найден файл
|
|
||||||
|
|
||||||
// Настройка заголовков
|
|
||||||
header('Content-Description: File Transfer');
|
|
||||||
header('Content-Type: image/jpeg');
|
|
||||||
header('Content-Disposition: attachment; filename=' . basename($file));
|
|
||||||
header('Content-Transfer-Encoding: binary');
|
|
||||||
header('Content-Length: ' . filesize($file));
|
|
||||||
|
|
||||||
// Очистить буфер вывода
|
|
||||||
ob_end_clean();
|
|
||||||
|
|
||||||
return file_get_contents($file);
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Запись
|
* Запись
|
||||||
*
|
*
|
||||||
|
@ -96,59 +63,54 @@ final class books_controller extends core
|
||||||
*/
|
*/
|
||||||
public function write(array $vars = [], array $files = []): ?string
|
public function write(array $vars = [], array $files = []): ?string
|
||||||
{
|
{
|
||||||
// ПЕРЕНЕСТИ В МОДЕЛЬ
|
// Инициализация журнала ошибок
|
||||||
|
$vars['errors'] = [];
|
||||||
|
|
||||||
// Инициализация буфера сохранённых книг
|
if (count($books = books::import($files['books'] ?? [], errors: $vars['errors'])) > 0) {
|
||||||
$books = [];
|
// Загружены книги
|
||||||
|
} else {
|
||||||
for ($i = -1; count($files['books']['name']) > ++$i;) {
|
// Не загружены книги
|
||||||
// Перебор загруженных книг
|
|
||||||
|
|
||||||
// Генерация хеша файла
|
|
||||||
$hash = hash_file('md5', $files['books']['tmp_name'][$i]) ?? 0;
|
|
||||||
|
|
||||||
if (move_uploaded_file($files['books']['tmp_name'][$i], \STORAGE . DIRECTORY_SEPARATOR . 'temp' . DIRECTORY_SEPARATOR . $hash . '_' . $files['books']['name'][$i])) {
|
|
||||||
// Загружен и перемещён из временной папки файл с книгой
|
|
||||||
|
|
||||||
// Запись в буфер сохранённых книг
|
|
||||||
$books[] = $hash . '_' . $files['books']['name'][$i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach ($books as $book) {
|
|
||||||
// Перебор сохранённых книг
|
|
||||||
|
|
||||||
// Запись в базу данных
|
|
||||||
|
|
||||||
|
|
||||||
// Инициализация пути до хранилища
|
|
||||||
$storage = \STORAGE . DIRECTORY_SEPARATOR . 'books' . DIRECTORY_SEPARATOR . 'id' . DIRECTORY_SEPARATOR;
|
|
||||||
|
|
||||||
// Извлечение изображений из PDF-документа
|
|
||||||
exec("cd $storage && pdfimages -j $book");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Перенаправление
|
// Перенаправление
|
||||||
header('Location: /books', response_code: 303);
|
header('Location: /books', response_code: 303);
|
||||||
|
|
||||||
return null;
|
return 'wtf';
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Чтение
|
* Чтение
|
||||||
*
|
*
|
||||||
* @param array $vars Параметры запроса
|
* @param array $vars
|
||||||
*
|
*
|
||||||
* @return string|null HTML-документ
|
* @return string|null Файл, если найден
|
||||||
*/
|
*/
|
||||||
public function read(array $vars = []): ?string
|
public function read(array $vars = []): ?string
|
||||||
{
|
{
|
||||||
if (accounts::deauthentication($vars)) {
|
if (isset($vars['id'], $vars['file'])) {
|
||||||
// Удалось деаутентифицироваться
|
// Найдены обязательные входные параметры
|
||||||
|
|
||||||
|
// Инициализация пути до файла
|
||||||
|
$file = \STORAGE . DIRECTORY_SEPARATOR . 'books' . DIRECTORY_SEPARATOR . $vars['id'] . DIRECTORY_SEPARATOR . $vars['file'] . '.jpg';
|
||||||
|
|
||||||
|
if (file_exists($file)) {
|
||||||
|
// Найден файл
|
||||||
|
|
||||||
|
// Настройка заголовков
|
||||||
|
header('Content-Description: File Transfer');
|
||||||
|
header('Content-Type: image/jpeg');
|
||||||
|
header('Content-Disposition: attachment; filename=' . basename($file));
|
||||||
|
header('Content-Transfer-Encoding: binary');
|
||||||
|
header('Content-Length: ' . filesize($file));
|
||||||
|
|
||||||
|
// Очистить буфер вывода
|
||||||
|
ob_end_clean();
|
||||||
|
|
||||||
|
return file_get_contents($file);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Генерация представления
|
return null;
|
||||||
return $this->view->render(DIRECTORY_SEPARATOR . 'main' . DIRECTORY_SEPARATOR . 'index.html', $vars);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -160,11 +122,5 @@ final class books_controller extends core
|
||||||
*/
|
*/
|
||||||
public function delete(array $vars = []): ?string
|
public function delete(array $vars = []): ?string
|
||||||
{
|
{
|
||||||
if (accounts::deauthentication($vars)) {
|
|
||||||
// Удалось деаутентифицироваться
|
|
||||||
}
|
|
||||||
|
|
||||||
// Генерация представления
|
|
||||||
return $this->view->render(DIRECTORY_SEPARATOR . 'main' . DIRECTORY_SEPARATOR . 'index.html', $vars);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,8 +20,11 @@ final class main_controller extends core
|
||||||
{
|
{
|
||||||
public function index(array $vars = []): ?string
|
public function index(array $vars = []): ?string
|
||||||
{
|
{
|
||||||
|
// Инициализация журнала ошибок
|
||||||
|
$vars['errors'] = [];
|
||||||
|
|
||||||
// Проверка аутентифицированности
|
// Проверка аутентифицированности
|
||||||
$vars['account'] = accounts::account($vars);
|
$vars['account'] = accounts::init(errors: $vars['errors']);
|
||||||
|
|
||||||
// Генерация представления
|
// Генерация представления
|
||||||
return $this->view->render(DIRECTORY_SEPARATOR . 'main' . DIRECTORY_SEPARATOR . 'index.html', $vars);
|
return $this->view->render(DIRECTORY_SEPARATOR . 'main' . DIRECTORY_SEPARATOR . 'index.html', $vars);
|
||||||
|
|
|
@ -15,33 +15,86 @@ use exception;
|
||||||
*/
|
*/
|
||||||
final class accounts_model extends core
|
final class accounts_model extends core
|
||||||
{
|
{
|
||||||
|
/**
|
||||||
|
* Идентификатор
|
||||||
|
*/
|
||||||
|
public int $id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Почта
|
||||||
|
*/
|
||||||
|
public string $mail;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Пароль
|
||||||
|
*/
|
||||||
|
public string $password;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Хеш
|
||||||
|
*/
|
||||||
|
public string $hash;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Время активности хеша
|
||||||
|
*/
|
||||||
|
public int $time;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Время активности хеша
|
||||||
|
*/
|
||||||
|
public array $permissions;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Конструктор
|
||||||
|
*
|
||||||
|
* @param array $vars Параметры
|
||||||
|
*/
|
||||||
|
public function __construct(array $vars = []) {
|
||||||
|
foreach ($vars as $key => $value) {
|
||||||
|
// Перебор параметров
|
||||||
|
|
||||||
|
// Запись свойства
|
||||||
|
if (property_exists($this, $key)) $this->$key = $value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Регистрация
|
* Регистрация
|
||||||
*
|
*
|
||||||
* @param string $name Входной псевдоним
|
* @param string $mail Почта
|
||||||
* @param string $email Почта
|
* @param string $password Пароль
|
||||||
* @param string $password Пароль (password)
|
* @param bool $authenticate Автоматическая аутентификация в случае успешной регистрации
|
||||||
* @param bool $authentication Автоматическая аутентификация в случае успешной регистрации
|
|
||||||
* @param array &$errors Журнал ошибок
|
* @param array &$errors Журнал ошибок
|
||||||
*
|
*
|
||||||
* @return array|bool Аккаунт, если удалось аутентифицироваться
|
* @return static|null Аккаунт
|
||||||
*/
|
*/
|
||||||
public static function registration(string $name = null, string $email = null, string $password, array &$errors = []): array
|
public static function registration(string $mail, string $password, bool $authenticate = true, array &$errors = []): ?static
|
||||||
{
|
{
|
||||||
|
// Инициализация журнала ошибок
|
||||||
|
$errors['account'] ?? $errors['account'] = [];
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (static::account($errors)) {
|
if (static::init(errors: $errors)) {
|
||||||
// Аутентифицирован пользователь
|
// Аутентифицирован пользователь
|
||||||
|
|
||||||
// Запись ошибки
|
// Запись ошибки
|
||||||
throw new exception('Уже аутентифицирован');
|
throw new exception('Уже аутентифицирован');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (empty($account = static::read(['name' => $name]) or $account = static::read(['email' => $email]))) {
|
if (empty($account = static::read(['mail' => $mail]))) {
|
||||||
// Не удалось найти аккаунт
|
// Не удалось найти аккаунт
|
||||||
|
|
||||||
if (static::write($name, $email, $password, $errors)) {
|
if (static::write($mail, $password, $errors)) {
|
||||||
// Удалось зарегистрироваться
|
// Удалось зарегистрироваться
|
||||||
|
|
||||||
|
if ($authenticate) {
|
||||||
|
// Запрошена аутентификация
|
||||||
|
|
||||||
|
// Аутентификация
|
||||||
|
$account = static::authentication($mail, $password, true, $errors);
|
||||||
|
}
|
||||||
|
|
||||||
return $account;
|
return $account;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -51,7 +104,7 @@ final class accounts_model extends core
|
||||||
}
|
}
|
||||||
} catch (exception $e) {
|
} catch (exception $e) {
|
||||||
// Запись в журнал ошибок
|
// Запись в журнал ошибок
|
||||||
$errors[]= [
|
$errors['account'][] = [
|
||||||
'text' => $e->getMessage(),
|
'text' => $e->getMessage(),
|
||||||
'file' => $e->getFile(),
|
'file' => $e->getFile(),
|
||||||
'line' => $e->getLine(),
|
'line' => $e->getLine(),
|
||||||
|
@ -59,41 +112,44 @@ final class accounts_model extends core
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
return [];
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Аутентификация
|
* Аутентификация
|
||||||
*
|
*
|
||||||
* @param string $login Входной псевдоним
|
* @param string $mail Почта
|
||||||
* @param string $password Пароль (password)
|
* @param string $password Пароль
|
||||||
* @param bool $remember Функция "Запомнить меня" - увеличенное время хранения cookies
|
* @param bool $remember Функция "Запомнить меня" - увеличенное время хранения cookies
|
||||||
* @param array &$errors Журнал ошибок
|
* @param array &$errors Журнал ошибок
|
||||||
*
|
*
|
||||||
* @return array Аккаунт (если не найден, то пустой массив)
|
* @return static|null Аккаунт
|
||||||
*/
|
*/
|
||||||
public static function authentication(string $login, string $password, bool $remember = false, array &$errors = []): array
|
public static function authentication(string $mail, string $password, bool $remember = false, array &$errors = []): ?static
|
||||||
{
|
{
|
||||||
|
// Инициализация журнала ошибок
|
||||||
|
$errors['account'] ?? $errors['account'] = [];
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (static::account($errors)) {
|
if (static::init(errors: $errors)) {
|
||||||
// Аутентифицирован пользователь
|
// Аутентифицирован пользователь
|
||||||
|
|
||||||
// Запись ошибки
|
// Запись ошибки
|
||||||
throw new exception('Уже аутентифицирован');
|
throw new exception('Уже аутентифицирован');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (empty($account = static::read(['mail' => $mail]))) {
|
||||||
if (empty($account = static::read(['name' => $login]) or $account = static::read(['email' => $login]))) {
|
|
||||||
// Не удалось найти аккаунт
|
// Не удалось найти аккаунт
|
||||||
|
|
||||||
throw new exception('Не удалось найти аккаунт');
|
throw new exception('Не удалось найти аккаунт');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (password_verify($password, $account['password'])) {
|
|
||||||
|
if (password_verify($password, $account->password)) {
|
||||||
// Совпадают хеши паролей
|
// Совпадают хеши паролей
|
||||||
|
|
||||||
// Инициализация идентификатора сессии
|
// Инициализация идентификатора сессии
|
||||||
session_id($account['id']);
|
session_id((string) $account->id);
|
||||||
|
|
||||||
// Инициализация названия сессии
|
// Инициализация названия сессии
|
||||||
session_name('id');
|
session_name('id');
|
||||||
|
@ -105,10 +161,10 @@ final class accounts_model extends core
|
||||||
$time = time() + ($remember ? 604800 : 86400);
|
$time = time() + ($remember ? 604800 : 86400);
|
||||||
|
|
||||||
// Инициализация хеша
|
// Инициализация хеша
|
||||||
$hash = static::hash((int) $account['id'], crypt($account['password'], time() . $account['id']), $time, $errors)['hash'];
|
$hash = static::hash((int) $account->id, crypt($account->password, time() . $account->id), $time, $errors)['hash'];
|
||||||
|
|
||||||
// Инициализация cookies
|
// Инициализация cookies
|
||||||
setcookie("hash", $hash, $time, path: '/', secure: true);
|
setcookie('hash', $hash, $time, path: '/', secure: true);
|
||||||
|
|
||||||
return $account;
|
return $account;
|
||||||
} else {
|
} else {
|
||||||
|
@ -118,7 +174,7 @@ final class accounts_model extends core
|
||||||
}
|
}
|
||||||
} catch (exception $e) {
|
} catch (exception $e) {
|
||||||
// Запись в журнал ошибок
|
// Запись в журнал ошибок
|
||||||
$errors[]= [
|
$errors['account'][] = [
|
||||||
'text' => $e->getMessage(),
|
'text' => $e->getMessage(),
|
||||||
'file' => $e->getFile(),
|
'file' => $e->getFile(),
|
||||||
'line' => $e->getLine(),
|
'line' => $e->getLine(),
|
||||||
|
@ -126,7 +182,7 @@ final class accounts_model extends core
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
return [];
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -138,8 +194,11 @@ final class accounts_model extends core
|
||||||
*/
|
*/
|
||||||
public static function deauthentication(array &$errors = []): bool
|
public static function deauthentication(array &$errors = []): bool
|
||||||
{
|
{
|
||||||
|
// Инициализация журнала ошибок
|
||||||
|
$errors['account'] ?? $errors['account'] = [];
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if ($account = static::account($errors)) {
|
if ($account = static::init(errors: $errors)) {
|
||||||
// Аутентифицирован пользователь
|
// Аутентифицирован пользователь
|
||||||
|
|
||||||
// Инициализация запроса
|
// Инициализация запроса
|
||||||
|
@ -147,7 +206,7 @@ final class accounts_model extends core
|
||||||
|
|
||||||
// Параметры запроса
|
// Параметры запроса
|
||||||
$params = [
|
$params = [
|
||||||
":id" => $account['id'],
|
":id" => $account->id,
|
||||||
];
|
];
|
||||||
|
|
||||||
// Отправка запроса
|
// Отправка запроса
|
||||||
|
@ -157,8 +216,8 @@ final class accounts_model extends core
|
||||||
$request->fetch(pdo::FETCH_ASSOC);
|
$request->fetch(pdo::FETCH_ASSOC);
|
||||||
|
|
||||||
// Деинициализация cookies
|
// Деинициализация cookies
|
||||||
setcookie("id", '', 0, path: '/', secure: true);
|
setcookie('id', '', 0, path: '/', secure: true);
|
||||||
setcookie("hash", '', 0, path: '/', secure: true);
|
setcookie('hash', '', 0, path: '/', secure: true);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
|
@ -169,7 +228,7 @@ final class accounts_model extends core
|
||||||
}
|
}
|
||||||
} catch (exception $e) {
|
} catch (exception $e) {
|
||||||
// Запись в журнал ошибок
|
// Запись в журнал ошибок
|
||||||
$errors[]= [
|
$errors['account'][] = [
|
||||||
'text' => $e->getMessage(),
|
'text' => $e->getMessage(),
|
||||||
'file' => $e->getFile(),
|
'file' => $e->getFile(),
|
||||||
'line' => $e->getLine(),
|
'line' => $e->getLine(),
|
||||||
|
@ -181,21 +240,30 @@ final class accounts_model extends core
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Прочитать данные аккаунта, если пользователь аутентифицирован
|
* Инициализация
|
||||||
*
|
|
||||||
* Можно использовать как проверку на аутентифицированность
|
|
||||||
*
|
*
|
||||||
|
* @param int|null $account Аккаунт (идентификатор)
|
||||||
* @param array &$errors Журнал ошибок
|
* @param array &$errors Журнал ошибок
|
||||||
*
|
*
|
||||||
* @return array Аккаунт (если не найден, то пустой массив)
|
* @return static|null Аккаунт
|
||||||
*
|
|
||||||
* @todo 1. Сделать в static::read() возможность передачи нескольких параметров и перенести туда непосредственно чтение аккаунта с проверкой хеша
|
|
||||||
*/
|
*/
|
||||||
public static function account(array &$errors = []): array
|
public static function init(?int $account = null, array &$errors = []): ?static
|
||||||
{
|
{
|
||||||
|
// Инициализация журнала ошибок
|
||||||
|
$errors['account'] ?? $errors['account'] = [];
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (!empty($_COOKIE['id']) && !empty($_COOKIE['hash'])) {
|
if (isset($account)) {
|
||||||
// Аутентифицирован аккаунт (найдены cookie и они хранят значения - подразумевается, что не null или пустое)
|
// Получен идентификатор аккаунта
|
||||||
|
|
||||||
|
if (empty($account = static::read(['id' => $account]))) {
|
||||||
|
// Не найден аккаунт
|
||||||
|
|
||||||
|
// Генерация ошибки
|
||||||
|
throw new exception('Не найден пользователь');
|
||||||
|
}
|
||||||
|
} else if (!empty($_COOKIE['id']) && !empty($_COOKIE['hash'])) {
|
||||||
|
// Найдены cookie с данными аккаунта (подразумевается, что он аутентифицирован)
|
||||||
|
|
||||||
if ($_COOKIE['hash'] === static::hash((int) $_COOKIE['id'], errors: $errors)['hash']) {
|
if ($_COOKIE['hash'] === static::hash((int) $_COOKIE['id'], errors: $errors)['hash']) {
|
||||||
// Совпадает переданный хеш с тем, что хранится в базе данных
|
// Совпадает переданный хеш с тем, что хранится в базе данных
|
||||||
|
@ -206,34 +274,28 @@ final class accounts_model extends core
|
||||||
throw new exception('Вы аутентифицированы с другого устройства (не совпадают хеши аутентификации)');
|
throw new exception('Вы аутентифицированы с другого устройства (не совпадают хеши аутентификации)');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Инициализация запроса
|
if (empty($account = static::read([
|
||||||
$request = static::$db->prepare("SELECT * FROM `accounts` WHERE `id` = :id && `hash` = :hash");
|
'id' => $_COOKIE['id'],
|
||||||
|
'hash' => $_COOKIE['hash']
|
||||||
// Параметры запроса
|
]))) {
|
||||||
$params = [
|
// Не найден аккаунт или связка аккаунта с хешем
|
||||||
":id" => $_COOKIE['id'],
|
|
||||||
":hash" => $_COOKIE['hash'],
|
|
||||||
];
|
|
||||||
|
|
||||||
// Отправка запроса
|
|
||||||
$request->execute($params);
|
|
||||||
|
|
||||||
// Генерация ответа
|
|
||||||
if (empty($account = $request->fetch(pdo::FETCH_ASSOC))) {
|
|
||||||
// Не найдена связка идентификатора с хешем
|
|
||||||
|
|
||||||
// Генерация ошибки
|
// Генерация ошибки
|
||||||
throw new exception('Не найден пользотватель или время аутентификации истекло');
|
throw new exception('Не найден пользователь или время аутентификации истекло');
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
// Не найдены параметры для поиска аккаунта
|
||||||
|
|
||||||
// Чтение разрешений
|
return null;
|
||||||
$account['permissions'] = static::permissions((int) $account['id'], $errors);
|
|
||||||
|
|
||||||
return $account;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Чтение разрешений
|
||||||
|
$account->permissions = static::permissions((int) $account->id, $errors);
|
||||||
|
|
||||||
|
return $account;
|
||||||
} catch (exception $e) {
|
} catch (exception $e) {
|
||||||
// Запись в журнал ошибок
|
// Запись в журнал ошибок
|
||||||
$errors[]= [
|
$errors['account'][]= [
|
||||||
'text' => $e->getMessage(),
|
'text' => $e->getMessage(),
|
||||||
'file' => $e->getFile(),
|
'file' => $e->getFile(),
|
||||||
'line' => $e->getLine(),
|
'line' => $e->getLine(),
|
||||||
|
@ -241,11 +303,12 @@ final class accounts_model extends core
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
return [];
|
return null;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Прочитать разрешения аккаунта
|
* Прочитать разрешения из базы данных
|
||||||
*
|
*
|
||||||
* @param int $id Идентификатор аккаунта
|
* @param int $id Идентификатор аккаунта
|
||||||
* @param array &$errors Журнал ошибок
|
* @param array &$errors Журнал ошибок
|
||||||
|
@ -254,6 +317,9 @@ final class accounts_model extends core
|
||||||
*/
|
*/
|
||||||
public static function permissions(int $id, array &$errors = []): array
|
public static function permissions(int $id, array &$errors = []): array
|
||||||
{
|
{
|
||||||
|
// Инициализация журнала ошибок
|
||||||
|
$errors['account'] ?? $errors['account'] = [];
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Инициализация запроса
|
// Инициализация запроса
|
||||||
$request = static::$db->prepare("SELECT * FROM `permissions` WHERE `id` = :id");
|
$request = static::$db->prepare("SELECT * FROM `permissions` WHERE `id` = :id");
|
||||||
|
@ -280,7 +346,7 @@ final class accounts_model extends core
|
||||||
return $response;
|
return $response;
|
||||||
} catch (exception $e) {
|
} catch (exception $e) {
|
||||||
// Запись в журнал ошибок
|
// Запись в журнал ошибок
|
||||||
$errors[]= [
|
$errors['account'][] = [
|
||||||
'text' => $e->getMessage(),
|
'text' => $e->getMessage(),
|
||||||
'file' => $e->getFile(),
|
'file' => $e->getFile(),
|
||||||
'line' => $e->getLine(),
|
'line' => $e->getLine(),
|
||||||
|
@ -302,14 +368,17 @@ final class accounts_model extends core
|
||||||
*/
|
*/
|
||||||
public static function access(string $permission, int|null $id = null, array &$errors = []): ?bool
|
public static function access(string $permission, int|null $id = null, array &$errors = []): ?bool
|
||||||
{
|
{
|
||||||
|
// Инициализация журнала ошибок
|
||||||
|
$errors['account'] ?? $errors['account'] = [];
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Инициализация аккаунта
|
// Инициализация аккаунта
|
||||||
$account = isset($id) ? self::read(['id' => $id], $errors) : self::account($errors);
|
$account = isset($id) ? self::read(['id' => $id], $errors) : self::account($errors);
|
||||||
|
|
||||||
return isset($account['permissions'][$permission]) ? (bool) $account['permissions'][$permission] : null;
|
return isset($account->permissions[$permission]) ? (bool) $account->permissions[$permission] : null;
|
||||||
} catch (exception $e) {
|
} catch (exception $e) {
|
||||||
// Запись в журнал ошибок
|
// Запись в журнал ошибок
|
||||||
$errors[]= [
|
$errors['account'][]= [
|
||||||
'text' => $e->getMessage(),
|
'text' => $e->getMessage(),
|
||||||
'file' => $e->getFile(),
|
'file' => $e->getFile(),
|
||||||
'line' => $e->getLine(),
|
'line' => $e->getLine(),
|
||||||
|
@ -321,114 +390,57 @@ final class accounts_model extends core
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Запись пользователя в базу данных
|
* Запись в базу данных
|
||||||
*
|
*
|
||||||
* @param string|null $name Имя
|
* @param string $mail Почта
|
||||||
* @param string|null $email Почта
|
* @param string $password Пароль
|
||||||
* @param string|null $password Пароль
|
|
||||||
* @param array &$errors Журнал ошибок
|
* @param array &$errors Журнал ошибок
|
||||||
*
|
*
|
||||||
* @return array Аккаунт (если не найден, то пустой массив)
|
* @return static|null Аккаунт
|
||||||
*/
|
*/
|
||||||
public static function write(string|null $name = null, string|null $email = null, string|null $password = null, array &$errors = []): array
|
public static function write(string $mail, string $password, array &$errors = []): ?static
|
||||||
{
|
{
|
||||||
|
// Инициализация журнала ошибок
|
||||||
|
$errors['account'] ?? $errors['account'] = [];
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Инициализация параметров запроса
|
// Инициализация параметров запроса
|
||||||
$params = [];
|
$params = [];
|
||||||
|
|
||||||
if (isset($name)) {
|
|
||||||
try {
|
|
||||||
// Проверка параметра
|
|
||||||
if (iconv_strlen($name) < 3) throw new exception('Длина имени должна быть не менее 3 символов');
|
|
||||||
if (iconv_strlen($name) > 60) throw new exception('Длина имени должна быть не более 60 символов');
|
|
||||||
|
|
||||||
// Запись в буфер параметров запроса
|
|
||||||
$params[':name'] = $name;
|
|
||||||
} catch (exception $e) {
|
|
||||||
// Запись в журнал ошибок
|
|
||||||
$errors[] = [
|
|
||||||
'text' => $e->getMessage(),
|
|
||||||
'file' => $e->getFile(),
|
|
||||||
'line' => $e->getLine()
|
|
||||||
];
|
|
||||||
|
|
||||||
goto end;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isset($email)) {
|
|
||||||
try {
|
|
||||||
// Проверка параметра
|
|
||||||
if (filter_var($email, FILTER_VALIDATE_EMAIL) === false) throw new exception('Не удалось распознать почту');
|
|
||||||
if (iconv_strlen($email) < 3) throw new exception('Длина почты должна быть не менее 3 символов');
|
|
||||||
if (iconv_strlen($email) > 60) throw new exception('Длина почты должна быть не более 80 символов');
|
|
||||||
|
|
||||||
// Запись в буфер параметров запроса
|
|
||||||
$params[':email'] = $email;
|
|
||||||
} catch (exception $e) {
|
|
||||||
// Запись в журнал ошибок
|
|
||||||
$errors[] = [
|
|
||||||
'text' => $e->getMessage(),
|
|
||||||
'file' => $e->getFile(),
|
|
||||||
'line' => $e->getLine()
|
|
||||||
];
|
|
||||||
|
|
||||||
goto end;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isset($password)) {
|
|
||||||
try {
|
|
||||||
// Проверка параметра
|
|
||||||
if (iconv_strlen($password) < 3) throw new exception('Длина пароля должна быть не менее 3 символов');
|
|
||||||
if (iconv_strlen($password) > 60) throw new exception('Длина пароля должна быть не более 120 символов');
|
|
||||||
|
|
||||||
// Запись в буфер параметров запроса
|
|
||||||
$params[':password'] = password_hash($password, PASSWORD_BCRYPT);
|
|
||||||
} catch (exception $e) {
|
|
||||||
// Запись в журнал ошибок
|
|
||||||
$errors[] = [
|
|
||||||
'text' => $e->getMessage(),
|
|
||||||
'file' => $e->getFile(),
|
|
||||||
'line' => $e->getLine()
|
|
||||||
];
|
|
||||||
|
|
||||||
goto end;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Инициализация запроса
|
|
||||||
$request = static::$db->prepare("INSERT INTO `accounts` (" . (isset($name) ? '`name`' : '') . (isset($name) && isset($email) ? ', ' : '') . (isset($email) ? '`email`' : '') . ((isset($name) || isset($email)) && isset($password) ? ', ' : '') . (isset($password) ? '`password`' : '') . ") VALUES (" . (isset($name) ? ':name' : '') . (isset($name) && isset($email) ? ', ' : '') . (isset($email) ? ':email' : '') . ((isset($name) || isset($email)) && isset($password) ? ', ' : '') . (isset($password) ? ':password' : '') . ")");
|
|
||||||
|
|
||||||
// Отправка запроса
|
|
||||||
$request->execute($params);
|
|
||||||
|
|
||||||
// Генерация ответа
|
|
||||||
$request->fetch(pdo::FETCH_ASSOC);
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (isset($name)) {
|
// Проверка параметра
|
||||||
// Передано имя аккаунта
|
if (filter_var($mail, FILTER_VALIDATE_mail) === false) throw new exception('Не удалось распознать почту');
|
||||||
|
if (iconv_strlen($mail) < 3) throw new exception('Длина почты должна быть не менее 3 символов');
|
||||||
|
if (iconv_strlen($mail) > 60) throw new exception('Длина почты должна быть не более 80 символов');
|
||||||
|
|
||||||
// Чтение аккаунта
|
// Запись в буфер параметров запроса
|
||||||
$account = static::read(['name' => $name]);
|
$params[':mail'] = $mail;
|
||||||
} else if (isset($email)) {
|
|
||||||
// Передана почта аккаунта
|
|
||||||
|
|
||||||
// Чтение аккаунта
|
// Проверка параметра
|
||||||
$account = static::read(['email' => $email]);
|
if (iconv_strlen($password) < 3) throw new exception('Длина пароля должна быть не менее 3 символов');
|
||||||
} else {
|
if (iconv_strlen($password) > 60) throw new exception('Длина пароля должна быть не более 120 символов');
|
||||||
// Не передано ни имя, ни почта
|
|
||||||
|
|
||||||
throw new exception('Не переданны данные для полноценной регистрации аккаунта');
|
// Запись в буфер параметров запроса
|
||||||
}
|
$params[':password'] = password_hash($password, PASSWORD_BCRYPT);
|
||||||
|
|
||||||
|
// Инициализация запроса
|
||||||
|
$request = static::$db->prepare("INSERT INTO `accounts` (" . (isset($name) ? '`name`' : '') . (isset($name) && isset($mail) ? ', ' : '') . (isset($mail) ? '`mail`' : '') . ((isset($name) || isset($mail)) && isset($password) ? ', ' : '') . (isset($password) ? '`password`' : '') . ") VALUES (" . (isset($name) ? ':name' : '') . (isset($name) && isset($mail) ? ', ' : '') . (isset($mail) ? ':mail' : '') . ((isset($name) || isset($mail)) && isset($password) ? ', ' : '') . (isset($password) ? ':password' : '') . ")");
|
||||||
|
|
||||||
|
// Отправка запроса
|
||||||
|
$request->execute($params);
|
||||||
|
|
||||||
|
// Генерация ответа
|
||||||
|
$request->fetch(pdo::FETCH_ASSOC);
|
||||||
|
|
||||||
|
// Чтение аккаунта
|
||||||
|
$account = static::read(['mail' => $mail]);
|
||||||
|
|
||||||
// Инициализация запроса
|
// Инициализация запроса
|
||||||
$request = static::$db->prepare("INSERT INTO `permissions` (`id`) VALUES (:id)");
|
$request = static::$db->prepare("INSERT INTO `permissions` (`id`) VALUES (:id)");
|
||||||
|
|
||||||
// Инициализация параметров
|
// Инициализация параметров
|
||||||
$params = [
|
$params = [
|
||||||
':id' => $account['id']
|
':id' => $account->id
|
||||||
];
|
];
|
||||||
|
|
||||||
// Отправка запроса
|
// Отправка запроса
|
||||||
|
@ -438,7 +450,7 @@ final class accounts_model extends core
|
||||||
$request->fetch(pdo::FETCH_ASSOC);
|
$request->fetch(pdo::FETCH_ASSOC);
|
||||||
} catch (exception $e) {
|
} catch (exception $e) {
|
||||||
// Запись в журнал ошибок
|
// Запись в журнал ошибок
|
||||||
$errors[] = [
|
$errors['account'][] = [
|
||||||
'text' => $e->getMessage(),
|
'text' => $e->getMessage(),
|
||||||
'file' => $e->getFile(),
|
'file' => $e->getFile(),
|
||||||
'line' => $e->getLine(),
|
'line' => $e->getLine(),
|
||||||
|
@ -447,7 +459,7 @@ final class accounts_model extends core
|
||||||
}
|
}
|
||||||
} catch (exception $e) {
|
} catch (exception $e) {
|
||||||
// Запись в журнал ошибок
|
// Запись в журнал ошибок
|
||||||
$errors[]= [
|
$errors['account'][] = [
|
||||||
'text' => $e->getMessage(),
|
'text' => $e->getMessage(),
|
||||||
'file' => $e->getFile(),
|
'file' => $e->getFile(),
|
||||||
'line' => $e->getLine(),
|
'line' => $e->getLine(),
|
||||||
|
@ -458,52 +470,58 @@ final class accounts_model extends core
|
||||||
// Конец выполнения
|
// Конец выполнения
|
||||||
end:
|
end:
|
||||||
|
|
||||||
return isset($account) && $account ? $account : [];
|
return $account ?? [];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Чтение пользователя из базы данных
|
* Чтение из базы данных
|
||||||
*
|
*
|
||||||
* @param array $search Поиск ('поле' => 'значение'), работает только с одним полем
|
* @param array $expression Выражение поиска ('поле' => 'значение')
|
||||||
* @param array &$errors Журнал ошибок
|
* @param array &$errors Журнал ошибок
|
||||||
*
|
*
|
||||||
* @return array Аккаунт, если найден
|
* @return static|null Аккаунт
|
||||||
*/
|
*/
|
||||||
public static function read(array $search, array &$errors = []): array
|
public static function read(array $expression, array &$errors = []): ?static
|
||||||
{
|
{
|
||||||
|
// Инициализация журнала ошибок
|
||||||
|
$errors['account'] ?? $errors['account'] = [];
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Инициализация данных для поиска
|
// Инициализация выражения поиска
|
||||||
$field = array_keys($search)[0] ?? null;
|
$where = 'WHERE ';
|
||||||
$value = $search[$field] ?? null;
|
|
||||||
|
|
||||||
if (empty($field)) {
|
// Инициализация параметров запроса
|
||||||
// Получено пустое значение поля
|
$params = [];
|
||||||
|
|
||||||
// Запись ошибки
|
foreach ($expression as $parameter => $value) {
|
||||||
throw new exception('Пустое значение поля для поиска');
|
// Перебор выражения поиска
|
||||||
|
|
||||||
|
// Запись в строку запроса
|
||||||
|
$where .= "`$parameter` = :$parameter &&";
|
||||||
|
|
||||||
|
// Запись параметров запроса
|
||||||
|
$params[":$parameter"] = $value;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Инициализация запроса
|
// Очистка или реинициализация выражения поиска
|
||||||
$request = static::$db->prepare("SELECT * FROM `accounts` WHERE `$field` = :field LIMIT 1");
|
$where = empty($expression) ? '' : trim(trim($where, '&&'));
|
||||||
|
|
||||||
// Параметры запроса
|
// Инициализация запроса
|
||||||
$params = [
|
$request = static::$db->prepare("SELECT * FROM `accounts` $where LIMIT 1");
|
||||||
":field" => $value,
|
|
||||||
];
|
|
||||||
|
|
||||||
// Отправка запроса
|
// Отправка запроса
|
||||||
$request->execute($params);
|
$request->execute($params);
|
||||||
|
|
||||||
// Генерация ответа
|
// Генерация ответа
|
||||||
if ($account = $request->fetch(pdo::FETCH_ASSOC)) {
|
if ($account = new static($request->fetch(pdo::FETCH_ASSOC))) {
|
||||||
// Найден аккаунт
|
// Найден аккаунт
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if ($permissions = static::permissions((int) $account['id'], $errors)) {
|
if ($permissions = static::permissions((int) $account->id, $errors)) {
|
||||||
// Найдены разрешения
|
// Найдены разрешения
|
||||||
|
|
||||||
// Запись в буфер данных аккаунта
|
// Запись в буфер данных аккаунта
|
||||||
$account['permissions'] = $permissions;
|
$account->permissions = $permissions;
|
||||||
} else {
|
} else {
|
||||||
// Не найдены разрешения
|
// Не найдены разрешения
|
||||||
|
|
||||||
|
@ -511,7 +529,7 @@ final class accounts_model extends core
|
||||||
}
|
}
|
||||||
} catch (exception $e) {
|
} catch (exception $e) {
|
||||||
// Запись в журнал ошибок
|
// Запись в журнал ошибок
|
||||||
$errors[] = [
|
$errors['account'][] = [
|
||||||
'text' => $e->getMessage(),
|
'text' => $e->getMessage(),
|
||||||
'file' => $e->getFile(),
|
'file' => $e->getFile(),
|
||||||
'line' => $e->getLine()
|
'line' => $e->getLine()
|
||||||
|
@ -524,7 +542,7 @@ final class accounts_model extends core
|
||||||
}
|
}
|
||||||
} catch (exception $e) {
|
} catch (exception $e) {
|
||||||
// Запись в журнал ошибок
|
// Запись в журнал ошибок
|
||||||
$errors[]= [
|
$errors['account'][]= [
|
||||||
'text' => $e->getMessage(),
|
'text' => $e->getMessage(),
|
||||||
'file' => $e->getFile(),
|
'file' => $e->getFile(),
|
||||||
'line' => $e->getLine(),
|
'line' => $e->getLine(),
|
||||||
|
@ -532,7 +550,7 @@ final class accounts_model extends core
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
return isset($account) && $account ? $account : [];
|
return $account ?? null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -547,6 +565,9 @@ final class accounts_model extends core
|
||||||
*/
|
*/
|
||||||
public static function hash(int $id, string|null $hash = null, int|null $time = null, array &$errors = []): array
|
public static function hash(int $id, string|null $hash = null, int|null $time = null, array &$errors = []): array
|
||||||
{
|
{
|
||||||
|
// Инициализация журнала ошибок
|
||||||
|
$errors['account'] ?? $errors['account'] = [];
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (isset($hash, $time)) {
|
if (isset($hash, $time)) {
|
||||||
// Переданы хеш и его время хранения
|
// Переданы хеш и его время хранения
|
||||||
|
@ -608,7 +629,7 @@ final class accounts_model extends core
|
||||||
}
|
}
|
||||||
} catch (exception $e) {
|
} catch (exception $e) {
|
||||||
// Запись в журнал ошибок
|
// Запись в журнал ошибок
|
||||||
$errors[]= [
|
$errors['account'][] = [
|
||||||
'text' => $e->getMessage(),
|
'text' => $e->getMessage(),
|
||||||
'file' => $e->getFile(),
|
'file' => $e->getFile(),
|
||||||
'line' => $e->getLine(),
|
'line' => $e->getLine(),
|
||||||
|
|
|
@ -4,6 +4,8 @@ declare(strict_types=1);
|
||||||
|
|
||||||
namespace mirzaev\surikovlib\models;
|
namespace mirzaev\surikovlib\models;
|
||||||
|
|
||||||
|
use mirzaev\surikovlib\models\accounts_model as accounts;
|
||||||
|
|
||||||
use pdo;
|
use pdo;
|
||||||
use exception;
|
use exception;
|
||||||
|
|
||||||
|
@ -15,35 +17,260 @@ use exception;
|
||||||
*/
|
*/
|
||||||
final class books_model extends core
|
final class books_model extends core
|
||||||
{
|
{
|
||||||
public static function read(array $where = [], int $limit = 1, int $page = 1): array
|
/**
|
||||||
|
* Чтение
|
||||||
|
*
|
||||||
|
* @param array $expression Выражение поиска
|
||||||
|
* @param int $limit Ограничение по количеству
|
||||||
|
* @param int $page Страница (сдвиг)
|
||||||
|
* @param array &$errors Журнал ошибок
|
||||||
|
*
|
||||||
|
* @return array Книги
|
||||||
|
*/
|
||||||
|
public static function read(array $expression = [], int $limit = 1, int $page = 1, array &$errors = []): array
|
||||||
{
|
{
|
||||||
// Инициализация строки поиска
|
// Инициализация журнала ошибок
|
||||||
$row = '';
|
$errors['books'] ?? $errors['books'] = [];
|
||||||
|
|
||||||
// Инициализация параметров запроса
|
try {
|
||||||
$params = [];
|
// Инициализация выражения поиска
|
||||||
|
$where = 'WHERE ';
|
||||||
|
|
||||||
foreach ($where as $parameter => $value) {
|
// Инициализация параметров запроса
|
||||||
// Перебор параметров поиска
|
$params = [];
|
||||||
|
|
||||||
// Запись функции
|
foreach ($expression as $parameter => $value) {
|
||||||
if(empty($row)) $row = 'WHERE ';
|
// Перебор выражения поиска
|
||||||
|
|
||||||
// Запись в строку поиска
|
// Запись в строку запроса
|
||||||
$row .= "`$parameter` = :$parameter";
|
$where .= "`$parameter` = :$parameter &&";
|
||||||
|
|
||||||
$params[$parameter] = $value;
|
// Запись параметров запроса
|
||||||
|
$params[":$parameter"] = $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Очистка или реинициализация выражения поиска
|
||||||
|
$where = empty($expression) ? '' : trim(trim($where, '&&'));
|
||||||
|
|
||||||
|
// Инициализация страницы
|
||||||
|
$page = $limit * --$page;
|
||||||
|
|
||||||
|
// Инициализация запроса
|
||||||
|
$request = static::$db->prepare("SELECT * FROM `books` $where LIMIT $page, $limit");
|
||||||
|
|
||||||
|
// Отправка запроса
|
||||||
|
$request->execute($params);
|
||||||
|
|
||||||
|
return (array) $request->fetchAll(pdo::FETCH_ASSOC);
|
||||||
|
} catch (exception $e) {
|
||||||
|
// Запись в журнал ошибок
|
||||||
|
$errors['books'][] = [
|
||||||
|
'text' => $e->getMessage(),
|
||||||
|
'file' => $e->getFile(),
|
||||||
|
'line' => $e->getLine(),
|
||||||
|
'stack' => $e->getTrace()
|
||||||
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Инициализация страницы
|
return [];
|
||||||
$page = $limit * --$page;
|
}
|
||||||
|
|
||||||
// Инициализация запроса
|
/**
|
||||||
$request = static::$db->prepare("SELECT * FROM `books` $row LIMIT $page, $limit");
|
* Запись в базу данных
|
||||||
|
*
|
||||||
|
* @param string $title Название
|
||||||
|
* @param string|null $description Описание
|
||||||
|
* @param int|null $account Аккаунт (идентификатор)
|
||||||
|
* @param array &$errors Журнал ошибок
|
||||||
|
*
|
||||||
|
* @return int|null Идентификатор записанной книги
|
||||||
|
*/
|
||||||
|
public static function write(string $title, ?string $description = null, ?int $account = null, array &$errors = []): ?int
|
||||||
|
{
|
||||||
|
// Инициализация журнала ошибок
|
||||||
|
$errors['books'] ?? $errors['books'] = [];
|
||||||
|
|
||||||
// Отправка запроса
|
try {
|
||||||
$request->execute($params);
|
// Инициализация аккаунта
|
||||||
|
$account = accounts::init($account, $errors);
|
||||||
|
|
||||||
return (array) $request->fetchAll(pdo::FETCH_ASSOC);
|
if (empty($account) || !accounts::access('books', $account->id)) {
|
||||||
|
// Не удалось найти аккаунт или разрешение на управление книгами не выдано
|
||||||
|
|
||||||
|
throw new exception('У вас нет разрешения на управление книгами');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Инициализация запроса
|
||||||
|
$request = static::$db->prepare("INSERT INTO `books` (`account`, `title`, `description`) VALUES (:account, :title, :description)");
|
||||||
|
|
||||||
|
// Инициализация параметров
|
||||||
|
$params = [
|
||||||
|
':account' => $account->id,
|
||||||
|
':title' => $title,
|
||||||
|
':description' => $description
|
||||||
|
];
|
||||||
|
|
||||||
|
// Отправка запроса
|
||||||
|
$request->execute($params);
|
||||||
|
|
||||||
|
if ($id = static::$db->lastInsertId()) {
|
||||||
|
// Получен идентификатор загруженной книги (подразумевается)
|
||||||
|
|
||||||
|
return (int) $id;
|
||||||
|
}
|
||||||
|
} catch (exception $e) {
|
||||||
|
// Запись в журнал ошибок
|
||||||
|
$errors['books'][] = [
|
||||||
|
'text' => $e->getMessage(),
|
||||||
|
'file' => $e->getFile(),
|
||||||
|
'line' => $e->getLine(),
|
||||||
|
'stack' => $e->getTrace()
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Импорт
|
||||||
|
*
|
||||||
|
* @param array $books Книги (файлы)
|
||||||
|
* @param int|null $account Аккаунт (идентификатор)
|
||||||
|
* @param array &$errors Журнал ошибок
|
||||||
|
*
|
||||||
|
* @return array Записанные книги
|
||||||
|
*/
|
||||||
|
public static function import(array $books, ?int $account = null, array &$errors = []): array
|
||||||
|
{
|
||||||
|
// Инициализация журнала ошибок
|
||||||
|
$errors['books'] ?? $errors['books'] = [];
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (empty($books)) {
|
||||||
|
// Не найдены книги
|
||||||
|
|
||||||
|
throw new exception('Не найдены книги для записи');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Инициализация аккаунта
|
||||||
|
$account = accounts::init($account, $errors);
|
||||||
|
|
||||||
|
if (empty($account) || !accounts::access('books', $account->id)) {
|
||||||
|
// Не найден аккаунт или разрешение на управление книгами не выдано
|
||||||
|
|
||||||
|
throw new exception('У вас нет разрешения на управление книгами');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Инициализация буфера инициализированных книг
|
||||||
|
$initialized = [];
|
||||||
|
|
||||||
|
for ($i = -1; count($books['name']) > ++$i;) {
|
||||||
|
// Перебор загруженных книг
|
||||||
|
|
||||||
|
// Генерация хеша файла
|
||||||
|
$hash = hash_file('md5', $books['tmp_name'][$i]) ?? 0;
|
||||||
|
|
||||||
|
if (move_uploaded_file($books['tmp_name'][$i], \STORAGE . DIRECTORY_SEPARATOR . 'temp' . DIRECTORY_SEPARATOR . $hash . '_' . $books['name'][$i])) {
|
||||||
|
// Загружен и перемещён из временной папки файл с книгой
|
||||||
|
|
||||||
|
// Извлечение имени файла
|
||||||
|
|
||||||
|
// Запись в буфер инициализированных книг
|
||||||
|
$initialized[] = [
|
||||||
|
'name' => preg_replace('/\.pdf/', '', $books['name'])[0],
|
||||||
|
'file' => $hash . '_' . $books['name'][$i]
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Инициализация буфера записанных книг
|
||||||
|
$writed = [];
|
||||||
|
|
||||||
|
foreach ($initialized as $book) {
|
||||||
|
// Перебор инициализированных книг
|
||||||
|
|
||||||
|
try {
|
||||||
|
if ($id = static::write($book['name'], 'Без описания', $account->id ?? null, $errors)) {
|
||||||
|
// Записана в базу данных книга
|
||||||
|
|
||||||
|
// Инициализация пути до хранилища
|
||||||
|
$directory = \STORAGE . DIRECTORY_SEPARATOR . 'books' . DIRECTORY_SEPARATOR . $id . DIRECTORY_SEPARATOR;
|
||||||
|
|
||||||
|
// Инициализация директории
|
||||||
|
if (!file_exists($directory)) if (!mkdir($directory, 0755, true)) throw new exception('Не удалось записать директорию для книги');
|
||||||
|
|
||||||
|
// Инициализация пути до временного файла
|
||||||
|
$file = \STORAGE . DIRECTORY_SEPARATOR . 'temp' . DIRECTORY_SEPARATOR . $book['file'];
|
||||||
|
|
||||||
|
// Извлечение изображений из PDF-документа
|
||||||
|
exec("pdfimages -j '$file' '$directory'");
|
||||||
|
|
||||||
|
// Переименование файлов в необходимый формат
|
||||||
|
exec("echo 'export j=-1; for i in $directory*.jpg; do let j+=1; mv \$i $directory\$j.jpg; done' | bash");
|
||||||
|
|
||||||
|
// Запись в буфер записанных книг
|
||||||
|
$writed[] = $id;
|
||||||
|
} else {
|
||||||
|
// Не записана в базу данных книга
|
||||||
|
|
||||||
|
throw new exception('Не удалось записать книгу в базу данных', 500);
|
||||||
|
}
|
||||||
|
} catch (exception $e) {
|
||||||
|
// Запись в журнал ошибок
|
||||||
|
$errors['books'][] = [
|
||||||
|
'text' => $e->getMessage(),
|
||||||
|
'file' => $e->getFile(),
|
||||||
|
'line' => $e->getLine(),
|
||||||
|
'stack' => $e->getTrace()
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (exception $e) {
|
||||||
|
// Запись в журнал ошибок
|
||||||
|
$errors['books'][] = [
|
||||||
|
'text' => $e->getMessage(),
|
||||||
|
'file' => $e->getFile(),
|
||||||
|
'line' => $e->getLine(),
|
||||||
|
'stack' => $e->getTrace()
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
return $writed ?? [];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Подсчёт количества страниц
|
||||||
|
*
|
||||||
|
* @param int $id Идентификатор
|
||||||
|
* @param array &$errors Журнал ошибок
|
||||||
|
*
|
||||||
|
* @return int|null Количество страниц
|
||||||
|
*/
|
||||||
|
public static function amount(int $id, array &$errors = []): ?int
|
||||||
|
{
|
||||||
|
// Инициализация журнала ошибок
|
||||||
|
$errors['books'] ?? $errors['books'] = [];
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Инициализация счётчика
|
||||||
|
$amount = -1;
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
// Перебор директорий (!!! Рекурсия !!!)
|
||||||
|
|
||||||
|
// Перебор изображений по возрастанию (от 0.jpg до 999.jpg и т.д.)
|
||||||
|
if (!file_exists(\STORAGE . DIRECTORY_SEPARATOR . 'books' . DIRECTORY_SEPARATOR . $id . DIRECTORY_SEPARATOR . ++$amount . '.jpg')) return $amount;
|
||||||
|
}
|
||||||
|
} catch (exception $e) {
|
||||||
|
// Запись в журнал ошибок
|
||||||
|
$errors['books'][] = [
|
||||||
|
'text' => $e->getMessage(),
|
||||||
|
'file' => $e->getFile(),
|
||||||
|
'line' => $e->getLine(),
|
||||||
|
'stack' => $e->getTrace()
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -65,3 +65,13 @@
|
||||||
list-style: none;
|
list-style: none;
|
||||||
background-color: #ae8f8f;
|
background-color: #ae8f8f;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#authentication>div#account>p>b {
|
||||||
|
margin-right: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#authentication>div#account>p>span {
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
overflow: hidden;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
|
@ -8,9 +8,8 @@ main>section#books>* {
|
||||||
}
|
}
|
||||||
|
|
||||||
main>section#books>form.upload {
|
main>section#books>form.upload {
|
||||||
width: calc(100% / 3 - 20px - 9px * 2);
|
width: calc(100% / 3 - 20px - 8px);
|
||||||
height: calc(220px - 9px * 2);
|
height: 212px;
|
||||||
margin: 5px;
|
|
||||||
margin-right: 20px;
|
margin-right: 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -22,31 +21,86 @@ main>section#books>form.upload>p {
|
||||||
|
|
||||||
main>section#books>article.book {
|
main>section#books>article.book {
|
||||||
width: calc(100% / 3 - 20px);
|
width: calc(100% / 3 - 20px);
|
||||||
|
height: 220px;
|
||||||
|
position: relative;
|
||||||
margin-right: 20px;
|
margin-right: 20px;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
}
|
}
|
||||||
|
|
||||||
main>section#books>article.book:nth-child(3) {
|
main>section#books>article.book:nth-child(3n) {
|
||||||
width: calc(100% / 3);
|
|
||||||
margin-right: unset;
|
margin-right: unset;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
main>section#books>:is(form.upload, article.book):nth-last-child(1),
|
||||||
|
main>section#books>:is(form.upload, article.book):nth-last-child(2),
|
||||||
|
main>section#books>:is(form.upload, article.book):nth-last-child(3) {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
main>section#books>article.book>img {
|
main>section#books>article.book>img {
|
||||||
height: 220px;
|
height: 100%;
|
||||||
object-fit: cover;
|
object-fit: cover;
|
||||||
object-position: right;
|
object-position: right;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
clip-path: polygon(5px calc(100% - 5px), calc(100% - 5px) calc(100% - 5px), calc(100% - 5px) 5px, 5px 5px);
|
/* clip-path: polygon(5px calc(100% - 5px), calc(100% - 5px) calc(100% - 5px), calc(100% - 5px) 5px, 5px 5px); */
|
||||||
}
|
}
|
||||||
|
|
||||||
main>section#books>article.book>h4 {
|
main>section#books>article.book>h4 {
|
||||||
margin-top: 5px;
|
width: calc(100% - 20px);
|
||||||
margin-bottom: 10px;
|
position: absolute;
|
||||||
height: 50px;
|
bottom: 0;
|
||||||
text-align: center;
|
margin: 0;
|
||||||
|
padding: 10px;
|
||||||
|
text-align: left;
|
||||||
|
overflow-wrap: break-word;
|
||||||
|
-webkit-hyphens: auto;
|
||||||
|
-moz-hyphens: auto;
|
||||||
|
-ms-hyphens: auto;
|
||||||
|
hyphens: auto;
|
||||||
|
color: #fff;
|
||||||
|
background: rgba(0, 0, 0, 50%);
|
||||||
}
|
}
|
||||||
|
|
||||||
main>section#books>article.book>p {
|
main>section#books>article.book>p {
|
||||||
margin: unset;
|
margin: unset;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
main>section#book>img,
|
||||||
|
main>section#book>img::before {
|
||||||
|
margin-bottom: 20px;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
main>section#book>img::before{
|
||||||
|
margin-top: -1em;
|
||||||
|
height: 200px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
main>section#book>nav>ul {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
display: flex;
|
||||||
|
list-style: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
main>section#book>nav>ul>li[type="button"] {
|
||||||
|
padding: 6px 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
main>section#book>nav>ul>li:only-of-type {
|
||||||
|
margin-left: auto;
|
||||||
|
margin-right: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
main>section#book>nav>ul>li.previous {
|
||||||
|
margin-left: auto;
|
||||||
|
margin-right: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
main>section#book>nav>ul>li.next {
|
||||||
|
margin-right: auto;
|
||||||
|
}
|
||||||
|
|
|
@ -3,11 +3,16 @@
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
::selection,
|
||||||
|
::-moz-selection {
|
||||||
|
background-color: #544f7f;
|
||||||
|
}
|
||||||
|
|
||||||
body {
|
body {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-rows: auto auto 150px;
|
grid-template-rows: auto auto 150px;
|
||||||
grid-template-columns: auto 300px 600px auto;
|
grid-template-columns: minmax(100px, auto) 300px minmax(500px, auto) minmax(100px, auto);;
|
||||||
background-color: #e5ddd1;
|
background-color: #e5ddd1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -54,8 +59,9 @@ main {
|
||||||
}
|
}
|
||||||
|
|
||||||
main>section>h2 {
|
main>section>h2 {
|
||||||
margin-left: 1.5rem;
|
margin-top: 0;
|
||||||
margin-top: unset;
|
margin-bottom: 2rem;
|
||||||
|
text-align: center;
|
||||||
font-size: 1.8rem;
|
font-size: 1.8rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -168,7 +174,7 @@ footer {
|
||||||
}
|
}
|
||||||
|
|
||||||
.button,
|
.button,
|
||||||
:is(a, label)[type="button"],
|
:is(li, a, label)[type="button"],
|
||||||
input[type="submit"] {
|
input[type="submit"] {
|
||||||
padding: 10px 20px;
|
padding: 10px 20px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
@ -180,14 +186,14 @@ input[type="submit"] {
|
||||||
}
|
}
|
||||||
|
|
||||||
.button:hover,
|
.button:hover,
|
||||||
:is(a, label)[type="button"]:hover,
|
:is(li, a, label)[type="button"]:hover,
|
||||||
input[type="submit"]:hover {
|
input[type="submit"]:hover {
|
||||||
color: #fff;
|
color: #fff;
|
||||||
background-color: #c5531f;
|
background-color: #c5531f;
|
||||||
}
|
}
|
||||||
|
|
||||||
.button:active:is(:active, :focus),
|
.button:active:is(:active, :focus),
|
||||||
:is(a, label)[type="button"]:is(:active, :focus),
|
:is(li, a, label)[type="button"]:is(:active, :focus),
|
||||||
input[type="radio"]:checked+label[type="button"],
|
input[type="radio"]:checked+label[type="button"],
|
||||||
input[type="submit"]:is(:active, :focus) {
|
input[type="submit"]:is(:active, :focus) {
|
||||||
color: #ddd;
|
color: #ddd;
|
||||||
|
@ -247,6 +253,11 @@ input:is([type="text"], [type="password"]).measured+.unit {
|
||||||
user-select: none;
|
user-select: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.unselectable::selection,
|
||||||
|
.unselectable *::-moz-selection {
|
||||||
|
background: none;
|
||||||
|
}
|
||||||
|
|
||||||
.divider {
|
.divider {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
border-radius: 2px;
|
border-radius: 2px;
|
||||||
|
|
|
@ -2,15 +2,15 @@
|
||||||
<link href="/css/auth.css" rel="stylesheet">
|
<link href="/css/auth.css" rel="stylesheet">
|
||||||
|
|
||||||
{% if account is not empty %}
|
{% if account is not empty %}
|
||||||
<h3>Аккаунт</h3>
|
<h3 class="unselectable">Аккаунт</h3>
|
||||||
<div>
|
<div id="account">
|
||||||
<p><b>Почта:</b> <span>{{ account.email }}</span></p>
|
<p><b class="unselectable">Почта:</b><span title="{{ account.mail }}">{{ account.mail }}</span></p>
|
||||||
<a class="exit" type="button" href='/account/deauthentication'>Выход</a>
|
<a class="exit unselectable" type="button" href='/account/deauthentication'>Выход</a>
|
||||||
</div>
|
</div>
|
||||||
{% else %}
|
{% else %}
|
||||||
<h3>Аутентификация</h3>
|
<h3 class="unselectable">Аутентификация</h3>
|
||||||
<form method="POST" accept-charset="UTF-8">
|
<form method="POST" accept-charset="UTF-8">
|
||||||
<input type="text" name="email" placeholder="Почта">
|
<input type="text" name="mail" placeholder="Почта">
|
||||||
<input type="password" name="password" placeholder="Пароль">
|
<input type="password" name="password" placeholder="Пароль">
|
||||||
|
|
||||||
<div class="submit">
|
<div class="submit">
|
||||||
|
|
|
@ -3,9 +3,16 @@
|
||||||
{% block main %}
|
{% block main %}
|
||||||
<link href="/css/books.css" rel="stylesheet">
|
<link href="/css/books.css" rel="stylesheet">
|
||||||
|
|
||||||
<article class="book">
|
<section id="book">
|
||||||
<img src="/books/{{ book.id|e }}/cover" alt='Обложка книги "{{ book.title|e }}"'>
|
<h2>{{ book.title|e }}</h2>
|
||||||
<h3><a href="/books/{{ book.id|e }}">{{ book.title|e }}</a></h3>
|
<img class="unselectable" src="/storage/books/{{ book.id|e }}/{{ page|e }}" alt='Страница отсутствует'>
|
||||||
<p>{{ book.description|e|length|trim(' ') > 80 ? book.description|e|slice(0, 80)|trim(' ') ~ '...' : book.description|e}}</p>
|
<nav>
|
||||||
</article>
|
<ul>
|
||||||
|
{% if page != 0 %}
|
||||||
|
<li class="previous unselectable" type="button"><a href="/books/{{ book.id|e }}/{{ page|e - 1 }}" title="Страница №{{ page|e - 1 }}">Назад</a></li>
|
||||||
|
{% endif %}
|
||||||
|
<li class="next unselectable" type="button"><a href="/books/{{ book.id|e }}/{{ page|e + 1 }}" title="Страница №{{ page|e + 1 }}">Вперёд</a></li>
|
||||||
|
</ul>
|
||||||
|
</nav>
|
||||||
|
</section>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
|
@ -5,13 +5,17 @@
|
||||||
<link href="/css/upload.css" rel="stylesheet">
|
<link href="/css/upload.css" rel="stylesheet">
|
||||||
|
|
||||||
<section id="books">
|
<section id="books">
|
||||||
<form class="upload" action="/books/write" enctype="multipart/form-data" method="POST">
|
{% if account is not empty %}
|
||||||
|
{% if account.permissions.books is defined and account.permissions.books == 1 %}
|
||||||
|
<form class="upload unselectable" action="/storage/books/write" enctype="multipart/form-data" method="POST">
|
||||||
<input type="file" name="books[]" accept=".pdf" oninput="this.parentElement.submit();" multiple="true">
|
<input type="file" name="books[]" accept=".pdf" oninput="this.parentElement.submit();" multiple="true">
|
||||||
<p>+</p>
|
<p>+</p>
|
||||||
</form>
|
</form>
|
||||||
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
{% for book in books %}
|
{% for book in books %}
|
||||||
<article class="book">
|
<article class="book">
|
||||||
<img src="/books/{{ book.id|e }}/cover" alt='Обложка книги "{{ book.title|e }}"'>
|
<img src="/storage/books/{{ book.id|e }}/0" class="unselectable" alt='Обложка книги "{{ book.title|e }}"'>
|
||||||
<h4><a href="/books/{{ book.id|e }}">{{ book.title|e }}</a></h3>
|
<h4><a href="/books/{{ book.id|e }}">{{ book.title|e }}</a></h3>
|
||||||
</article>
|
</article>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
|
|
||||||
<title>
|
<title>
|
||||||
{% block title %}
|
{% block title %}
|
||||||
Библеотека Сурикова
|
Библиотека Сурикова
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
</title>
|
</title>
|
||||||
</head>
|
</head>
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<header>
|
<header class="unselectable">
|
||||||
<section class="menu">
|
<section class="menu">
|
||||||
<nav>
|
<nav>
|
||||||
<a class="link" href="/surikov" title="Архивный фонд">Кеменев</a>
|
<a class="link" href="/surikov" title="Архивный фонд">Кеменов</a>
|
||||||
<a class="link" href="/kemenev" title="Список книг">Суриков</a>
|
<a class="link" href="/kemenev" title="Список книг">Суриков</a>
|
||||||
<a id="logo" href="/" title="Главная страница">
|
<a id="logo" href="/" title="Главная страница">
|
||||||
<img src="/img/surikovlib_logo_1_white.svg">
|
<img src="/img/surikovlib_logo_1_white.svg">
|
||||||
|
|
|
@ -1,8 +0,0 @@
|
||||||
<script src="https://vk.com/js/api/openapi.js?169" type="text/javascript"></script>
|
|
||||||
<script type="text/javascript" src="https://vk.com/js/api/openapi.js?169"></script>
|
|
||||||
|
|
||||||
<div id="group"></div>
|
|
||||||
|
|
||||||
<script type="text/javascript">
|
|
||||||
VK.Widgets.Group("group", { mode: 4, wide: 0, width: parseInt(getComputedStyle(document.getElementsByTagName('aside')[0]).getPropertyValue('width')), height: "600", color1: 'd9b5b5', color2: '000', color3: '86781C' }, 29605269);
|
|
||||||
</script>
|
|
Loading…
Reference in New Issue