~singpolyma/biboumi

3047bd41b212390da8e3a4dbcf351e79879042dd — louiz’ 8 years ago 1140db3
MAM results can be filtered by start and end dates
M README.rst => README.rst +1 -0
@@ 29,6 29,7 @@ Usage
-----
Read `the documentation`_.


Authors
-------
Florent Le Coz (louiz’) <louiz@louiz.org>

M louloulibs/xmpp/xmpp_component.hpp => louloulibs/xmpp/xmpp_component.hpp +1 -0
@@ 30,6 30,7 @@
#define MAM_NS           "urn:xmpp:mam:1"
#define FORWARD_NS       "urn:xmpp:forward:0"
#define CLIENT_NS        "jabber:client"
#define DATAFORM_NS      "jabber:x:data"

/**
 * An XMPP component, communicating with an XMPP server using the protocole

M src/database/database.cpp => src/database/database.cpp +24 -8
@@ 6,6 6,7 @@
#include <irc/iid.hpp>
#include <uuid.h>
#include <utils/get_first_non_empty.hpp>
#include <utils/time.hpp>

using namespace std::string_literals;



@@ 136,14 137,30 @@ void Database::store_muc_message(const std::string& owner, const Iid& iid,
  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)
    limit = 1024;
  const auto& res = litesql::select<db::MucLogLine>(*Database::db,
                                                   db::MucLogLine::Owner == owner &&
                                                   db::MucLogLine::IrcChanName == chan_name &&
                                                   db::MucLogLine::IrcServerName == server).orderBy(db::MucLogLine::Id, false).limit(limit).all();
  auto request = litesql::select<db::MucLogLine>(*Database::db,
                                              db::MucLogLine::Owner == owner &&
                                              db::MucLogLine::IrcChanName == chan_name &&
                                              db::MucLogLine::IrcServerName == server);
  request.orderBy(db::MucLogLine::Id, false);

  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()};
}



@@ 152,7 169,6 @@ void Database::close()
  Database::db.reset(nullptr);
}


std::string Database::gen_uuid()
{
  char uuid_str[37];

M src/database/database.hpp => src/database/database.hpp +1 -1
@@ 49,7 49,7 @@ public:
                                                                                      const std::string& server,
                                                                                      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,
                                                  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,
                                time_point date, const std::string& body, const std::string& nick);


M src/xmpp/biboumi_component.cpp => src/xmpp/biboumi_component.cpp +30 -7
@@ 550,13 550,36 @@ bool BiboumiComponent::handle_mam_request(const Stanza& stanza)
    Iid iid(to.local, {'#', '&'});
    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);
          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);
            }
        std::string start;
        std::string end;
        const XmlNode* x = query->get_child("x", DATAFORM_NS);
        if (x)
          {
            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());
        return true;
      }

M tests/end_to_end/__main__.py => tests/end_to_end/__main__.py +25 -1
@@ 1086,8 1086,32 @@ if __name__ == '__main__':
                            ),

                    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}']"),
                ]),
    )