construct/matrix/filter.cc

250 lines
5.3 KiB
C++

// Matrix Construct
//
// Copyright (C) Matrix Construct Developers, Authors & Contributors
// Copyright (C) 2016-2019 Jason Volk <jason@zemos.net>
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice is present in all copies. The
// full license for this software is available in the LICENSE file.
///////////////////////////////////////////////////////////////////////////////
//
// m/filter.h
//
bool
ircd::m::match(const room_event_filter &filter,
const event::idx &event_idx)
{
m::event::keys::include include_keys;
if(json::get<"contains_url"_>(filter))
include_keys.set("content");
if(json::get<"rooms"_>(filter) || json::get<"not_rooms"_>(filter))
include_keys.set("room_id");
if(json::get<"types"_>(filter) || json::get<"not_types"_>(filter))
include_keys.set("type");
if(json::get<"senders"_>(filter) || json::get<"not_senders"_>(filter))
include_keys.set("sender");
const m::event::fetch event
{
std::nothrow, event_idx, m::event::fetch::opts
{
include_keys,
}
};
if(unlikely(!event.valid))
return false;
return match(filter, event);
}
//TODO: globular expression
//TODO: tribool for contains_url; we currently ignore the false value.
bool
ircd::m::match(const room_event_filter &filter,
const event &event)
{
if(json::get<"contains_url"_>(filter) == true)
if(!json::get<"content"_>(event).has("url"))
return false;
for(const json::string room_id : json::get<"not_rooms"_>(filter))
if(json::get<"room_id"_>(event) == room_id)
return false;
if(empty(json::get<"rooms"_>(filter)))
return match(event_filter{filter}, event);
for(const json::string room_id : json::get<"rooms"_>(filter))
if(json::get<"room_id"_>(event) == room_id)
return match(event_filter{filter}, event);
return false;
}
bool
ircd::m::match(const event_filter &filter,
const event::idx &event_idx)
{
m::event::keys::include include_keys;
if(json::get<"types"_>(filter) || json::get<"not_types"_>(filter))
include_keys.set("type");
if(json::get<"senders"_>(filter) || json::get<"not_senders"_>(filter))
include_keys.set("sender");
const m::event::fetch event
{
std::nothrow, event_idx, m::event::fetch::opts
{
include_keys,
}
};
if(unlikely(!event.valid))
return false;
return match(filter, event);
}
//TODO: globular expression
bool
ircd::m::match(const event_filter &filter,
const event &event)
{
for(const json::string type : json::get<"not_types"_>(filter))
if(json::get<"type"_>(event) == type)
return false;
for(const json::string sender : json::get<"not_senders"_>(filter))
if(json::get<"sender"_>(event) == sender)
return false;
if(empty(json::get<"senders"_>(filter)) && empty(json::get<"types"_>(filter)))
return true;
if(empty(json::get<"senders"_>(filter)))
{
for(const json::string type : json::get<"types"_>(filter))
if(json::get<"type"_>(event) == type)
return true;
return false;
}
if(empty(json::get<"types"_>(filter)))
{
for(const json::string sender : json::get<"senders"_>(filter))
if(json::get<"sender"_>(event) == sender)
return true;
return false;
}
return true;
}
//
// filter
//
/// Convenience interface for filters out of common `?filter=` query string
/// arguments. This function expects a raw urlencoded value of the filter
/// query parameter. It detects if the value is an "inline" filter by being
/// a valid JSON object; otherwise it considers the value an ID and fetches
/// the filter stored previously by the user.
std::string
ircd::m::filter::get(const string_view &val,
const m::user &user)
{
if(!val)
return {};
const bool is_inline
{
startswith(val, "{") || startswith(val, "%7B")
};
if(is_inline)
return util::string(val.size(), [&val]
(const mutable_buffer &buf)
{
return url::decode(buf, val);
});
if(!user.user_id)
return {};
char idbuf[m::event::STATE_KEY_MAX_SIZE];
const string_view &id
{
url::decode(idbuf, val)
};
const m::user::filter filter
{
user
};
return filter.get(id);
}
//
// filter::filter
//
ircd::m::filter::filter(const user &user,
const string_view &filter_id,
const mutable_buffer &buf)
{
const json::object &obj
{
user::filter(user).get(buf, filter_id)
};
new (this) m::filter
{
obj
};
}
//
// room_filter
//
ircd::m::room_filter::room_filter(const mutable_buffer &buf,
const json::members &members)
:super_type::tuple
{
json::stringify(mutable_buffer{buf}, members)
}
{
}
//
// state_filter
//
ircd::m::state_filter::state_filter(const mutable_buffer &buf,
const json::members &members)
:super_type::tuple
{
json::stringify(mutable_buffer{buf}, members)
}
{
}
//
// room_event_filter
//
ircd::m::room_event_filter::room_event_filter(const mutable_buffer &buf,
const json::members &members)
:super_type::tuple
{
json::stringify(mutable_buffer{buf}, members)
}
{
}
//
// event_filter
//
ircd::m::event_filter::event_filter(const mutable_buffer &buf,
const json::members &members)
:super_type::tuple
{
json::stringify(mutable_buffer{buf}, members)
}
{
}