MAM results can be filtered by start and end dates
This commit is contained in:
@@ -29,6 +29,7 @@ Usage
|
|||||||
-----
|
-----
|
||||||
Read `the documentation`_.
|
Read `the documentation`_.
|
||||||
|
|
||||||
|
|
||||||
Authors
|
Authors
|
||||||
-------
|
-------
|
||||||
Florent Le Coz (louiz’) <louiz@louiz.org>
|
Florent Le Coz (louiz’) <louiz@louiz.org>
|
||||||
|
|||||||
@@ -30,6 +30,7 @@
|
|||||||
#define MAM_NS "urn:xmpp:mam:1"
|
#define MAM_NS "urn:xmpp:mam:1"
|
||||||
#define FORWARD_NS "urn:xmpp:forward:0"
|
#define FORWARD_NS "urn:xmpp:forward:0"
|
||||||
#define CLIENT_NS "jabber:client"
|
#define CLIENT_NS "jabber:client"
|
||||||
|
#define DATAFORM_NS "jabber:x:data"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An XMPP component, communicating with an XMPP server using the protocole
|
* An XMPP component, communicating with an XMPP server using the protocole
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
#include <irc/iid.hpp>
|
#include <irc/iid.hpp>
|
||||||
#include <uuid.h>
|
#include <uuid.h>
|
||||||
#include <utils/get_first_non_empty.hpp>
|
#include <utils/get_first_non_empty.hpp>
|
||||||
|
#include <utils/time.hpp>
|
||||||
|
|
||||||
using namespace std::string_literals;
|
using namespace std::string_literals;
|
||||||
|
|
||||||
@@ -136,14 +137,30 @@ void Database::store_muc_message(const std::string& owner, const Iid& iid,
|
|||||||
line.update();
|
line.update();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<db::MucLogLine> Database::get_muc_logs(const std::string& owner, const std::string& chan_name, const std::string& server, int limit)
|
std::vector<db::MucLogLine> Database::get_muc_logs(const std::string& owner, const std::string& chan_name, const std::string& server,
|
||||||
|
int limit, const std::string& start, const std::string& end)
|
||||||
{
|
{
|
||||||
if (limit == -1)
|
auto request = litesql::select<db::MucLogLine>(*Database::db,
|
||||||
limit = 1024;
|
db::MucLogLine::Owner == owner &&
|
||||||
const auto& res = litesql::select<db::MucLogLine>(*Database::db,
|
db::MucLogLine::IrcChanName == chan_name &&
|
||||||
db::MucLogLine::Owner == owner &&
|
db::MucLogLine::IrcServerName == server);
|
||||||
db::MucLogLine::IrcChanName == chan_name &&
|
request.orderBy(db::MucLogLine::Id, false);
|
||||||
db::MucLogLine::IrcServerName == server).orderBy(db::MucLogLine::Id, false).limit(limit).all();
|
|
||||||
|
if (limit >= 0)
|
||||||
|
request.limit(limit);
|
||||||
|
if (!start.empty())
|
||||||
|
{
|
||||||
|
const auto start_time = utils::parse_datetime(start);
|
||||||
|
if (start_time != -1)
|
||||||
|
request.where(db::MucLogLine::Date >= start_time);
|
||||||
|
}
|
||||||
|
if (!end.empty())
|
||||||
|
{
|
||||||
|
const auto end_time = utils::parse_datetime(end);
|
||||||
|
if (end_time != -1)
|
||||||
|
request.where(db::MucLogLine::Date <= end_time);
|
||||||
|
}
|
||||||
|
const auto& res = request.all();
|
||||||
return {res.crbegin(), res.crend()};
|
return {res.crbegin(), res.crend()};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -152,7 +169,6 @@ void Database::close()
|
|||||||
Database::db.reset(nullptr);
|
Database::db.reset(nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
std::string Database::gen_uuid()
|
std::string Database::gen_uuid()
|
||||||
{
|
{
|
||||||
char uuid_str[37];
|
char uuid_str[37];
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ public:
|
|||||||
const std::string& server,
|
const std::string& server,
|
||||||
const std::string& channel);
|
const std::string& channel);
|
||||||
static std::vector<db::MucLogLine> get_muc_logs(const std::string& owner, const std::string& chan_name, const std::string& server,
|
static std::vector<db::MucLogLine> get_muc_logs(const std::string& owner, const std::string& chan_name, const std::string& server,
|
||||||
int limit);
|
int limit=-1, const std::string& before="", const std::string& after="");
|
||||||
static void store_muc_message(const std::string& owner, const Iid& iid,
|
static void store_muc_message(const std::string& owner, const Iid& iid,
|
||||||
time_point date, const std::string& body, const std::string& nick);
|
time_point date, const std::string& body, const std::string& nick);
|
||||||
|
|
||||||
|
|||||||
@@ -550,13 +550,36 @@ bool BiboumiComponent::handle_mam_request(const Stanza& stanza)
|
|||||||
Iid iid(to.local, {'#', '&'});
|
Iid iid(to.local, {'#', '&'});
|
||||||
if (iid.type == Iid::Type::Channel && to.resource.empty())
|
if (iid.type == Iid::Type::Channel && to.resource.empty())
|
||||||
{
|
{
|
||||||
const auto lines = Database::get_muc_logs(from.bare(), iid.get_local(), iid.get_server(), -1);
|
std::string start;
|
||||||
for (const db::MucLogLine& line: lines)
|
std::string end;
|
||||||
{
|
const XmlNode* x = query->get_child("x", DATAFORM_NS);
|
||||||
const auto queryid = query->get_tag("queryid");
|
if (x)
|
||||||
if (!line.nick.value().empty())
|
{
|
||||||
this->send_archived_message(line, to.full(), from.full(), queryid);
|
const XmlNode* value;
|
||||||
}
|
const auto fields = x->get_children("field", DATAFORM_NS);
|
||||||
|
for (const auto& field: fields)
|
||||||
|
{
|
||||||
|
if (field->get_tag("var") == "start")
|
||||||
|
{
|
||||||
|
value = field->get_child("value", DATAFORM_NS);
|
||||||
|
if (value)
|
||||||
|
start = value->get_inner();
|
||||||
|
}
|
||||||
|
else if (field->get_tag("var") == "end")
|
||||||
|
{
|
||||||
|
value = field->get_child("value", DATAFORM_NS);
|
||||||
|
if (value)
|
||||||
|
end = value->get_inner();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const auto lines = Database::get_muc_logs(from.bare(), iid.get_local(), iid.get_server(), -1, start, end);
|
||||||
|
for (const db::MucLogLine& line: lines)
|
||||||
|
{
|
||||||
|
const auto queryid = query->get_tag("queryid");
|
||||||
|
if (!line.nick.value().empty())
|
||||||
|
this->send_archived_message(line, to.full(), from.full(), queryid);
|
||||||
|
}
|
||||||
this->send_iq_result_full_jid(id, from.full(), to.full());
|
this->send_iq_result_full_jid(id, from.full(), to.full());
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1086,8 +1086,32 @@ if __name__ == '__main__':
|
|||||||
),
|
),
|
||||||
|
|
||||||
partial(expect_stanza,
|
partial(expect_stanza,
|
||||||
"/iq[@type='result'][@id='id1'][@from='#foo%{irc_server_one}'][@to='{jid_one}/{resource_one}']")
|
"/iq[@type='result'][@id='id1'][@from='#foo%{irc_server_one}'][@to='{jid_one}/{resource_one}']"),
|
||||||
|
|
||||||
|
# Retrieve an empty archive by specifying an early “end” date
|
||||||
|
partial(send_stanza, """<iq to='#foo%{irc_server_one}' from='{jid_one}/{resource_one}' type='set' id='id2'>
|
||||||
|
<query xmlns='urn:xmpp:mam:1' queryid='qid2'>
|
||||||
|
<x xmlns='jabber:x:data' type='submit'>
|
||||||
|
<field var='FORM_TYPE' type='hidden'> <value>urn:xmpp:mam:1</value></field>
|
||||||
|
<field var='end'><value>2000-06-07T00:00:00Z</value></field>
|
||||||
|
</x>
|
||||||
|
</query></iq>"""),
|
||||||
|
|
||||||
|
partial(expect_stanza,
|
||||||
|
"/iq[@type='result'][@id='id2'][@from='#foo%{irc_server_one}'][@to='{jid_one}/{resource_one}']"),
|
||||||
|
|
||||||
|
# Retrieve an empty archive by specifying a late “start” date
|
||||||
|
# (note that this test will break in ~1000 years)
|
||||||
|
partial(send_stanza, """<iq to='#foo%{irc_server_one}' from='{jid_one}/{resource_one}' type='set' id='id3'>
|
||||||
|
<query xmlns='urn:xmpp:mam:1' queryid='qid3'>
|
||||||
|
<x xmlns='jabber:x:data' type='submit'>
|
||||||
|
<field var='FORM_TYPE' type='hidden'> <value>urn:xmpp:mam:1</value></field>
|
||||||
|
<field var='start'><value>3016-06-07T00:00:00Z</value></field>
|
||||||
|
</x>
|
||||||
|
</query></iq>"""),
|
||||||
|
|
||||||
|
partial(expect_stanza,
|
||||||
|
"/iq[@type='result'][@id='id3'][@from='#foo%{irc_server_one}'][@to='{jid_one}/{resource_one}']"),
|
||||||
]),
|
]),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user