labo86/rdtas

View on GitHub
src/app/User.php

Summary

Maintainability
A
1 hr
Test Coverage
<?php
declare(strict_types=1);


namespace labo86\rdtas\app;


use DateInterval;
use DateTime;
use labo86\exception_with_data\ExceptionWithData;
use labo86\exception_with_data\Util;
use labo86\rdtas\ErrMsg;
use labo86\rdtas\pdo\Util as UtilPDO;
use PDO;
use Throwable;

class User
{

    const DDL_TABLE_SESSIONS = <<<EOF
create table sessions
(
    session_id varchar(36) not null
        primary key,
    user_id varchar(36) null,
    creation_date datetime null,
    expiration_date datetime null,
    status varchar(36) null
);
EOF;

    const DDL_TABLE_USERS = <<<EOF
create table users
(
    user_id varchar(36) not null
        primary key,
    name varchar(36) null,
    nickname varchar(36) null,
    password_hash varchar(255) null,
    email varchar(100) null,
    type varchar(10) null
);
EOF;


    const DATE_FORMAT = "Y-m-d H:i:s";

    public static function getSession(PDO $pdo, string $session_id) : array {

        try {
            $row = UtilPDO::selectRow($pdo, 'SELECT user_id, creation_date, expiration_date, status FROM sessions WHERE session_id = :session_id', [
                'session_id' => $session_id
            ]);

            return $row;
        } catch ( Throwable $exception ) {
            throw Util::rethrow(ErrMsg::SESSION_DOES_NOT_EXIST, [
                'session_id' => $session_id
            ], $exception);

        }
    }

    public static function getUser(PDO $pdo, string $user_id) : array {
        try {
            $row = UtilPDO::selectRow($pdo, 'SELECT user_id, name, nickname, type FROM users WHERE user_id = :user_id', [
                'user_id' => $user_id
            ]);

            return $row;
        } catch ( Throwable $exception ) {
            throw Util::rethrow(ErrMsg::USER_DOES_NOT_EXIST, [
                'user_id' => $user_id
            ], $exception);
        }

    }

    public static function getUserByName(PDO $pdo, string $name) : array {
        try {
            $row = UtilPDO::selectRow($pdo, 'SELECT user_id, name, type FROM users WHERE name = :name', [
                'name' => $name
            ]);

            return $row;
        } catch ( Throwable $exception ) {
            throw Util::rethrow(ErrMsg::USER_DOES_NOT_EXIST, [
                'name' => $name
            ], $exception);
        }

    }

    public static function createUser(PDO $pdo, string $user_id, string $username, string $password_hash) : array {
        UtilPDO::updateOne($pdo,"INSERT INTO users (user_id, name, nickname,password_hash, type) VALUES (:user_id, :name, :nickname, :password_hash, :type)", [
            'user_id' => $user_id,
            'name' => $username,
            'nickname' => $username,
            'password_hash' => $password_hash,
            'type' => 'REGISTERED'
        ]);
        return [];
    }

    public static function validateUserType(PDO $pdo, string $user_id, string $required_type) : array {
        $user = self::getUser($pdo, $user_id);
        $type = $user['type'];
        if ( $user['type'] !== $required_type ) {
            throw new ExceptionWithData(ErrMsg::USER_DOES_NOT_HAVE_PERMISSION, [
                'user_id' =>  $user_id,
                'required_type' => $required_type,
                'user_type' => $type
            ]);
        }
        return $user;
    }

    public static function createSession(PDO $pdo, string $username, string $password) : array {
        try {
            $row = UtilPDO::selectRow($pdo, "SELECT user_id, name, password_hash FROM users WHERE name = :name", [
                'name' => $username
            ]);
        } catch ( Throwable $exception ) {
            throw Util::rethrow(ErrMsg::USER_DOES_NOT_EXIST, [
                'username' => $username
            ], $exception);
        }

        $session_id = md5(microtime());
        $password_hash = $row['password_hash'];
        if ( !password_verify($password, $password_hash) ) {
            throw new ExceptionWithData(ErrMsg::WRONG_PASSWORD, [
                'username' => $username,
                'password' => $password
            ]);
        }

        $user_id = $row['user_id'];
        $date = new DateTime();
        $creation_date = $date->format(self::DATE_FORMAT);
        $date->add(new DateInterval('P1D'));
        $expiration_date =  $date->format(self::DATE_FORMAT);
        UtilPDO::updateOne($pdo, 'INSERT INTO sessions (session_id, user_id, creation_date, expiration_date, status) VALUES (:session_id, :user_id, :creation_date, :expiration_date, :status)',
            [
                'session_id' => $session_id,
                'user_id' => $user_id,
                'creation_date' => $creation_date,
                'expiration_date' => $expiration_date,
                'status' => 'ACTIVE'
            ]);

        return [
            'session_id' => $session_id,
            'user_id' => $user_id,
            'creation_date' => $creation_date,
            'expiration_date' => $expiration_date,
            'status' => 'ACTIVE'
        ];
    }

    /**
     * Funcion de utilidad.
     * Siempre se me olvida que utilizar.
     * Ahora usa BCRYPT
     * Usa la funcion {@see password_hash()}
     * Para validar un password use {@see password_verify()}
     * @param string $password
     * @return string
     */
    public static function createPasswordHash(string $password) : string {
        return password_hash($password, PASSWORD_BCRYPT);
    }

    public static function validateSession(PDO $pdo, string $session_id) : array {
        $session = self::getSession($pdo, $session_id);
        $user_id = $session['user_id'];
        $status = $session['status'];
        if ( $status !== 'ACTIVE' )
            throw new ExceptionWithData(ErrMsg::SESSION_INACTIVE, [
                'session_id' => $session_id,
                'user_id' => $user_id,
                'status' => $status
            ]);


        $expiration_date = DateTime::createFromFormat(self::DATE_FORMAT, $session['expiration_date']);
        $current_date = new DateTime();
        if ( $expiration_date < $current_date ) {
            throw new ExceptionWithData(ErrMsg::SESSION_EXPIRED, [
                'session_id' => $session_id,
                'user_id' => $user_id,
                'status' => $status,
                'current_date' => $current_date->format(self::DATE_FORMAT),
                'expiration_date' => $expiration_date->format(self::DATE_FORMAT)
            ]);
        }

        return $session;
    }

    /**
     * Esta funcion {@see validateSession() valida} y obtiene el user id
     * @param PDO $pdo
     * @param string $session_id
     * @return string
     * @throws ExceptionWithData
     */
    public static function getUserIdFromSessionId(PDO $pdo, string $session_id) : string {
        $session = self::validateSession($pdo, $session_id);
        return $session['user_id'];
    }

    /**
     * @param PDO $pdo
     * @param string $session_id
     * @return array la informacion del usuario
     * @throws ExceptionWithData
     */
    public static function validateAdminFromSessionId(PDO $pdo, string $session_id) : array {
        $user_id = self::getUserIdFromSessionId($pdo, $session_id);
        return self::validateUserType($pdo, $user_id, 'ADMIN');
    }

    public static function closeSession(PDO $pdo, string $session_id) {
        UtilPDO::updateOne($pdo, 'UPDATE sessions SET status = :status WHERE session_id = :session_id',
            [
                'status' => 'CLOSED',
                'session_id' => $session_id
        ]);
    }

    public static function setUserNickname(PDO $pdo, string $user_id, string $nickname) {
        UtilPDO::updateOne($pdo, 'UPDATE users SET nickname = :nickname WHERE user_id = :user_id',
            [
                'nickname' => $nickname,
                'user_id' => $user_id
            ]);
    }

    public static function setUserType(PDO $pdo, string $user_id, string $type) {
        UtilPDO::updateOne($pdo, 'UPDATE users SET type = :type WHERE user_id = :user_id',
            [
                'type' => $type,
                'user_id' => $user_id
            ]);
    }


    public static function setUserPassword(PDO $pdo, string $user_id, string $password_hash) {
        UtilPDO::updateOne($pdo, 'UPDATE users SET password_hash = :password_hash WHERE user_id = :user_id',
            [
                'password_hash' => $password_hash,
                'user_id' => $user_id
            ]);
    }

}