<commit_before><?php

use Movim\Widget\Base;
use Illuminate\Database\Capsule\Manager as DB;

use Respect\Validation\Validator;

use App\Contact;
use App\Message;
use App\Roster;

class Chats extends Base
{
    public function load()
    {
        $this->addcss('chats.css');
        $this->addjs('chats.js');
        $this->registerEvent('session_start_handle', 'onStart');
        $this->registerEvent('receiptack', 'onMessage', 'chat');
        $this->registerEvent('displayed', 'onMessage', 'chat');
        $this->registerEvent('retracted', 'onMessage', 'chat');
        $this->registerEvent('carbons', 'onMessage');
        $this->registerEvent('message', 'onMessage');
        $this->registerEvent('presence', 'onPresence'/*, 'chat'*/);
        $this->registerEvent('chatstate', 'onChatState', 'chat');
        // Bug: In Chat::ajaxGet, Notification.current might come after this event
        // so we don't set the filter
        $this->registerEvent('chat_open', 'onChatOpen', /* 'chat'*/);
    }

    public function onStart($packet)
    {
        $tpl = $this->tpl();
        $tpl->cacheClear('_chats_item');
    }

    public function onMessage($packet)
    {
        $message = $packet->content;

        if ($message->type != 'groupchat') {
            // If the message is from me
            if ($message->user_id == $message->jidto) {
                $from = $message->jidfrom;
            } else {
                $from = $message->jidto;
            }

            $this->ajaxOpen($from, false);
        }
    }

    public function onChatOpen($jid)
    {
        if (!$this->validateJid($jid)) {
            return;
        }

        $this->rpc(
            'MovimTpl.replace',
            '#' . cleanupId($jid . '_chat_item'),
            $this->prepareChat(
                $jid,
                $this->resolveContactFromJid($jid),
                $this->resolveRosterFromJid($jid),
                $this->resolveMessageFromJid($jid)
            )
        );
        $this->rpc('Chats.setActive', $jid);
        $this->rpc('Chats.refresh');
    }

    public function onPresence($packet)
    {
        if ($packet->content != null) {
            $chats = \App\Cache::c('chats');
            if (is_array($chats) &&  array_key_exists($packet->content->jid, $chats)) {
                $this->rpc(
                    'MovimTpl.replace',
                    '#' . cleanupId($packet->content->jid.'_chat_item'),
                    $this->prepareChat(
                        $packet->content->jid,
                        $this->resolveContactFromJid($packet->content->jid),
                        $this->resolveRosterFromJid($packet->content->jid),
                        $this->resolveMessageFromJid($packet->content->jid)
                    )
                );
                $this->rpc('Chats.refresh');
            }
        }
    }

    public function onChatState(array $array)
    {
        $this->setState($array[0], isset($array[1]));
    }

    private function setState(string $jid, bool $composing)
    {
        $chats = \App\Cache::c('chats');
        if (is_array($chats) &&  array_key_exists($jid, $chats)) {
            $this->rpc(
                $composing
                    ? 'MovimUtils.addClass'
                    : 'MovimUtils.removeClass',
                '#' . cleanupId($jid.'_chat_item') . ' span.primary',
                'composing'
            );
        }
    }

    public function ajaxHttpGet()
    {
        $this->rpc('MovimTpl.fill', '#chats_widget_list', $this->prepareChats());
        $this->rpc('Chats.refresh');
    }

    /**
     * @brief Get history
     */
    public function ajaxGetHistory($jid = false)
    {
        // The following requests seems to be heavy if the user has no
        // messages yet in the database
        $empty = ($this->user->messages()->count() == 0);

        $g = new \Moxl\Xec\Action\MAM\Get;

        if ($jid == false) {
            if (!$empty) {
                $message = $this->user->messages()
                                ->orderBy('published', 'desc')
                                ->first();

                if ($message) {
                    $g->setStart(strtotime($message->published));
                }
            }

            $g->setLimit(150);
            $g->request();
        } elseif ($this->validateJid($jid)) {
            if (!$empty) {
                $message = \App\Message::jid($jid)
                                       ->orderBy('published', 'desc')
                                       ->first();

                if ($message) {
                    $g->setStart(strtotime($message->published));
                }
            }

            $g->setJid(echapJid($jid));
            $g->request();<commit_msg>Fix an anoying performance issue in PostgreSQL, see https://stackoverflow.com/questions/40365098/why-is-postgres-not-using-my-index-on-a-simple-order-by-limit-1<commit_after><?php

use Movim\Widget\Base;
use Illuminate\Database\Capsule\Manager as DB;

use Respect\Validation\Validator;

use App\Contact;
use App\Message;
use App\Roster;

class Chats extends Base
{
    public function load()
    {
        $this->addcss('chats.css');
        $this->addjs('chats.js');
        $this->registerEvent('session_start_handle', 'onStart');
        $this->registerEvent('receiptack', 'onMessage', 'chat');
        $this->registerEvent('displayed', 'onMessage', 'chat');
        $this->registerEvent('retracted', 'onMessage', 'chat');
        $this->registerEvent('carbons', 'onMessage');
        $this->registerEvent('message', 'onMessage');
        $this->registerEvent('presence', 'onPresence'/*, 'chat'*/);
        $this->registerEvent('chatstate', 'onChatState', 'chat');
        // Bug: In Chat::ajaxGet, Notification.current might come after this event
        // so we don't set the filter
        $this->registerEvent('chat_open', 'onChatOpen', /* 'chat'*/);
    }

    public function onStart($packet)
    {
        $tpl = $this->tpl();
        $tpl->cacheClear('_chats_item');
    }

    public function onMessage($packet)
    {
        $message = $packet->content;

        if ($message->type != 'groupchat') {
            // If the message is from me
            if ($message->user_id == $message->jidto) {
                $from = $message->jidfrom;
            } else {
                $from = $message->jidto;
            }

            $this->ajaxOpen($from, false);
        }
    }

    public function onChatOpen($jid)
    {
        if (!$this->validateJid($jid)) {
            return;
        }

        $this->rpc(
            'MovimTpl.replace',
            '#' . cleanupId($jid . '_chat_item'),
            $this->prepareChat(
                $jid,
                $this->resolveContactFromJid($jid),
                $this->resolveRosterFromJid($jid),
                $this->resolveMessageFromJid($jid)
            )
        );
        $this->rpc('Chats.setActive', $jid);
        $this->rpc('Chats.refresh');
    }

    public function onPresence($packet)
    {
        if ($packet->content != null) {
            $chats = \App\Cache::c('chats');
            if (is_array($chats) &&  array_key_exists($packet->content->jid, $chats)) {
                $this->rpc(
                    'MovimTpl.replace',
                    '#' . cleanupId($packet->content->jid.'_chat_item'),
                    $this->prepareChat(
                        $packet->content->jid,
                        $this->resolveContactFromJid($packet->content->jid),
                        $this->resolveRosterFromJid($packet->content->jid),
                        $this->resolveMessageFromJid($packet->content->jid)
                    )
                );
                $this->rpc('Chats.refresh');
            }
        }
    }

    public function onChatState(array $array)
    {
        $this->setState($array[0], isset($array[1]));
    }

    private function setState(string $jid, bool $composing)
    {
        $chats = \App\Cache::c('chats');
        if (is_array($chats) &&  array_key_exists($jid, $chats)) {
            $this->rpc(
                $composing
                    ? 'MovimUtils.addClass'
                    : 'MovimUtils.removeClass',
                '#' . cleanupId($jid.'_chat_item') . ' span.primary',
                'composing'
            );
        }
    }

    public function ajaxHttpGet()
    {
        $this->rpc('MovimTpl.fill', '#chats_widget_list', $this->prepareChats());
        $this->rpc('Chats.refresh');
    }

    /**
     * @brief Get history
     */
    public function ajaxGetHistory($jid = false)
    {
        $g = new \Moxl\Xec\Action\MAM\Get;

        // The following requests seems to be heavy for PostgreSQL
        // see https://stackoverflow.com/questions/40365098/why-is-postgres-not-using-my-index-on-a-simple-order-by-limit-1
        // a little hack is needed to use corectly the indexes
        if ($jid == false) {
            $message = $this->user->messages();

            $message = (DB::getDriverName() == 'pgsql')
                ? $message->orderByRaw('published desc nulls last')
                : $message->orderBy('published', 'desc');
            $message = $message->first();

            if ($message && $message->published) {
                $g->setStart(strtotime($message->published));
            }

            $g->setLimit(150);
            $g->request();
        } elseif ($this->validateJid($jid)) {
            $message = \App\Message::jid($jid);

            $message = (DB::getDriverName() == 'pgsql')
                ? $message->orderByRaw('published desc nulls last')
                : $message->orderBy('published', 'desc');
            $message = $message->first();

            if ($message && $message->published) {
                $g->setStart(strtotime($message->published));
            }

            $g->setJid(echapJid($jid));
            $g->request();
{'fraction_non_alphanumeric': 0.1602221100454316, 'fraction_numerical': 0.00292781423523473, 'mean_word_length': 1.7162051000822593, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 144, 'https://': 2, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4091957', 'n_tokens_mistral': 2981, 'n_tokens_neox': 2865, 'n_words': 468}