0
0
Fork 0
mirror of https://github.com/matrix-construct/construct synced 2024-12-27 07:54:05 +01:00

ircd:Ⓜ️:room: Reorg / slim the class member function interface.

ircd:Ⓜ️:room: Rename interface function.
This commit is contained in:
Jason Volk 2019-08-14 01:01:46 -07:00
parent 67f6a36b3f
commit fca330e1c1
29 changed files with 250 additions and 244 deletions

View file

@ -25,19 +25,27 @@ namespace ircd::m
bool operator!=(const room &, const room &); // room_id inequality bool operator!=(const room &, const room &); // room_id inequality
bool operator==(const room &, const room &); // room_id equality bool operator==(const room &, const room &); // room_id equality
// [GET] Util // [GET] Convenience boolean suite
bool exists(const room &); bool exists(const room &);
bool exists(const id::room &); bool exists(const id::room &);
bool exists(const id::room_alias &, const bool &remote = false); bool exists(const id::room_alias &, const bool &remote = false);
bool internal(const id::room &); bool internal(const id::room &);
bool federate(const id::room &); bool federated(const id::room &);
id::user::buf creator(const id::room &);
bool creator(const id::room &, const id::user &); bool creator(const id::room &, const id::user &);
bool membership(const room &, const id::user &, const string_view & = "join");
bool join_rule(const room &, const string_view &rule);
bool visible(const room &, const string_view &mxid, const m::event *const & = nullptr);
bool local_only(const room &);
// [GET] Convenience and tools
id::user::buf creator(const id::room &);
string_view type(const mutable_buffer &, const room &); string_view type(const mutable_buffer &, const room &);
string_view version(const mutable_buffer &, const room &, std::nothrow_t); string_view version(const mutable_buffer &, const room &, std::nothrow_t);
string_view version(const mutable_buffer &, const room &); string_view version(const mutable_buffer &, const room &);
string_view join_rule(const mutable_buffer &out, const room &);
string_view membership(const mutable_buffer &out, const room &, const m::id::user &);
id::user::buf any_user(const room &, const string_view &host, const string_view &memshp = "join");
// [GET]
id::room room_id(const mutable_buffer &, const id::room_alias &); id::room room_id(const mutable_buffer &, const id::room_alias &);
id::room room_id(const mutable_buffer &, const string_view &id_or_alias); id::room room_id(const mutable_buffer &, const string_view &id_or_alias);
id::room::buf room_id(const id::room_alias &); id::room::buf room_id(const id::room_alias &);
@ -149,15 +157,6 @@ struct ircd::m::room
event::idx get(std::nothrow_t, const string_view &type) const; event::idx get(std::nothrow_t, const string_view &type) const;
event::idx get(const string_view &type) const; event::idx get(const string_view &type) const;
// misc / convenience utils
bool membership(const m::id::user &, const string_view &membership = "join") const;
string_view membership(const mutable_buffer &out, const m::id::user &) const;
bool visible(const string_view &mxid, const m::event *const & = nullptr) const;
string_view join_rule(const mutable_buffer &out) const;
id::user::buf any_user(const string_view &host, const string_view &membership = "join") const;
bool join_rule(const string_view &rule) const;
bool lonly() const;
room(const id &room_id, room(const id &room_id,
const string_view &event_id, const string_view &event_id,
const vm::copts *const &copts = nullptr, const vm::copts *const &copts = nullptr,

View file

@ -1623,13 +1623,13 @@ ircd::m::v1::fetch_head(const id::room &room_id,
// generate a random one from our host as well. // generate a random one from our host as well.
m::user::id::buf user_id m::user::id::buf user_id
{ {
room.any_user(my_host(), "join") any_user(room, my_host(), "join")
}; };
// Make another attempt to find an invited user because that carries some // Make another attempt to find an invited user because that carries some
// value (this query is not as fast as querying join memberships). // value (this query is not as fast as querying join memberships).
if(!user_id) if(!user_id)
user_id = room.any_user(my_host(), "invite"); user_id = any_user(room, my_host(), "invite");
return fetch_head(room_id, remote, user_id); return fetch_head(room_id, remote, user_id);
} }

View file

@ -985,6 +985,99 @@ ircd::m::top(std::nothrow_t,
return ret; return ret;
} }
ircd::m::id::user::buf
ircd::m::any_user(const room &room,
const string_view &host,
const string_view &membership)
{
user::id::buf ret;
const room::members members{room};
members.for_each(membership, [&host, &ret]
(const auto &user_id, const auto &event_idx)
{
if(host && user_id.host() != host)
return true;
ret = user_id;
return false;
});
return ret;
}
ircd::string_view
ircd::m::membership(const mutable_buffer &out,
const room &room,
const user::id &user_id)
{
const room::state state
{
room
};
const auto event_idx
{
state.get(std::nothrow, "m.room.member", user_id)
};
return room::members::membership(out, event_idx);
}
/// Receive the join_rule of the room into buffer of sufficient size.
/// The protocol does not specify a join_rule string longer than 7
/// characters but do be considerate of the future. This function
/// properly defaults the string as per the protocol spec.
ircd::string_view
ircd::m::join_rule(const mutable_buffer &out,
const room &room)
{
static const string_view default_join_rule
{
"invite"
};
string_view ret
{
default_join_rule
};
const event::keys::include keys
{
"content"
};
const m::event::fetch::opts fopts
{
keys, room.fopts? room.fopts->gopts : db::gopts{}
};
const room::state state
{
room, &fopts
};
state.get(std::nothrow, "m.room.join_rules", "", [&ret, &out]
(const m::event &event)
{
const auto &content
{
json::get<"content"_>(event)
};
const json::string &rule
{
content.get("join_rule", default_join_rule)
};
ret = string_view
{
data(out), copy(out, rule)
};
});
return ret;
}
ircd::string_view ircd::string_view
ircd::m::version(const mutable_buffer &buf, ircd::m::version(const mutable_buffer &buf,
const room &room) const room &room)
@ -1019,7 +1112,6 @@ ircd::m::version(const mutable_buffer &buf,
strlcpy{buf, "1"_sv} strlcpy{buf, "1"_sv}
}; };
if(event_idx)
m::get(std::nothrow, event_idx, "content", [&buf, &ret] m::get(std::nothrow, event_idx, "content", [&buf, &ret]
(const json::object &content) (const json::object &content)
{ {
@ -1047,7 +1139,6 @@ ircd::m::type(const mutable_buffer &buf,
room.get(std::nothrow, "m.room.create", "") room.get(std::nothrow, "m.room.create", "")
}; };
if(event_idx)
m::get(std::nothrow, event_idx, "content", [&buf, &ret] m::get(std::nothrow, event_idx, "content", [&buf, &ret]
(const json::object &content) (const json::object &content)
{ {
@ -1065,18 +1156,6 @@ ircd::m::type(const mutable_buffer &buf,
return ret; return ret;
} }
bool
ircd::m::creator(const id::room &room_id,
const id::user &user_id)
{
const auto creator_user_id
{
creator(room_id)
};
return creator_user_id == user_id;
}
ircd::m::id::user::buf ircd::m::id::user::buf
ircd::m::creator(const id::room &room_id) ircd::m::creator(const id::room &room_id)
{ {
@ -1084,10 +1163,7 @@ ircd::m::creator(const id::room &room_id)
// future compatibility if the content.creator field gets eliminated. // future compatibility if the content.creator field gets eliminated.
static const event::fetch::opts fopts static const event::fetch::opts fopts
{ {
event::keys::include event::keys::include {"sender"}
{
"sender",
}
}; };
const room::state state const room::state state
@ -1108,15 +1184,91 @@ ircd::m::creator(const id::room &room_id)
return ret; return ret;
} }
//
// boolean suite
//
/// The only joined members are from our origin (local only). This indicates
/// we won't have any other federation servers to query for room data, nor do
/// we need to broadcast events to the federation. This is not an authority
/// about a room's type or ability to federate. Returned value changes to false
/// when another origin joins.
bool bool
ircd::m::federate(const id::room &room_id) ircd::m::local_only(const room &room)
{
const room::origins origins
{
room
};
return origins.empty() || origins.only(my_host());
}
bool
ircd::m::visible(const room &room,
const string_view &mxid,
const event *const &event)
{
if(event)
return m::visible(*event, mxid);
const m::event event_
{
json::members
{
{ "event_id", room.event_id },
{ "room_id", room.room_id },
}
};
return m::visible(event_, mxid);
}
/// Test of the join_rule of the room is the argument.
bool
ircd::m::join_rule(const room &room,
const string_view &rule)
{
char buf[32];
return join_rule(buf, room) == rule;
}
bool
ircd::m::membership(const room &room,
const user::id &user_id,
const string_view &membership)
{
const room::state state
{
room
};
const auto event_idx
{
state.get(std::nothrow, "m.room.member", user_id)
};
return room::members::membership(event_idx, membership);
}
bool
ircd::m::creator(const room::id &room_id,
const user::id &user_id)
{
const auto creator_user_id
{
creator(room_id)
};
return creator_user_id == user_id;
}
bool
ircd::m::federated(const id::room &room_id)
{ {
static const m::event::fetch::opts fopts static const m::event::fetch::opts fopts
{ {
event::keys::include event::keys::include { "content" },
{
"content",
}
}; };
const m::room::state state const m::room::state state
@ -1172,6 +1324,10 @@ ircd::m::exists(const room &room)
return exists(room.room_id); return exists(room.room_id);
} }
//
// util
//
bool bool
ircd::m::operator==(const room &a, const room &b) ircd::m::operator==(const room &a, const room &b)
{ {
@ -1236,155 +1392,6 @@ ircd::m::room::index(const room::id &room_id,
// room::room // room::room
// //
ircd::m::id::user::buf
ircd::m::room::any_user(const string_view &host,
const string_view &membership)
const
{
user::id::buf ret;
const members members{*this};
members.for_each(membership, [&host, &ret]
(const auto &user_id, const auto &event_idx)
{
if(host && user_id.host() != host)
return true;
ret = user_id;
return false;
});
return ret;
}
/// Test of the join_rule of the room is the argument.
bool
ircd::m::room::join_rule(const string_view &rule)
const
{
char buf[32];
return join_rule(mutable_buffer{buf}) == rule;
}
/// Receive the join_rule of the room into buffer of sufficient size.
/// The protocol does not specify a join_rule string longer than 7
/// characters but do be considerate of the future. This function
/// properly defaults the string as per the protocol spec.
ircd::string_view
ircd::m::room::join_rule(const mutable_buffer &out)
const
{
static const string_view default_join_rule
{
"invite"
};
string_view ret
{
default_join_rule
};
const event::keys::include keys
{
"content"
};
const m::event::fetch::opts fopts
{
keys, this->fopts? this->fopts->gopts : db::gopts{}
};
const room::state state
{
*this, &fopts
};
state.get(std::nothrow, "m.room.join_rules", "", [&ret, &out]
(const m::event &event)
{
const auto &content
{
json::get<"content"_>(event)
};
const string_view &rule
{
content.get("join_rule", default_join_rule)
};
ret = string_view
{
data(out), copy(out, unquote(rule))
};
});
return ret;
}
/// The only joined members are from our origin (local only). This indicates
/// we won't have any other federation servers to query for room data, nor do
/// we need to broadcast events to the federation. This is not an authority
/// about a room's type or ability to federate. Returned value changes to false
/// when another origin joins.
bool
ircd::m::room::lonly()
const
{
const origins origins(*this);
return origins.empty() || origins.only(my_host());
}
bool
ircd::m::room::visible(const string_view &mxid,
const event *const &event)
const
{
if(event)
return m::visible(*event, mxid);
const m::event event_
{
json::members
{
{ "event_id", event_id },
{ "room_id", room_id },
}
};
return m::visible(event_, mxid);
}
bool
ircd::m::room::membership(const m::id::user &user_id,
const string_view &membership)
const
{
char buf[64];
return this->membership(buf, user_id) == membership;
}
ircd::string_view
ircd::m::room::membership(const mutable_buffer &out,
const m::id::user &user_id)
const
{
string_view ret;
const room::state state{*this};
state.get(std::nothrow, "m.room.member", user_id, [&out, &ret]
(const event::idx &event_idx)
{
m::get(std::nothrow, event_idx, "content", [&out, &ret]
(const json::object &content)
{
ret =
{
data(out), copy(out, unquote(content.get("membership")))
};
});
});
return ret;
}
bool bool
ircd::m::room::has(const string_view &type) ircd::m::room::has(const string_view &type)
const const

View file

@ -132,7 +132,7 @@ get__events(client &client,
room_id, event_id room_id, event_id
}; };
if(!room.visible(request.user_id)) if(!visible(room, request.user_id))
throw m::ACCESS_DENIED throw m::ACCESS_DENIED
{ {
"You are not able to view the room at this event." "You are not able to view the room at this event."

View file

@ -74,7 +74,7 @@ get__context(client &client,
room_id, event_id room_id, event_id
}; };
if(!room.visible(request.user_id)) if(!visible(room, request.user_id))
throw m::ACCESS_DENIED throw m::ACCESS_DENIED
{ {
"You are not permitted to view the room at this event" "You are not permitted to view the room at this event"

View file

@ -33,7 +33,7 @@ get__event(client &client,
room_id, event_id room_id, event_id
}; };
if(!room.visible(request.user_id)) if(!visible(room, request.user_id))
throw m::ACCESS_DENIED throw m::ACCESS_DENIED
{ {
"You are not permitted to view the room at this event" "You are not permitted to view the room at this event"

View file

@ -42,7 +42,7 @@ post__forget(client &client,
char room_membuf[m::room::MEMBERSHIP_MAX_SIZE]; char room_membuf[m::room::MEMBERSHIP_MAX_SIZE];
const string_view &room_membership const string_view &room_membership
{ {
room.membership(room_membuf, request.user_id) membership(room_membuf, room, request.user_id)
}; };
char user_membuf[m::room::MEMBERSHIP_MAX_SIZE]; char user_membuf[m::room::MEMBERSHIP_MAX_SIZE];

View file

@ -103,7 +103,7 @@ get__initialsync_local(client &client,
char membership_buf[m::room::MEMBERSHIP_MAX_SIZE]; char membership_buf[m::room::MEMBERSHIP_MAX_SIZE];
json::stack::member json::stack::member
{ {
out, "membership", room.membership(membership_buf, request.user_id) out, "membership", membership(membership_buf, room, request.user_id)
}; };
json::stack::member json::stack::member

View file

@ -70,7 +70,7 @@ ircd::m::join(const room &room,
return ret; return ret;
} }
if(room.membership(user_id, "join")) if(membership(room, user_id, "join"))
{ {
const auto &event_idx const auto &event_idx
{ {

View file

@ -67,7 +67,7 @@ get__members(client &client,
string_view{room_id} string_view{room_id}
}; };
if(!room.visible(request.user_id)) if(!visible(room, request.user_id))
throw m::ACCESS_DENIED throw m::ACCESS_DENIED
{ {
"You do not have permission to view %s members.", "You do not have permission to view %s members.",
@ -137,7 +137,7 @@ get__joined_members(client &client,
string_view{room_id} string_view{room_id}
}; };
if(!room.visible(request.user_id)) if(!visible(room, request.user_id))
throw m::ACCESS_DENIED throw m::ACCESS_DENIED
{ {
"You do not have permission to view %s joined members.", "You do not have permission to view %s joined members.",

View file

@ -79,7 +79,7 @@ get__messages(client &client,
room_id, page.from room_id, page.from
}; };
if(!room.visible(request.user_id)) if(!visible(room, request.user_id))
throw m::ACCESS_DENIED throw m::ACCESS_DENIED
{ {
"You are not permitted to view the room at this event" "You are not permitted to view the room at this event"

View file

@ -101,7 +101,7 @@ get__state(client &client,
string_view{room_id} string_view{room_id}
}; };
if(!room.visible(request.user_id)) if(!visible(room, request.user_id))
throw m::ACCESS_DENIED throw m::ACCESS_DENIED
{ {
"You are not permitted to view %s", "You are not permitted to view %s",

View file

@ -46,7 +46,7 @@ post__unban(client &client,
power.level("ban") power.level("ban")
}; };
if(!room.membership(user_id, "ban")) if(!membership(room, user_id, "ban"))
throw m::error throw m::error
{ {
http::OK, "M_BAD_STATE", http::OK, "M_BAD_STATE",

View file

@ -57,7 +57,7 @@ ircd::m::sync::rooms_linear(data &data)
const string_view &membership const string_view &membership
{ {
data.room? data.room?
room.membership(membuf, data.user): m::membership(membuf, room, data.user):
string_view{} string_view{}
}; };

View file

@ -91,7 +91,7 @@ ircd::m::sync::room_account_data_linear_events(data &data,
char membuf[room::MEMBERSHIP_MAX_SIZE]; char membuf[room::MEMBERSHIP_MAX_SIZE];
const auto membership const auto membership
{ {
room.membership(membuf, data.user) m::membership(membuf, room, data.user)
}; };
if(!membership) if(!membership)
@ -153,7 +153,7 @@ ircd::m::sync::room_account_data_linear_tags(data &data,
char membuf[room::MEMBERSHIP_MAX_SIZE]; char membuf[room::MEMBERSHIP_MAX_SIZE];
const auto membership const auto membership
{ {
room.membership(membuf, data.user) m::membership(membuf, room, data.user)
}; };
if(!membership) if(!membership)

View file

@ -55,7 +55,7 @@ ircd::m::sync::room_ephemeral_m_receipt_m_read_linear(data &data)
json::get<"state_key"_>(*data.event) json::get<"state_key"_>(*data.event)
}; };
if(!room.membership(data.user, "join")) if(!membership(room, data.user, "join"))
return false; return false;
json::stack::object rooms json::stack::object rooms

View file

@ -41,7 +41,7 @@ ircd::m::sync::room_ephemeral_m_typing_linear(data &data)
}; };
// Check if our user is a member of the room targetted by the typing notif // Check if our user is a member of the room targetted by the typing notif
if(!target_room.membership(data.user, "join")) if(!membership(target_room, data.user, "join"))
return false; return false;
const m::user::id &sender const m::user::id &sender

View file

@ -7729,7 +7729,7 @@ console_cmd__room__top(opt &out, const string_view &line)
char version_buf[32]; char version_buf[32];
out << "index: " << m::room::index(room_id) << std::endl; out << "index: " << m::room::index(room_id) << std::endl;
out << "version: " << m::version(version_buf, room_id) << std::endl; out << "version: " << m::version(version_buf, room_id) << std::endl;
out << "federate: " << std::boolalpha << m::federate(room_id) << std::endl; out << "federated: " << std::boolalpha << m::federated(room_id) << std::endl;
out << "top index: " << std::get<m::event::idx>(top) << std::endl; out << "top index: " << std::get<m::event::idx>(top) << std::endl;
out << "top depth: " << std::get<int64_t>(top) << std::endl; out << "top depth: " << std::get<int64_t>(top) << std::endl;
out << "top event: " << std::get<m::event::id::buf>(top) << std::endl; out << "top event: " << std::get<m::event::id::buf>(top) << std::endl;
@ -8123,7 +8123,7 @@ console_cmd__room__visible(opt &out, const string_view &line)
const bool visible const bool visible
{ {
room.visible(mxid) m::visible(room, mxid)
}; };
out << room_id << " is " out << room_id << " is "
@ -11949,12 +11949,12 @@ console_cmd__fed__head(opt &out, const string_view &line)
user_id = param["user_id"]; user_id = param["user_id"];
if(!user_id) if(!user_id)
user_id = room.any_user(my_host(), "join"); user_id = any_user(room, my_host(), "join");
// Make another attempt to find an invited user because that carries some // Make another attempt to find an invited user because that carries some
// value (this query is not as fast as querying join memberships). // value (this query is not as fast as querying join memberships).
if(!user_id) if(!user_id)
user_id = room.any_user(my_host(), "invite"); user_id = any_user(room, my_host(), "invite");
thread_local char buf[16_KiB]; thread_local char buf[16_KiB];
m::v1::make_join::opts opts; m::v1::make_join::opts opts;

View file

@ -92,7 +92,7 @@ get__backfill_ids(client &client,
room_id, event_id room_id, event_id
}; };
if(!room.visible(request.node_id)) if(!visible(room, request.node_id))
throw m::ACCESS_DENIED throw m::ACCESS_DENIED
{ {
"You are not permitted to view the room at this event" "You are not permitted to view the room at this event"

View file

@ -72,7 +72,7 @@ get__event_auth(client &client,
bool visible bool visible
{ {
room.visible(request.node_id) m::visible(room, request.node_id)
}; };
// make an exception to the visibility for invitee cases. // make an exception to the visibility for invitee cases.

View file

@ -85,7 +85,7 @@ get__make_join(client &client,
"You are not permitted by the room's server access control list." "You are not permitted by the room's server access control list."
}; };
if(!room.visible(user_id)) if(!visible(room, user_id))
throw m::ACCESS_DENIED throw m::ACCESS_DENIED
{ {
"You are not permitted to view the room at this event." "You are not permitted to view the room at this event."

View file

@ -81,7 +81,7 @@ get__make_leave(client &client,
char membuf[m::room::MEMBERSHIP_MAX_SIZE]; char membuf[m::room::MEMBERSHIP_MAX_SIZE];
const string_view membership const string_view membership
{ {
room.membership(membuf, user_id) m::membership(membuf, room, user_id)
}; };
if(membership != "join" && membership != "invite") if(membership != "join" && membership != "invite")

View file

@ -63,7 +63,7 @@ get__state(client &client,
room_id, event_id room_id, event_id
}; };
if(!room.visible(request.node_id)) if(!visible(room, request.node_id))
throw m::ACCESS_DENIED throw m::ACCESS_DENIED
{ {
"You are not permitted to view the room at this event" "You are not permitted to view the room at this event"

View file

@ -56,7 +56,7 @@ get__state_ids(client &client,
room_id, event_id room_id, event_id
}; };
if(!room.visible(request.node_id)) if(!visible(room, request.node_id))
throw m::ACCESS_DENIED throw m::ACCESS_DENIED
{ {
"You are not permitted to view the room at this event" "You are not permitted to view the room at this event"

View file

@ -41,7 +41,7 @@ try
if(!exists(my_room)) if(!exists(my_room))
create(my_room, me.user_id, "internal"); create(my_room, me.user_id, "internal");
if(!my_room.membership(me.user_id, "join")) if(!membership(my_room, me, "join"))
join(my_room, me.user_id); join(my_room, me.user_id);
if(!my_room.has("m.room.name", "")) if(!my_room.has("m.room.name", ""))

View file

@ -499,7 +499,7 @@ try
return; return;
// Only broadcast if the user is joined to the room. // Only broadcast if the user is joined to the room.
if(!m::room(room_id).membership(user, "join")) if(!membership(m::room(room_id), user, "join"))
return; return;
const m::user::room user_room const m::user::room user_room

View file

@ -25,7 +25,7 @@ _visible_to_user(const m::event &event,
char membership_buf[m::room::MEMBERSHIP_MAX_SIZE]; char membership_buf[m::room::MEMBERSHIP_MAX_SIZE];
string_view membership string_view membership
{ {
room.membership(membership_buf, user_id) m::membership(membership_buf, room, user_id)
}; };
if(membership == "join") if(membership == "join")
@ -46,7 +46,7 @@ _visible_to_user(const m::event &event,
if(room.event_id) if(room.event_id)
{ {
const m::room present{room.room_id}; const m::room present{room.room_id};
membership = present.membership(membership_buf, user_id); membership = m::membership(membership_buf, present, user_id);
return membership == "join" || membership == "invite"; return membership == "join" || membership == "invite";
} }

View file

@ -71,11 +71,11 @@ ircd::m::rooms::for_each(const opts &opts,
return; return;
if(opts.remote_joined_only) if(opts.remote_joined_only)
if(room(room_id).lonly()) if(local_only(room(room_id)))
return; return;
if(opts.local_only) if(opts.local_only)
if(!room(room_id).lonly()) if(!local_only(room(room_id)))
return; return;
if(opts.server && !opts.summary) if(opts.server && !opts.summary)
@ -91,7 +91,7 @@ ircd::m::rooms::for_each(const opts &opts,
return; return;
if(opts.join_rule) if(opts.join_rule)
if(!room(room_id).join_rule(opts.join_rule)) if(!join_rule(room(room_id), opts.join_rule))
return; return;
ret = closure(room_id); ret = closure(room_id);

View file

@ -75,7 +75,7 @@ commit(const m::typing &edu)
{ {
// Check if the user is actually in the room. // Check if the user is actually in the room.
const m::room room{at<"room_id"_>(edu)}; const m::room room{at<"room_id"_>(edu)};
if(!room.membership(at<"user_id"_>(edu), "join")) if(!membership(room, at<"user_id"_>(edu), "join"))
throw m::FORBIDDEN throw m::FORBIDDEN
{ {
"Cannot type in a room %s to which you are not joined", "Cannot type in a room %s to which you are not joined",
@ -217,7 +217,7 @@ _handle_edu_m_typing(const m::event &event,
// branch for remote servers only because our committer above did this // branch for remote servers only because our committer above did this
// already for our client. // already for our client.
const m::room room{room_id}; const m::room room{room_id};
if(!room.membership(user_id, "join")) if(!membership(room, user_id, "join"))
{ {
log::dwarning log::dwarning
{ {