Skip to content
Snippets Groups Projects
Database.php 10.98 KiB
<?php

namespace QuasselRestSearch;

use PDO;

require_once 'User.php';
require_once 'Config.php';
require_once 'helper/AuthHelper.php';
require_once 'backends/BackendFactory.php';

class Database
{
    private $user;

    private $backend;

    private function __construct(string $database_connector, string $username, string $password, string $type)
    {
        $this->backend = BackendFactory::create($type, new \PDO($database_connector, $username, $password));
    }

    public static function createFromConfig(Config $config): Database
    {
        return Database::createFromOptions($config->database_connector, $config->username, $config->password, $config->backend);
    }

    public static function createFromOptions(string $database_connector, string $username, string $password, string $type): Database
    {
        return new Database($database_connector, $username, $password, $type);
    }

    public function authenticateFromHeader(string $header): bool
    {
        $parsedHeader = AuthHelper::parseAuthHeader($header);
        return $this->authenticate($parsedHeader['username'], $parsedHeader['password']);
    }

    public function authenticate(string $username, string $password): bool
    {
        if (!isset($username) || !isset($password)) {
            syslog(LOG_ERR, "Username or password not set");
            return false;
        }

        $stmt = $this->backend->findUser();

        $stmt->bindParam(":username", $username);
        $stmt->execute();
        $result = $stmt->fetch(\PDO::FETCH_ASSOC);

        if ($result === FALSE) {
            syslog(LOG_ERR, "Couldn’t find user " . $username);
            return false;
        }

        $user = new User($result);

        if (!AuthHelper::initialAuthenticateUser($password, $user->password, $user->hashversion)) {
            syslog(LOG_ERR, "Password does not match for user " . $username);
            return false;
        }

        $this->user = $user;
        return true;
    }

    private function apply_config(\PDOStatement $stmt)
    {
        $stmt->bindValue(':config_normalization', 0, PDO::PARAM_INT);

        $stmt->bindValue(':weight_content', 1, PDO::PARAM_INT);
        $stmt->bindValue(':weight_type', 1, PDO::PARAM_INT);
        $stmt->bindValue(':weight_time', 12, PDO::PARAM_INT);
    }

    public function find(string $query, int $since = null, int $before = null, string $buffer = null, string $network = null, string $sender = null, int $limitPerBuffer = 4): array
    {
        $truncatedLimit = max(min($limitPerBuffer, 10), 0);
        $truncatedLimit = 20;

        $messages = $this->findInBufferMultiple($query, $since, $before, $buffer, $network, $sender, $truncatedLimit);
        $hasMore = $this->findInBufferMultipleCount($query, $since, $before, $buffer, $network, $sender, 0, $truncatedLimit);

        $buffermap = [];

        foreach ($messages as $message) {
            if (!array_key_exists($message['bufferid'], $buffermap)) {
                $buffermap[$message['bufferid']] = [
                    "bufferid" => $message['bufferid'],
                    "buffername" => $message['buffername'],
                    "networkname" => $message['networkname'],
                    "messages" => []
                ];
            }

            array_push($buffermap[$message['bufferid']]['messages'], $message);
        }

        foreach ($hasMore as $hasMoreResult) {
            if (!is_null($buffermap[$hasMoreResult['bufferid']]))
                $buffermap[$hasMoreResult['bufferid']]['hasmore'] = $hasMoreResult['hasmore'];
        }

        return array_values($buffermap);
    }

    public function findInBufferMultiple(string $query, int $since = null, int $before = null, string $buffer = null, string $network = null, string $sender = null, int $limit = 4): array
    {
        $ignore_since = $since === null;
        $ignore_before = $before === null;
        $ignore_network = $network === null;
        $ignore_buffer = $buffer === null;
        $ignore_sender = $sender === null;

        $stmt = $this->backend->findInBuffers();
        $this->apply_config($stmt);

        $stmt->bindParam(':userid', $this->user->userid, PDO::PARAM_INT);
        $stmt->bindParam(':query', $query, PDO::PARAM_STR);
        $stmt->bindParam(':limit', $limit, PDO::PARAM_INT);

        $stmt->bindValue(':since', !$ignore_since ? (string)$since : "1970-01-01", PDO::PARAM_STR);
        $stmt->bindValue(':before', !$ignore_before ? (string)$before : "1970-01-01", PDO::PARAM_STR);
        $stmt->bindValue(':buffer', !$ignore_buffer ? (string)$buffer : "", PDO::PARAM_STR);
        $stmt->bindValue(':network', !$ignore_network ? (string)$network : "", PDO::PARAM_STR);
        $stmt->bindValue(':sender', !$ignore_sender ? (string)$sender : "", PDO::PARAM_STR);
        $stmt->bindParam(':ignore_since', $ignore_since, PDO::PARAM_INT);
        $stmt->bindParam(':ignore_before', $ignore_before, PDO::PARAM_INT);
        $stmt->bindParam(':ignore_buffer', $ignore_network, PDO::PARAM_INT);
        $stmt->bindParam(':ignore_network', $ignore_buffer, PDO::PARAM_INT);
        $stmt->bindParam(':ignore_sender', $ignore_sender, PDO::PARAM_INT);

        $stmt->execute();
        return $stmt->fetchAll(\PDO::FETCH_ASSOC);
    }

    public function findInBufferMultipleCount(string $query, int $since = null, int $before = null, string $buffer = null, string $network = null, string $sender = null, int $offset = 0, int $limit = 4): array
    {
        $truncatedLimit = max(min($limit, 50), 0);
        $ignore_since = $since === null;
        $ignore_before = $before === null;
        $ignore_network = $network === null;
        $ignore_buffer = $buffer === null;
        $ignore_sender = $sender === null;

        $stmt = $this->backend->findInBuffersCount();

        $stmt->bindParam(':userid', $this->user->userid, PDO::PARAM_INT);
        $stmt->bindParam(':query', $query, PDO::PARAM_STR);

        $stmt->bindValue(':since', !$ignore_since ? (string)$since : "1970-01-01", PDO::PARAM_STR);
        $stmt->bindValue(':before', !$ignore_before ? (string)$before : "1970-01-01", PDO::PARAM_STR);
        $stmt->bindValue(':buffer', !$ignore_buffer ? (string)$buffer : "", PDO::PARAM_STR);
        $stmt->bindValue(':network', !$ignore_network ? (string)$network : "", PDO::PARAM_STR);
        $stmt->bindValue(':sender', !$ignore_sender ? (string)$sender : "", PDO::PARAM_STR);
        $stmt->bindParam(':ignore_since', $ignore_since, PDO::PARAM_INT);
        $stmt->bindParam(':ignore_before', $ignore_before, PDO::PARAM_INT);
        $stmt->bindParam(':ignore_buffer', $ignore_network, PDO::PARAM_INT);
        $stmt->bindParam(':ignore_network', $ignore_buffer, PDO::PARAM_INT);
        $stmt->bindParam(':ignore_sender', $ignore_sender, PDO::PARAM_INT);

        $stmt->bindParam(':limit', $truncatedLimit, PDO::PARAM_INT);
        $stmt->bindParam(':offset', $offset, PDO::PARAM_INT);

        $success = $stmt->execute();
        $result = $stmt->fetchAll(\PDO::FETCH_ASSOC);

        return $result;
    }

    public function findInBuffer(string $query, int $since = null, int $before = null, string $sender = null, int $bufferid, int $offset = 0, int $limit = 20): array
    {
        $truncatedLimit = max(min($limit, 50), 0);
        $ignore_since = $since === null;
        $ignore_before = $before === null;
        $ignore_sender = $sender === null;

        $stmt = $this->backend->findInBuffer();
        $this->apply_config($stmt);

        $stmt->bindParam(':userid', $this->user->userid, PDO::PARAM_INT);
        $stmt->bindParam(':bufferid', $bufferid, PDO::PARAM_INT);
        $stmt->bindParam(':query', $query, PDO::PARAM_STR);

        $stmt->bindValue(':since', !$ignore_since ? (string)$since : "1970-01-01", PDO::PARAM_STR);
        $stmt->bindValue(':before', !$ignore_before ? (string)$before : "1970-01-01", PDO::PARAM_STR);
        $stmt->bindValue(':sender', !$ignore_sender ? (string)$sender : "", PDO::PARAM_STR);
        $stmt->bindParam(':ignore_since', $ignore_since, PDO::PARAM_INT);
        $stmt->bindParam(':ignore_before', $ignore_before, PDO::PARAM_INT);
        $stmt->bindParam(':ignore_sender', $ignore_sender, PDO::PARAM_INT);

        $stmt->bindParam(':limit', $truncatedLimit, PDO::PARAM_INT);
        $stmt->bindParam(':offset', $offset, PDO::PARAM_INT);

        $stmt->execute();
        return [
            'results' => $stmt->fetchAll(\PDO::FETCH_ASSOC),
            'hasmore' => $this->findInBufferCount($query, $since, $before, $bufferid, $offset, $limit)
        ];
    }

    public function findInBufferCount(string $query, int $since = null, int $before = null, string $sender = null, int $bufferid, int $offset = 0, int $limit = 4): array
    {
        $truncatedLimit = max(min($limit, 50), 0);
        $ignore_since = $since === null;
        $ignore_before = $before === null;
        $ignore_sender = $sender === null;

        $stmt = $this->backend->findInBufferCount();

        $stmt->bindParam(':userid', $this->user->userid, PDO::PARAM_INT);
        $stmt->bindParam(':bufferid', $bufferid, PDO::PARAM_INT);
        $stmt->bindParam(':query', $query, PDO::PARAM_STR);

        $stmt->bindValue(':since', !$ignore_since ? (string)$since : "1970-01-01", PDO::PARAM_STR);
        $stmt->bindValue(':before', !$ignore_before ? (string)$before : "1970-01-01", PDO::PARAM_STR);
        $stmt->bindValue(':sender', !$ignore_sender ? (string)$sender : "", PDO::PARAM_STR);
        $stmt->bindParam(':ignore_since', $ignore_since, PDO::PARAM_INT);
        $stmt->bindParam(':ignore_before', $ignore_before, PDO::PARAM_INT);
        $stmt->bindParam(':ignore_sender', $ignore_sender, PDO::PARAM_INT);

        $stmt->bindParam(':limit', $truncatedLimit, PDO::PARAM_INT);
        $stmt->bindParam(':offset', $offset, PDO::PARAM_INT);

        $stmt->execute();
        return $stmt->fetchAll(\PDO::FETCH_ASSOC);
    }

    public function context(int $anchor, int $buffer, int $loadBefore, int $loadAfter): array
    {
        return array_merge(array_reverse($this->before($anchor, $buffer, $loadBefore)), $this->after($anchor, $buffer, $loadAfter));
    }

    public function before(int $anchor, int $buffer, int $limit): array
    {
        $truncatedLimit = max(min($limit, 50), 0);

        $stmt = $this->backend->loadBefore();

        $stmt->bindParam(":userid", $this->user->userid, PDO::PARAM_INT);
        $stmt->bindParam(":bufferid", $buffer, PDO::PARAM_INT);
        $stmt->bindParam(":anchor", $anchor, PDO::PARAM_INT);

        $stmt->bindParam(":limit", $truncatedLimit, PDO::PARAM_INT);

        $stmt->execute();
        return $stmt->fetchAll(\PDO::FETCH_ASSOC);
    }

    public function after(int $anchor, int $buffer, int $limit): array
    {
        $truncatedLimit = max(min($limit + 1, 50), 1);

        $stmt = $this->backend->loadAfter();

        $stmt->bindParam(":userid", $this->user->userid, PDO::PARAM_INT);
        $stmt->bindParam(":bufferid", $buffer, PDO::PARAM_INT);
        $stmt->bindParam(":anchor", $anchor, PDO::PARAM_INT);

        $stmt->bindParam(":limit", $truncatedLimit, PDO::PARAM_INT);

        $stmt->execute();
        return $stmt->fetchAll(\PDO::FETCH_ASSOC);
    }
}