Skip to content

Commit

Permalink
Handle user leave in direct message rooms
Browse files Browse the repository at this point in the history
  • Loading branch information
exul committed Jul 15, 2017
1 parent e829ab4 commit 7a1ed9e
Show file tree
Hide file tree
Showing 7 changed files with 170 additions and 62 deletions.
1 change: 1 addition & 0 deletions migrations/20161204173030_create_rooms/up.sql
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ CREATE TABLE rooms (
rocketchat_server_id VARCHAR,
is_admin_room BOOLEAN NOT NULL DEFAULT false,
is_bridged BOOLEAN NOT NULL DEFAULT false,
is_direct_message_room BOOLEAN NOT NULL DEFAULT false,
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
CONSTRAINT rooms_pk PRIMARY KEY (matrix_room_id)
Expand Down
6 changes: 5 additions & 1 deletion src/matrix-rocketchat/db/room.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,14 +27,16 @@ pub struct Room {
pub is_admin_room: bool,
/// A flag to indicate if the room is bridged to Rocket.Chat
pub is_bridged: bool,
/// A flag to indicate if the room is used to send direct messages between two users.
pub is_direct_message_room: bool,
/// created timestamp
pub created_at: String,
/// updated timestamp
pub updated_at: String,
}

/// A new `Room`, not yet saved.
#[derive(Insertable)]
#[derive(Debug, Insertable)]
#[table_name = "rooms"]
pub struct NewRoom {
/// The rooms unique id on the matrix server.
Expand All @@ -50,6 +52,8 @@ pub struct NewRoom {
pub is_admin_room: bool,
/// A flag to indicate if the room is bridged to Rocket.Chat
pub is_bridged: bool,
/// A flag to indicate if the room is used to send direct messages between two users.
pub is_direct_message_room: bool,
}

impl Room {
Expand Down
1 change: 1 addition & 0 deletions src/matrix-rocketchat/db/schema.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ table! {
rocketchat_room_id -> Nullable<Text>,
is_admin_room -> Bool,
is_bridged -> Bool,
is_direct_message_room -> Bool,
created_at -> Timestamp,
updated_at -> Timestamp,
}
Expand Down
17 changes: 12 additions & 5 deletions src/matrix-rocketchat/handlers/events/room_handler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ impl<'a> RoomHandler<'a> {
room_creator_id: UserId,
invited_user_id: UserId,
) -> Result<Room> {
let room = self.create_room(channel, rocketchat_server.id.clone(), room_creator_id, invited_user_id)?;
let room = self.create_room(channel, rocketchat_server.id.clone(), room_creator_id, invited_user_id, false)?;
self.add_virtual_users_to_room(rocketchat_api, channel, rocketchat_server.id.clone(), room.matrix_room_id.clone())?;
Ok(room)
}
Expand All @@ -129,6 +129,7 @@ impl<'a> RoomHandler<'a> {
rocketchat_room_id: None,
is_admin_room: true,
is_bridged: false,
is_direct_message_room: false,
};
Room::insert(self.connection, &room)?;
let user_in_room = NewUserInRoom {
Expand Down Expand Up @@ -189,7 +190,7 @@ impl<'a> RoomHandler<'a> {
}

fn handle_user_leave(&self, matrix_user_id: &UserId, matrix_room_id: &RoomId) -> Result<()> {
let room = match Room::find_by_matrix_room_id(self.connection, matrix_room_id)? {
let mut room = match Room::find_by_matrix_room_id(self.connection, matrix_room_id)? {
Some(room) => room,
None => return Ok(()),
};
Expand All @@ -198,6 +199,10 @@ impl<'a> RoomHandler<'a> {
return self.leave_and_forget_room(&room);
}

if room.is_direct_message_room {
room.set_is_bridged(self.connection, false)?;
}

if let Some(user_in_room) =
UserInRoom::find_by_matrix_user_id_and_matrix_room_id(self.connection, matrix_user_id, matrix_room_id)?
{
Expand Down Expand Up @@ -312,6 +317,7 @@ impl<'a> RoomHandler<'a> {
rocketchat_server_id: String,
room_creator_id: UserId,
invited_user_id: UserId,
is_direct_message_room: bool,
) -> Result<Room> {
let bot_matrix_user_id = self.config.matrix_bot_user_id()?;
let room_alias_name = format!("{}_{}_{}", self.config.sender_localpart, rocketchat_server_id, channel.id);
Expand All @@ -325,6 +331,7 @@ impl<'a> RoomHandler<'a> {
rocketchat_room_id: Some(channel.id.clone()),
is_admin_room: false,
is_bridged: true,
is_direct_message_room: is_direct_message_room,
};
let room = Room::insert(self.connection, &new_room)?;

Expand Down Expand Up @@ -376,7 +383,7 @@ impl<'a> RoomHandler<'a> {
None => {
info!(
self.logger,
"Received join event for bot user {} and room {}, but the room wasn't persisted to the database. \
"Received join event for user {} and room {}, but the room wasn't persisted to the database. \
This is usually because the join event was finished before the room was stored in the database. \
That's not an issue, because room creators are saved to the database when the room is created.",
&matrix_user_id,
Expand All @@ -398,8 +405,8 @@ impl<'a> RoomHandler<'a> {
}

let user_in_room = NewUserInRoom {
matrix_user_id: matrix_user_id,
matrix_room_id: matrix_room_id,
matrix_user_id: matrix_user_id.clone(),
matrix_room_id: matrix_room_id.clone(),
};
UserInRoom::insert(self.connection, &user_in_room)?;

Expand Down
1 change: 1 addition & 0 deletions src/matrix-rocketchat/handlers/rocketchat/forwarder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,7 @@ impl<'a> Forwarder<'a> {
rocketchat_server.id.clone(),
direct_message_sender.matrix_user_id.clone(),
user_on_rocketchat_server.matrix_user_id.clone(),
true,
)?;

Ok(Some(room.matrix_room_id.clone()))
Expand Down
72 changes: 72 additions & 0 deletions tests/forward_rocketchat_direct_message_to_matrix.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,9 @@ use matrix_rocketchat_test::{MessageForwarder, RS_TOKEN, Test, default_timeout,
use router::Router;
use ruma_client_api::Endpoint;
use ruma_client_api::r0::account::register::Endpoint as RegisterEndpoint;
use ruma_client_api::r0::membership::forget_room::Endpoint as ForgetRoomEndpoint;
use ruma_client_api::r0::membership::invite_user::Endpoint as InviteEndpoint;
use ruma_client_api::r0::membership::leave_room::Endpoint as LeaveRoomEndpoint;
use ruma_client_api::r0::room::create_room::Endpoint as CreateRoomEndpoint;
use ruma_client_api::r0::send::send_message_event::Endpoint as SendMessageEventEndpoint;
use ruma_identifiers::{RoomId, UserId};
Expand Down Expand Up @@ -125,6 +127,76 @@ fn successfully_forwards_a_direct_message() {
assert!(second_message_received_by_matrix.contains("Yay"));
}

#[test]
fn the_bot_user_stays_in_the_direct_message_room_if_the_user_leaves() {
let test = Test::new();

let mut rocketchat_router = Router::new();
let mut direct_messages = HashMap::new();
direct_messages.insert("spec_user_id_other_user_id", vec!["spec_user", "other_user"]);
let direct_messages_list_handler = handlers::RocketchatDirectMessagesList {
direct_messages: direct_messages,
status: status::Ok,
};
rocketchat_router.get(DIRECT_MESSAGES_LIST_PATH, direct_messages_list_handler, "direct_messages_list");

let mut matrix_router = test.default_matrix_routes();
let (forget_message_forwarder, forget_receiver) = MessageForwarder::new();
let (leave_room, leave_receiver) = handlers::MatrixLeaveRoom::with_forwarder(test.config.as_url.clone());
matrix_router.post(LeaveRoomEndpoint::router_path(), leave_room, "leave_room");
matrix_router.post(ForgetRoomEndpoint::router_path(), forget_message_forwarder, "forget_room");

let test = test.with_matrix_routes(matrix_router)
.with_rocketchat_mock()
.with_custom_rocketchat_routes(rocketchat_router)
.with_connected_admin_room()
.with_logged_in_user()
.run();

let direct_message = Message {
message_id: "spec_id_1".to_string(),
token: Some(RS_TOKEN.to_string()),
channel_id: "spec_user_id_other_user_id".to_string(),
channel_name: None,
user_id: "other_user_id".to_string(),
user_name: "other_user".to_string(),
text: "Hey there".to_string(),
};
let direct_message_payload = to_string(&direct_message).unwrap();

helpers::simulate_message_from_rocketchat(&test.config.as_url, &direct_message_payload);

helpers::join(
&test.config.as_url,
RoomId::try_from("!1234_id:localhost").unwrap(),
UserId::try_from("@spec_user:localhost").unwrap(),
);

helpers::leave_room(
&test.config.as_url,
RoomId::try_from("!1234_id:localhost").unwrap(),
UserId::try_from("@spec_user:localhost").unwrap(),
);

// no calls to the leave and forget endpoints, because the virtual user stays in the room
assert!(leave_receiver.recv_timeout(default_timeout()).is_err());
assert!(forget_receiver.recv_timeout(default_timeout()).is_err());

let connection = test.connection_pool.get().unwrap();
let room = Room::find_by_rocketchat_room_id(&connection, "rc_id".to_string(), "spec_user_id_other_user_id".to_string())
.unwrap()
.unwrap();

let users = room.users(&connection).unwrap();
assert_eq!(users.len(), 1);
assert!(users.iter().any(|u| u.matrix_user_id == UserId::try_from("@rocketchat_other_user_id_rc_id:localhost").unwrap()));

assert!(!room.is_bridged)
}

#[test]
fn successfully_forwards_a_direct_message_to_a_room_that_was_bridged_before() {}

#[test]
fn no_room_is_created_when_the_user_doesn_not_have_access_to_the_matching_direct_message_channel() {
let test = Test::new();
Expand Down

0 comments on commit 7a1ed9e

Please sign in to comment.