use js_int::{UInt, uint};
use ruma_common::{
EventId, MilliSecondsSinceUnixEpoch, OwnedEventId, OwnedRoomId, OwnedUserId, RoomVersionId,
owned_event_id, owned_user_id,
room::JoinRule,
room_version_rules::{AuthorizationRules, RoomVersionRules},
serde::JsonObject,
};
use ruma_events::{StateEventType, TimelineEventType};
use serde_json::{json, to_value as to_json_value};
use super::{Pdu, default_room_id};
use crate::{
StateMap, auth_types_for_event,
events::RoomCreateEvent,
utils::{event_id_map::EventIdMap, event_id_set::EventIdSet},
};
pub struct RoomTimelineFactory {
room_id: OwnedRoomId,
rules: RoomVersionRules,
server_ts: UInt,
pdus: EventIdMap<OwnedEventId, Pdu>,
timeline: Vec<OwnedEventId>,
state: StateMap<OwnedEventId>,
}
impl RoomTimelineFactory {
pub fn with_public_chat_preset(room_version: RoomVersionId) -> Self {
let mut factory = RoomCreatePduBuilder::new(room_version).build_factory();
let alice_id = UserFactory::Alice.user_id();
factory.add_room_member(
PublicChatInitialPdu::RoomMemberAliceJoin.event_id(),
alice_id.clone(),
RoomMemberPduContent::Join,
);
factory.add_room_power_levels(
PublicChatInitialPdu::RoomPowerLevels.event_id(),
alice_id.clone(),
RoomPowerLevelsPduContent::Default,
);
factory.add_room_join_rules(
PublicChatInitialPdu::RoomJoinRules.event_id(),
alice_id,
JoinRule::Public,
);
factory.add_room_member(
PublicChatInitialPdu::RoomMemberBobJoin.event_id(),
UserFactory::Bob.user_id(),
RoomMemberPduContent::Join,
);
factory
}
pub fn pdus(&self) -> &EventIdMap<OwnedEventId, Pdu> {
&self.pdus
}
pub fn get(&self, event_id: &EventId) -> Option<&Pdu> {
self.pdus.get(event_id)
}
pub fn get_fn<'a>(&'a self) -> impl Fn(&EventId) -> Option<&'a Pdu> + Copy {
|event_id: &EventId| self.get(event_id)
}
pub fn get_mut(&mut self, event_id: &EventId) -> Option<&mut Pdu> {
self.pdus.get_mut(event_id)
}
pub fn room_create_pdu(&self) -> RoomCreateEvent<&Pdu> {
RoomCreateEvent::new(
self.pdus
.get(&self.timeline[0])
.expect("A RoomTimelineFactory should have an `m.room.create` event"),
)
}
pub fn remove(&mut self, event_id: &EventId) {
self.pdus.remove(event_id);
}
pub fn state(&self) -> &StateMap<OwnedEventId> {
&self.state
}
pub fn state_event_id(
&self,
event_type: &StateEventType,
state_key: &str,
) -> Option<&OwnedEventId> {
self.state.get(&(event_type.clone(), state_key.to_owned()))
}
pub fn state_event(&self, event_type: &StateEventType, state_key: &str) -> Option<&Pdu> {
let event_id = self.state_event_id(event_type, state_key)?;
self.pdus.get(event_id)
}
pub fn state_event_fn<'a>(
&'a self,
) -> impl Fn(&StateEventType, &str) -> Option<&'a Pdu> + Copy {
|event_type: &StateEventType, state_key: &str| self.state_event(event_type, state_key)
}
pub fn full_auth_chain(&self, state_map: &StateMap<OwnedEventId>) -> EventIdSet<OwnedEventId> {
let mut auth_chain = EventIdSet::new();
let mut stack = state_map.values().cloned().collect::<Vec<_>>();
while let Some(event_id) = stack.pop() {
let pdu = self.pdus.get(&event_id).expect("PDU should be in map");
stack.extend(
pdu.auth_events
.iter()
.filter(|auth_event_id| !auth_chain.contains(auth_event_id))
.cloned(),
);
auth_chain.insert(event_id);
}
auth_chain
}
fn next_server_timestamp(&mut self) -> MilliSecondsSinceUnixEpoch {
self.server_ts += uint!(1);
MilliSecondsSinceUnixEpoch(self.server_ts)
}
pub fn prepare_to_add_pdu(&mut self, pdu: &mut Pdu) {
pdu.room_id = Some(self.room_id.clone());
pdu.origin_server_ts = self.next_server_timestamp();
pdu.prev_events.extend(self.timeline.last().cloned());
let auth_types = auth_types_for_event(
&pdu.event_type,
&pdu.sender,
pdu.state_key.as_deref(),
&pdu.content,
&self.rules.authorization,
)
.unwrap();
pdu.auth_events.extend(auth_types.iter().flat_map(|(event_type, state_key)| {
self.state_event_id(event_type, state_key).cloned()
}));
}
pub fn add_pdu(&mut self, pdu: Pdu) -> &mut Pdu {
let event_id = pdu.event_id.clone();
if let Some(state_key) = pdu.state_key.clone() {
self.state.insert((pdu.event_type.to_string().into(), state_key), event_id.clone());
}
self.timeline.push(event_id.clone());
self.pdus.entry(event_id).insert_entry(pdu)
}
pub fn create_room_member(
&mut self,
event_id: OwnedEventId,
target: OwnedUserId,
content: RoomMemberPduContent,
) -> Pdu {
let (sender, content) = content.into_parts(&target);
let mut pdu = Pdu::with_minimal_state_fields(
event_id,
sender,
TimelineEventType::RoomMember,
target.into(),
content,
);
self.prepare_to_add_pdu(&mut pdu);
pdu
}
pub fn add_room_member(
&mut self,
event_id: OwnedEventId,
target: OwnedUserId,
content: RoomMemberPduContent,
) -> &mut Pdu {
let pdu = self.create_room_member(event_id, target, content);
self.add_pdu(pdu)
}
pub fn create_room_power_levels(
&mut self,
event_id: OwnedEventId,
sender: OwnedUserId,
content: RoomPowerLevelsPduContent,
) -> Pdu {
let mut pdu = Pdu::with_minimal_state_fields(
event_id,
sender,
TimelineEventType::RoomPowerLevels,
String::new(),
content.into_json(&self.rules.authorization),
);
self.prepare_to_add_pdu(&mut pdu);
pdu
}
pub fn add_room_power_levels(
&mut self,
event_id: OwnedEventId,
sender: OwnedUserId,
content: RoomPowerLevelsPduContent,
) -> &mut Pdu {
let pdu = self.create_room_power_levels(event_id, sender, content);
self.add_pdu(pdu)
}
pub fn create_room_join_rules(
&mut self,
event_id: OwnedEventId,
sender: OwnedUserId,
join_rule: JoinRule,
) -> Pdu {
let mut pdu = Pdu::with_minimal_state_fields(
event_id,
sender,
TimelineEventType::RoomJoinRules,
String::new(),
join_rule,
);
self.prepare_to_add_pdu(&mut pdu);
pdu
}
pub fn add_room_join_rules(
&mut self,
event_id: OwnedEventId,
sender: OwnedUserId,
join_rule: JoinRule,
) -> &mut Pdu {
let pdu = self.create_room_join_rules(event_id, sender, join_rule);
self.add_pdu(pdu)
}
pub fn create_room_redaction(
&mut self,
event_id: OwnedEventId,
sender: OwnedUserId,
redacts: OwnedEventId,
) -> Pdu {
let mut content = JsonObject::new();
if self.rules.redaction.content_field_redacts {
content.insert("redacts".to_owned(), redacts.to_string().into());
}
let mut pdu =
Pdu::with_minimal_fields(event_id, sender, TimelineEventType::RoomRedaction, content);
pdu.redacts = Some(redacts);
self.prepare_to_add_pdu(&mut pdu);
pdu
}
pub fn add_room_redaction(
&mut self,
event_id: OwnedEventId,
sender: OwnedUserId,
redacts: OwnedEventId,
) -> &mut Pdu {
let pdu = self.create_room_redaction(event_id, sender, redacts);
self.add_pdu(pdu)
}
pub fn create_text_message(
&mut self,
event_id: OwnedEventId,
sender: OwnedUserId,
text: impl Into<String>,
) -> Pdu {
let mut pdu = Pdu::with_minimal_fields(
event_id,
sender,
TimelineEventType::RoomMessage,
json!({
"msgtype": "m.text",
"body": text.into(),
}),
);
self.prepare_to_add_pdu(&mut pdu);
pdu
}
pub fn create_room_third_party_invite(&mut self) -> Pdu {
let content = json!({
"display_name": "z...@o...",
"key_validity_url": "https://identity.local/_matrix/identity/v2/pubkey/isvalid",
"public_key": "Gb9ECWmEzf6FQbrBZ9w7lshQhqowtrbLDFw4rXAxZuE",
"public_keys": [
{
"key_validity_url": "https://identity.local/_matrix/identity/v2/pubkey/isvalid",
"public_key": "Gb9ECWmEzf6FQbrBZ9w7lshQhqowtrbLDFw4rXAxZuE"
},
{
"key_validity_url": "https://identity.local/_matrix/identity/v2/pubkey/ephemeral/isvalid",
"public_key": "VmTAw9B8j/gpkrXl1R7N2NNAyfWuwJnRf5YWHnO3rW4"
}
]
});
let mut pdu = Pdu::with_minimal_state_fields(
owned_event_id!("$room-third-party-invite-zara"),
UserFactory::Bob.user_id(),
TimelineEventType::RoomThirdPartyInvite,
"uniquetoken".to_owned(),
content,
);
self.prepare_to_add_pdu(&mut pdu);
pdu
}
pub fn add_room_third_party_invite(&mut self) -> &mut Pdu {
let pdu = self.create_room_third_party_invite();
self.add_pdu(pdu)
}
pub fn create_room_member_third_party_invite(&mut self) -> Pdu {
let zara_id = UserFactory::Zara.user_id();
let bob_id = UserFactory::Bob.user_id();
let content = json!({
"membership": "invite",
"third_party_invite": {
"display_name": "z...@o...",
"signed": {
"mxid": zara_id,
"sender": bob_id,
"token": "uniquetoken",
"signatures": {
"identity.local": {
"unknown:0": "SomeSignature",
"ed25519:0": "ClearlyWrongSignature",
"ed25519:1": "GTXhO9a3ysW0GWd79vTvzAPi2F2YjZNJDHkwFCyCfYaF0g6tEBjajamAkIgwhXNAp/85PVpzjY6j9oDci8DqDA",
}
},
}
}
});
let mut pdu = Pdu::with_minimal_state_fields(
owned_event_id!("$room-member-zara-invite"),
bob_id,
TimelineEventType::RoomMember,
zara_id.into(),
content,
);
self.prepare_to_add_pdu(&mut pdu);
pdu
}
}
#[derive(Debug, Clone, Copy)]
#[allow(clippy::enum_variant_names)]
pub enum PublicChatInitialPdu {
RoomCreate,
RoomMemberAliceJoin,
RoomPowerLevels,
RoomJoinRules,
RoomMemberBobJoin,
}
impl PublicChatInitialPdu {
pub fn type_and_state_key(self) -> (StateEventType, String) {
match self {
Self::RoomCreate => (StateEventType::RoomCreate, String::new()),
Self::RoomMemberAliceJoin => {
(StateEventType::RoomMember, UserFactory::Alice.user_id().into())
}
Self::RoomPowerLevels => (StateEventType::RoomPowerLevels, String::new()),
Self::RoomJoinRules => (StateEventType::RoomJoinRules, String::new()),
Self::RoomMemberBobJoin => {
(StateEventType::RoomMember, UserFactory::Bob.user_id().into())
}
}
}
pub fn event_id(self) -> OwnedEventId {
match self {
Self::RoomCreate => owned_event_id!("$room-create"),
Self::RoomMemberAliceJoin => owned_event_id!("$room-member-alice-join"),
Self::RoomPowerLevels => owned_event_id!("$room-power-levels"),
Self::RoomJoinRules => owned_event_id!("$room-join-rules"),
Self::RoomMemberBobJoin => owned_event_id!("$room-member-bob-join"),
}
}
}
#[derive(Debug, Clone, Copy)]
pub enum UserFactory {
Alice,
Bob,
Charlie,
Zara,
}
impl UserFactory {
pub fn user_id(self) -> OwnedUserId {
match self {
Self::Alice => owned_user_id!("@alice:matrix.local"),
Self::Bob => owned_user_id!("@bob:matrix.local"),
Self::Charlie => owned_user_id!("@charlie:matrix.local"),
Self::Zara => owned_user_id!("@zara:other.local"),
}
}
}
pub struct RoomCreatePduBuilder {
room_version: RoomVersionId,
rules: RoomVersionRules,
additional_creators: Vec<OwnedUserId>,
}
impl RoomCreatePduBuilder {
pub fn new(room_version: RoomVersionId) -> Self {
let rules = room_version.rules().expect("room version should be supported");
if !rules.authorization.strict_canonical_json {
panic!("Only room versions that enforce canonical JSON are properly supported");
}
Self { room_version, rules, additional_creators: Vec::new() }
}
pub fn additional_creators(mut self, additional_creators: Vec<OwnedUserId>) -> Self {
self.additional_creators = additional_creators;
self
}
fn build_inner(&self) -> Pdu {
let sender = UserFactory::Alice.user_id();
let mut content = JsonObject::new();
content.insert("room_version".to_owned(), self.room_version.to_string().into());
if !self.rules.authorization.use_room_create_sender {
content.insert("creator".to_owned(), sender.to_string().into());
}
if !self.additional_creators.is_empty() {
content.insert(
"additional_creators".to_owned(),
to_json_value(&self.additional_creators).unwrap(),
);
}
let mut pdu = Pdu::with_minimal_state_fields(
PublicChatInitialPdu::RoomCreate.event_id(),
sender,
TimelineEventType::RoomCreate,
String::new(),
content,
);
pdu.room_id = self
.rules
.event_format
.require_room_create_room_id
.then(|| default_room_id(&self.rules.room_id_format));
pdu
}
pub fn build(self) -> Pdu {
self.build_inner()
}
pub fn build_factory(self) -> RoomTimelineFactory {
let room_create = self.build_inner();
let room_create_event_id = room_create.event_id.clone();
let room_id = room_create
.room_id
.clone()
.unwrap_or_else(|| default_room_id(&self.rules.room_id_format));
RoomTimelineFactory {
room_id,
rules: self.rules,
server_ts: UInt::MIN,
pdus: [(room_create_event_id.clone(), room_create)].into(),
timeline: vec![room_create_event_id.clone()],
state: [((StateEventType::RoomCreate, String::new()), room_create_event_id)].into(),
}
}
}
pub enum RoomMemberPduContent {
Join,
JoinAuthorized {
via_users_server: OwnedUserId,
},
DisplayName {
displayname: String,
},
Ban {
sender: OwnedUserId,
},
Invite {
sender: OwnedUserId,
},
Knock,
Leave,
Kick {
sender: OwnedUserId,
},
}
impl RoomMemberPduContent {
pub fn into_parts(self, target: &OwnedUserId) -> (OwnedUserId, JsonObject) {
let mut content = JsonObject::new();
let (sender, membership) = match self {
Self::Join => (target.clone(), "join"),
Self::JoinAuthorized { via_users_server } => {
content.insert(
"join_authorised_via_users_server".to_owned(),
String::from(via_users_server).into(),
);
(target.clone(), "join")
}
Self::DisplayName { displayname } => {
content.insert("displayname".to_owned(), displayname.into());
(target.clone(), "join")
}
Self::Ban { sender } => (sender, "ban"),
Self::Invite { sender } => (sender, "invite"),
Self::Knock => (target.clone(), "knock"),
Self::Leave => (target.clone(), "leave"),
Self::Kick { sender } => (sender, "leave"),
};
content.insert("membership".to_owned(), membership.into());
(sender, content)
}
}
pub enum RoomPowerLevelsPduContent {
Default,
Invite {
value: i32,
},
Events {
event_types: Vec<TimelineEventType>,
value: i32,
},
User {
user_id: OwnedUserId,
value: i32,
},
}
impl RoomPowerLevelsPduContent {
fn into_json(self, authorization_rules: &AuthorizationRules) -> JsonObject {
let mut content = JsonObject::new();
if !authorization_rules.explicitly_privilege_room_creators {
let users = json!({
UserFactory::Alice.user_id(): 100,
});
content.insert("users".to_owned(), users);
}
match self {
Self::Default => {}
Self::Invite { value } => {
content.insert("invite".to_owned(), value.into());
}
Self::Events { event_types, value } => {
let events = JsonObject::from_iter(
event_types
.into_iter()
.map(|event_type| (event_type.to_string(), value.into())),
);
content.insert("events".to_owned(), events.into());
}
Self::User { user_id, value } => {
content
.entry("users".to_owned())
.or_insert_with(|| JsonObject::new().into())
.as_object_mut()
.unwrap()
.insert(user_id.into(), value.into());
}
}
content
}
}
#[cfg(test)]
mod tests {
use assert_matches2::assert_matches;
use js_int::int;
use ruma_common::{
RoomVersionId, owned_event_id, room::JoinRuleKind, room_version_rules::AuthorizationRules,
user_id,
};
use ruma_events::{StateEventType, room::member::MembershipState};
use super::RoomTimelineFactory;
use crate::events::{
RoomCreateEvent, RoomJoinRulesEvent, RoomMemberEvent, RoomPowerLevelsEvent,
};
#[test]
fn public_chat_preset_v10() {
let factory = RoomTimelineFactory::with_public_chat_preset(RoomVersionId::V10);
assert_eq!(factory.pdus.len(), 5);
assert_eq!(factory.timeline.len(), 5);
assert_eq!(factory.state.values().count(), 5);
assert_eq!(factory.room_id, "!room:matrix.local");
let room_create_event_id = owned_event_id!("$room-create");
assert_eq!(factory.timeline[0], room_create_event_id);
assert_eq!(
*factory.state_event_id(&StateEventType::RoomCreate, "").unwrap(),
room_create_event_id
);
let pdu = RoomCreateEvent::new(factory.get(&room_create_event_id).unwrap());
assert_eq!(pdu.event_id, room_create_event_id);
assert_eq!(pdu.room_id.as_ref().unwrap(), "!room:matrix.local");
assert_eq!(pdu.room_version(), Ok(RoomVersionId::V10));
assert_eq!(
pdu.creator(&AuthorizationRules::V10).as_deref(),
Ok(user_id!("@alice:matrix.local"))
);
assert!(pdu.prev_events.is_empty());
assert!(pdu.auth_events.is_empty());
let room_member_alice_join_event_id = owned_event_id!("$room-member-alice-join");
assert_eq!(factory.timeline[1], room_member_alice_join_event_id);
assert_eq!(
*factory.state_event_id(&StateEventType::RoomMember, "@alice:matrix.local").unwrap(),
room_member_alice_join_event_id
);
let pdu = RoomMemberEvent::new(factory.get(&room_member_alice_join_event_id).unwrap());
assert_eq!(pdu.event_id, room_member_alice_join_event_id);
assert_eq!(pdu.state_key.as_deref(), Some("@alice:matrix.local"));
assert_eq!(pdu.membership(), Ok(MembershipState::Join));
assert_eq!(pdu.prev_events, [room_create_event_id.clone()].into());
assert_eq!(pdu.auth_events, [room_create_event_id.clone()].into());
let room_power_levels_event_id = owned_event_id!("$room-power-levels");
assert_eq!(factory.timeline[2], room_power_levels_event_id);
assert_eq!(
*factory.state_event_id(&StateEventType::RoomPowerLevels, "").unwrap(),
room_power_levels_event_id
);
let pdu = RoomPowerLevelsEvent::new(factory.get(&room_power_levels_event_id).unwrap());
assert_eq!(pdu.event_id, room_power_levels_event_id);
let users = pdu.users(&AuthorizationRules::V10).unwrap().unwrap();
assert_eq!(users.get(user_id!("@alice:matrix.local")), Some(&int!(100)));
assert_eq!(pdu.prev_events, [room_member_alice_join_event_id.clone()].into());
assert_eq!(
pdu.auth_events,
[room_member_alice_join_event_id.clone(), room_create_event_id.clone()].into()
);
let room_join_rules_event_id = owned_event_id!("$room-join-rules");
assert_eq!(factory.timeline[3], room_join_rules_event_id);
assert_eq!(
*factory.state_event_id(&StateEventType::RoomJoinRules, "").unwrap(),
room_join_rules_event_id
);
let pdu = RoomJoinRulesEvent::new(factory.get(&room_join_rules_event_id).unwrap());
assert_eq!(pdu.event_id, room_join_rules_event_id);
assert_eq!(pdu.join_rule(), Ok(JoinRuleKind::Public));
assert_eq!(pdu.prev_events, [room_power_levels_event_id.clone()].into());
assert_eq!(
pdu.auth_events,
[
room_power_levels_event_id.clone(),
room_member_alice_join_event_id.clone(),
room_create_event_id.clone()
]
.into()
);
let room_member_bob_join_event_id = owned_event_id!("$room-member-bob-join");
assert_eq!(factory.timeline[4], room_member_bob_join_event_id);
assert_eq!(
*factory.state_event_id(&StateEventType::RoomMember, "@bob:matrix.local").unwrap(),
room_member_bob_join_event_id
);
let pdu = RoomMemberEvent::new(factory.get(&room_member_bob_join_event_id).unwrap());
assert_eq!(pdu.event_id, room_member_bob_join_event_id);
assert_eq!(pdu.state_key.as_deref(), Some("@bob:matrix.local"));
assert_eq!(pdu.membership(), Ok(MembershipState::Join));
assert_eq!(pdu.prev_events, [room_join_rules_event_id.clone()].into());
assert_eq!(
pdu.auth_events,
[
room_power_levels_event_id.clone(),
room_create_event_id.clone(),
room_join_rules_event_id.clone()
]
.into()
);
}
#[test]
fn public_chat_preset_v11() {
let factory = RoomTimelineFactory::with_public_chat_preset(RoomVersionId::V11);
assert_eq!(factory.pdus.len(), 5);
assert_eq!(factory.timeline.len(), 5);
assert_eq!(factory.state.values().count(), 5);
assert_eq!(factory.room_id, "!room:matrix.local");
let room_create_event_id = owned_event_id!("$room-create");
assert_eq!(factory.timeline[0], room_create_event_id);
assert_eq!(
*factory.state_event_id(&StateEventType::RoomCreate, "").unwrap(),
room_create_event_id
);
let pdu = RoomCreateEvent::new(factory.get(&room_create_event_id).unwrap());
assert_eq!(pdu.event_id, room_create_event_id);
assert_eq!(pdu.room_id.as_ref().unwrap(), "!room:matrix.local");
assert_eq!(pdu.room_version(), Ok(RoomVersionId::V11));
assert_matches!(pdu.creator(&AuthorizationRules::V10), Err(_));
assert!(pdu.prev_events.is_empty());
assert!(pdu.auth_events.is_empty());
let room_member_alice_join_event_id = owned_event_id!("$room-member-alice-join");
assert_eq!(factory.timeline[1], room_member_alice_join_event_id);
assert_eq!(
*factory.state_event_id(&StateEventType::RoomMember, "@alice:matrix.local").unwrap(),
room_member_alice_join_event_id
);
let pdu = RoomMemberEvent::new(factory.get(&room_member_alice_join_event_id).unwrap());
assert_eq!(pdu.event_id, room_member_alice_join_event_id);
assert_eq!(pdu.state_key.as_deref(), Some("@alice:matrix.local"));
assert_eq!(pdu.membership(), Ok(MembershipState::Join));
assert_eq!(pdu.prev_events, [room_create_event_id.clone()].into());
assert_eq!(pdu.auth_events, [room_create_event_id.clone()].into());
let room_power_levels_event_id = owned_event_id!("$room-power-levels");
assert_eq!(factory.timeline[2], room_power_levels_event_id);
assert_eq!(
*factory.state_event_id(&StateEventType::RoomPowerLevels, "").unwrap(),
room_power_levels_event_id
);
let pdu = RoomPowerLevelsEvent::new(factory.get(&room_power_levels_event_id).unwrap());
assert_eq!(pdu.event_id, room_power_levels_event_id);
let users = pdu.users(&AuthorizationRules::V11).unwrap().unwrap();
assert_eq!(users.get(user_id!("@alice:matrix.local")), Some(&int!(100)));
assert_eq!(pdu.prev_events, [room_member_alice_join_event_id.clone()].into());
assert_eq!(
pdu.auth_events,
[room_member_alice_join_event_id.clone(), room_create_event_id.clone()].into()
);
let room_join_rules_event_id = owned_event_id!("$room-join-rules");
assert_eq!(factory.timeline[3], room_join_rules_event_id);
assert_eq!(
*factory.state_event_id(&StateEventType::RoomJoinRules, "").unwrap(),
room_join_rules_event_id
);
let pdu = RoomJoinRulesEvent::new(factory.get(&room_join_rules_event_id).unwrap());
assert_eq!(pdu.event_id, room_join_rules_event_id);
assert_eq!(pdu.join_rule(), Ok(JoinRuleKind::Public));
assert_eq!(pdu.prev_events, [room_power_levels_event_id.clone()].into());
assert_eq!(
pdu.auth_events,
[
room_power_levels_event_id.clone(),
room_member_alice_join_event_id.clone(),
room_create_event_id.clone()
]
.into()
);
let room_member_bob_join_event_id = owned_event_id!("$room-member-bob-join");
assert_eq!(factory.timeline[4], room_member_bob_join_event_id);
assert_eq!(
*factory.state_event_id(&StateEventType::RoomMember, "@bob:matrix.local").unwrap(),
room_member_bob_join_event_id
);
let pdu = RoomMemberEvent::new(factory.get(&room_member_bob_join_event_id).unwrap());
assert_eq!(pdu.event_id, room_member_bob_join_event_id);
assert_eq!(pdu.state_key.as_deref(), Some("@bob:matrix.local"));
assert_eq!(pdu.membership(), Ok(MembershipState::Join));
assert_eq!(pdu.prev_events, [room_join_rules_event_id.clone()].into());
assert_eq!(
pdu.auth_events,
[
room_power_levels_event_id.clone(),
room_create_event_id.clone(),
room_join_rules_event_id.clone()
]
.into()
);
}
#[test]
fn public_chat_preset_v12() {
let factory = RoomTimelineFactory::with_public_chat_preset(RoomVersionId::V12);
assert_eq!(factory.pdus.len(), 5);
assert_eq!(factory.timeline.len(), 5);
assert_eq!(factory.state.values().count(), 5);
assert_eq!(factory.room_id, "!room-create");
let room_create_event_id = owned_event_id!("$room-create");
assert_eq!(factory.timeline[0], room_create_event_id);
assert_eq!(
*factory.state_event_id(&StateEventType::RoomCreate, "").unwrap(),
room_create_event_id
);
let pdu = RoomCreateEvent::new(factory.get(&room_create_event_id).unwrap());
assert_eq!(pdu.event_id, room_create_event_id);
assert_eq!(pdu.room_id, None);
assert_eq!(pdu.room_version(), Ok(RoomVersionId::V12));
assert_matches!(pdu.creator(&AuthorizationRules::V10), Err(_));
assert!(pdu.prev_events.is_empty());
assert!(pdu.auth_events.is_empty());
let room_member_alice_join_event_id = owned_event_id!("$room-member-alice-join");
assert_eq!(factory.timeline[1], room_member_alice_join_event_id);
assert_eq!(
*factory.state_event_id(&StateEventType::RoomMember, "@alice:matrix.local").unwrap(),
room_member_alice_join_event_id
);
let pdu = RoomMemberEvent::new(factory.get(&room_member_alice_join_event_id).unwrap());
assert_eq!(pdu.event_id, room_member_alice_join_event_id);
assert_eq!(pdu.state_key.as_deref(), Some("@alice:matrix.local"));
assert_eq!(pdu.membership(), Ok(MembershipState::Join));
assert_eq!(pdu.prev_events, [room_create_event_id.clone()].into());
assert!(pdu.auth_events.is_empty());
let room_power_levels_event_id = owned_event_id!("$room-power-levels");
assert_eq!(factory.timeline[2], room_power_levels_event_id);
assert_eq!(
*factory.state_event_id(&StateEventType::RoomPowerLevels, "").unwrap(),
room_power_levels_event_id
);
let pdu = RoomPowerLevelsEvent::new(factory.get(&room_power_levels_event_id).unwrap());
assert_eq!(pdu.event_id, room_power_levels_event_id);
assert_matches!(pdu.users(&AuthorizationRules::V12), Ok(None));
assert_eq!(pdu.prev_events, [room_member_alice_join_event_id.clone()].into());
assert_eq!(pdu.auth_events, [room_member_alice_join_event_id.clone(),].into());
let room_join_rules_event_id = owned_event_id!("$room-join-rules");
assert_eq!(factory.timeline[3], room_join_rules_event_id);
assert_eq!(
*factory.state_event_id(&StateEventType::RoomJoinRules, "").unwrap(),
room_join_rules_event_id
);
let pdu = RoomJoinRulesEvent::new(factory.get(&room_join_rules_event_id).unwrap());
assert_eq!(pdu.event_id, room_join_rules_event_id);
assert_eq!(pdu.join_rule(), Ok(JoinRuleKind::Public));
assert_eq!(pdu.prev_events, [room_power_levels_event_id.clone()].into());
assert_eq!(
pdu.auth_events,
[room_power_levels_event_id.clone(), room_member_alice_join_event_id.clone(),].into()
);
let room_member_bob_join_event_id = owned_event_id!("$room-member-bob-join");
assert_eq!(factory.timeline[4], room_member_bob_join_event_id);
assert_eq!(
*factory.state_event_id(&StateEventType::RoomMember, "@bob:matrix.local").unwrap(),
room_member_bob_join_event_id
);
let pdu = RoomMemberEvent::new(factory.get(&room_member_bob_join_event_id).unwrap());
assert_eq!(pdu.event_id, room_member_bob_join_event_id);
assert_eq!(pdu.state_key.as_deref(), Some("@bob:matrix.local"));
assert_eq!(pdu.membership(), Ok(MembershipState::Join));
assert_eq!(pdu.prev_events, [room_join_rules_event_id.clone()].into());
assert_eq!(
pdu.auth_events,
[room_power_levels_event_id.clone(), room_join_rules_event_id.clone()].into()
);
}
}