From 7b5bf6d34b5e093f1fe7285b3427e923d2c841b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timoth=C3=A9e=20Jaussoin?= Date: Fri, 1 Aug 2025 15:14:30 +0200 Subject: [PATCH] Add a MAMEarliest table to keep track of the earliest message when requesting MAM Get MAM when MAMEarliest is not there --- CHANGELOG.md | 1 + app/MAMEarliest.php | 17 ++++ app/User.php | 5 ++ app/Widgets/Chat/Chat.php | 78 +++++++++++++++---- app/Widgets/Chats/Chats.php | 5 +- ...0801115140_create_m_a_m_earliest_table.php | 31 ++++++++ src/Moxl/Xec/Action/MAM/Get.php | 35 +++++++-- 7 files changed, 149 insertions(+), 23 deletions(-) create mode 100644 app/MAMEarliest.php create mode 100644 database/migrations/20250801115140_create_m_a_m_earliest_table.php diff --git a/CHANGELOG.md b/CHANGELOG.md index 6b09b1fed..4a8c8c90f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ v0.31.1 (master) --------------------------- * Add a copy external link button on the Posts * Improve the Communities discovery flow when visiting a server +* Add a MAMEarliest table to keep track of the earliest message when requesting MAM v0.31 --------------------------- diff --git a/app/MAMEarliest.php b/app/MAMEarliest.php new file mode 100644 index 000000000..3281dc0f0 --- /dev/null +++ b/app/MAMEarliest.php @@ -0,0 +1,17 @@ +belongsTo('App\User'); + } +} diff --git a/app/User.php b/app/User.php index 965dc76bb..b1b274f97 100644 --- a/app/User.php +++ b/app/User.php @@ -60,6 +60,11 @@ class User extends Model return $this->hasMany('App\Message'); } + public function MAMEarliests() + { + return $this->hasMany('App\MAMEarliest'); + } + public function openChats() { return $this->hasMany('App\OpenChat'); diff --git a/app/Widgets/Chat/Chat.php b/app/Widgets/Chat/Chat.php index e207cb8aa..ad4e84410 100644 --- a/app/Widgets/Chat/Chat.php +++ b/app/Widgets/Chat/Chat.php @@ -9,6 +9,7 @@ use Moxl\Xec\Action\Muc\GetConfig; use Moxl\Xec\Action\Muc\SetConfig; use App\Contact; +use App\MAMEarliest; use App\Message; use App\MessageFile; use App\MessageOmemoHeader; @@ -21,6 +22,7 @@ use App\Widgets\Dictaphone\Dictaphone; use App\Widgets\Notif\Notif; use App\Widgets\Post\Post; use App\Widgets\Toast\Toast; +use Carbon\Carbon; use Moxl\Xec\Action\BOB\Request; use Moxl\Xec\Action\Disco\Request as DiscoRequest; @@ -39,12 +41,23 @@ class Chat extends \Movim\Widget\Base private $_pagination = 50; private $_wrapper = []; private $_messageTypes = [ - 'chat', 'headline', 'invitation', - 'jingle_incoming', 'jingle_outgoing', 'jingle_end', 'jingle_retract', 'jingle_reject' + 'chat', + 'headline', + 'invitation', + 'jingle_incoming', + 'jingle_outgoing', + 'jingle_end', + 'jingle_retract', + 'jingle_reject' ]; private $_messageTypesMuc = [ - 'groupchat', 'muji_propose', 'muji_retract', - 'muc_owner', 'muc_admin', 'muc_outcast', 'muc_member' + 'groupchat', + 'muji_propose', + 'muji_retract', + 'muc_owner', + 'muc_admin', + 'muc_outcast', + 'muc_member' ]; private $_mucPresences = []; @@ -177,9 +190,17 @@ class Chat extends \Movim\Widget\Base if ( $message->isEmpty() && !in_array($message->type, [ - 'jingle_incoming', 'jingle_outgoing', 'jingle_end', 'muc_owner', 'jingle_retract', 'jingle_reject', - 'muji_propose', 'muji_retract', - 'muc_admin', 'muc_outcast', 'muc_member' + 'jingle_incoming', + 'jingle_outgoing', + 'jingle_end', + 'muc_owner', + 'jingle_retract', + 'jingle_reject', + 'muji_propose', + 'muji_retract', + 'muc_admin', + 'muc_outcast', + 'muc_member' ]) ) { return; @@ -453,7 +474,7 @@ class Chat extends \Movim\Widget\Base ->where('jid', $jid) ->select(['bundleid', 'jid']) ->get() - ->mapToGroups(fn ($tuple) => [$tuple['jid'] => $tuple['bundleid']]) + ->mapToGroups(fn($tuple) => [$tuple['jid'] => $tuple['bundleid']]) ->toArray() ); } @@ -513,7 +534,7 @@ class Chat extends \Movim\Widget\Base }) ->select(['bundleid', 'jid']) ->get() - ->mapToGroups(fn ($tuple) => [$tuple['jid'] => $tuple['bundleid']]) + ->mapToGroups(fn($tuple) => [$tuple['jid'] => $tuple['bundleid']]) ->toArray() ); } @@ -872,7 +893,7 @@ class Chat extends \Movim\Widget\Base ->delete(); } - $newEmojis = $emojis->filter(fn ($value, $key) => $value->emoji != $emoji); + $newEmojis = $emojis->filter(fn($value, $key) => $value->emoji != $emoji); } $r->setTo($parentMessage->jidfrom != $parentMessage->user_id @@ -1159,7 +1180,7 @@ class Chat extends \Movim\Widget\Base * * @param string $jid */ - public function ajaxClearHistoryConfirm($jid) + public function ajaxClearHistoryConfirm(string $jid) { if (!validateJid($jid)) { return; @@ -1181,6 +1202,8 @@ class Chat extends \Movim\Widget\Base )->where('user_id', $this->user->id); })->delete(); + $this->user->MAMEarliests()->where('jid', $jid)->delete(); + $this->ajaxGet($jid); } @@ -1275,6 +1298,29 @@ class Chat extends \Movim\Widget\Base if ($unreadsCount > 0) { $this->rpc('Chat.insertSeparator', $unreadsCount); } + + // Do we need to query MAM? + if ($messages->isEmpty()) { + $earliest = MAMEarliest::query(); + $earliest = $muc ? $earliest->where('to', $jid) + : $earliest->where('jid', $jid); + + if (!$earliest->first()) { + $this->rpc('Chat.getHistory', true); + } + } elseif ($messages->count() < $this->_pagination) { + $earliest = MAMEarliest::query(); + $earliest = $muc ? $earliest->where('to', $jid) + : $earliest->where('jid', $jid); + $me = $earliest->first(); + + if ( + !$me || + (new Carbon($me->earliest))->isAfter(new Carbon($messages->first()->published)) + ) { + $this->rpc('Chat.getHistory', true); + } + } } public function prepareMessage(&$message, $jid = null) @@ -1581,8 +1627,14 @@ class Chat extends \Movim\Widget\Base // Internal messages if (in_array($message->type, [ - 'muc_owner', 'muc_admin', 'muc_outcast', 'muc_member', - 'jingle_reject', 'jingle_incoming', 'jingle_outgoing', 'jingle_retract', + 'muc_owner', + 'muc_admin', + 'muc_outcast', + 'muc_member', + 'jingle_reject', + 'jingle_incoming', + 'jingle_outgoing', + 'jingle_retract', 'muji_propose' ])) { $view = $this->tpl(); diff --git a/app/Widgets/Chats/Chats.php b/app/Widgets/Chats/Chats.php index 5d1155c37..208f97657 100644 --- a/app/Widgets/Chats/Chats.php +++ b/app/Widgets/Chats/Chats.php @@ -182,8 +182,9 @@ class Chats extends Base if ($message && $message->published) { $g->setStart(strtotime($message->published) + 1); } else { - // We only sync up the last month the first time - $g->setStart(\Carbon\Carbon::now()->subMonth()->timestamp); + // We sync up the last 500 messages at first + $g->setLimit(500); + $g->setBefore(''); } $g->request(); diff --git a/database/migrations/20250801115140_create_m_a_m_earliest_table.php b/database/migrations/20250801115140_create_m_a_m_earliest_table.php new file mode 100644 index 000000000..dbb9d2e48 --- /dev/null +++ b/database/migrations/20250801115140_create_m_a_m_earliest_table.php @@ -0,0 +1,31 @@ +schema->create('mam_earliest', function (Blueprint $table) { + $table->increments('id'); + + $table->string('user_id'); + $table->string('to')->nullable(); + $table->string('jid')->nullable(); + $table->dateTime('earliest'); + + $table->foreign('user_id')->references('id') + ->on('users')->onDelete('cascade'); + + $table->timestamps(); + + $table->unique(['user_id', 'to', 'jid']); + }); + } + + public function down() + { + $this->schema->drop('mam_earliest'); + } +} diff --git a/src/Moxl/Xec/Action/MAM/Get.php b/src/Moxl/Xec/Action/MAM/Get.php index 56ed5ca30..364b79ec7 100644 --- a/src/Moxl/Xec/Action/MAM/Get.php +++ b/src/Moxl/Xec/Action/MAM/Get.php @@ -2,6 +2,7 @@ namespace Moxl\Xec\Action\MAM; +use App\MAMEarliest; use Moxl\Xec\Action; use Moxl\Stanza\MAM; use Movim\Session; @@ -9,14 +10,14 @@ use Movim\Session; class Get extends Action { - protected $_queryid; - protected $_to; - protected $_jid; - protected $_start; - protected $_end; - protected $_limit; - protected $_after; - protected $_before; + protected ?string $_to = null; + protected ?string $_queryid = null; + protected ?string $_jid = null; + protected ?int $_start = null; + protected ?int $_end = null; + protected ?int $_limit = null; + protected ?string $_after = null; + protected ?string $_before = null; protected string $_version = '2'; protected int $_messageCounter = 0; @@ -61,6 +62,24 @@ class Get extends Action $totalCounter = $this->_messageCounter + $messagesCounter; + if ( + isset($stanza->fin->set) + && $stanza->fin->set->attributes()->xmlns == 'http://jabber.org/protocol/rsm' + && $stanza->fin->set->count == 0 + && ( + ($this->_end != null && $this->_start == null) + || + ($this->_end == null && $this->_start == null && $this->_before == '') + ) + ) { + $earliest = new MAMEarliest; + $earliest->user_id = \App\User::me()->id; + $earliest->to = $this->_to; + $earliest->jid = $this->_jid; + $earliest->earliest = date(MOVIM_SQL_DATE, $this->_end ?? time()); + $earliest->save(); + } + if ( isset($stanza->fin) && (!isset($stanza->fin->attributes()->complete) || $stanza->fin->attributes()->complete != 'true')