Skip to content

Commit

Permalink
Add unbridge command
Browse files Browse the repository at this point in the history
  • Loading branch information
exul committed Mar 26, 2017
1 parent 0265b7d commit ffac0fd
Show file tree
Hide file tree
Showing 17 changed files with 512 additions and 121 deletions.
4 changes: 2 additions & 2 deletions .rustfmt.toml
@@ -1,4 +1,4 @@
fn_call_width = 124
max_width = 124
fn_call_width = 128
max_width = 128
reorder_imported_names = true
chain_one_line_max = 6
7 changes: 5 additions & 2 deletions assets/translations.yaml
Expand Up @@ -41,6 +41,7 @@ en:
${channel_list}
room_successfully_bridged: "${channel_name} is now bridged."
room_successfully_unbridged: "${channel_name} is now unbridged."
defaults:
admin_room_display_name: "Admin Room (Rocket.Chat)"
internal_error: "An internal error occurred"
Expand All @@ -50,6 +51,7 @@ en:
authentication_failed: "Authentication failed!"
internal: "An internal error occurred"
no_rocketchat_server: "No Rocket.Chat server found when querying ${rocketchat_url} (version information is missing from the response)"
other_user_joined: "Another user join the admin room, leaving, please create a new admin room."
rocketchat_channel_already_bridged: "The channel ${channel_name} is already bridged."
rocketchat_channel_not_found: "No channel with the name ${channel_name} found."
rocketchat_token_missing: "A token is needed to connect new Rocket.Chat servers"
Expand All @@ -58,7 +60,8 @@ en:
rocketchat_join_first: "You have to join the channel ${channel_name} on the Rocket.Chat server before you can bridge it."
room_already_connected: "This room is already connected"
room_not_connected: "This room is not connected to a Rocket.Chat server, you have to connect it first to be able to execute the command, type `help` for further instructions on how to connect this room"
room_not_empty: "Cannot unbdrige room ${channel_name}, because Matrix users (${users}) are still using the room."
token_already_in_use: "The token ${token} is already in use, please use another token."
unsupported_rocketchat_api_version: "No supported API version (>= ${min_version}) found for the Rocket.Chat server, found version: ${version}"
too_many_members_in_room: "Admin rooms must only contain the user that invites the bot. Too many members in the room, leaving."
other_user_joined: "Another user join the admin room, leaving, please create a new admin room."
unsupported_rocketchat_api_version: "No supported API version (>= ${min_version}) found for the Rocket.Chat server, found version: ${version}"
unbridge_of_not_bridged_room: "The channel ${channel_name} is not bridged, cannot unbridge it."
2 changes: 1 addition & 1 deletion src/matrix-rocketchat/db/rocketchat_server.rs
Expand Up @@ -7,7 +7,7 @@ use errors::*;
use super::schema::rocketchat_servers;

/// A Rocket.Chat server.
#[derive(Debug, Identifiable, Queryable)]
#[derive(Associations, Debug, Identifiable, Queryable)]
#[table_name="rocketchat_servers"]
pub struct RocketchatServer {
/// The unique id for the Rocket.Chat server
Expand Down
54 changes: 46 additions & 8 deletions src/matrix-rocketchat/db/room.rs
Expand Up @@ -4,10 +4,8 @@ use diesel::sqlite::SqliteConnection;
use ruma_identifiers::{RoomId, UserId};

use errors::*;
use super::schema::{rocketchat_servers, rooms, users, users_in_rooms};
use super::RocketchatServer;
use super::user::User;
use super::user_in_room::UserInRoom;
use super::schema::{rocketchat_servers, rooms, users, users_in_rooms, users_on_rocketchat_servers};
use super::{RocketchatServer, User, UserInRoom, UserOnRocketchatServer};

/// A room that is managed by the application service. This can be either a bridged room or an
/// admin room.
Expand Down Expand Up @@ -86,6 +84,20 @@ impl Room {
Ok(rooms.into_iter().next())
}

/// Find a `Room` by its display name. It also requires the server id, because the
/// display name might not be unique across servers.
/// Returns `None`, if the room is not found.
pub fn find_by_display_name(connection: &SqliteConnection,
rocketchat_server_id: i32,
display_name: String)
-> Result<Option<Room>> {
let rooms = rooms::table.filter(rooms::rocketchat_server_id.eq(rocketchat_server_id)
.and(rooms::display_name.eq(display_name)))
.load(connection)
.chain_err(|| ErrorKind::DBSelectError)?;
Ok(rooms.into_iter().next())
}

/// Indicates if the room is bridged for a given user.
pub fn is_bridged_for_user(connection: &SqliteConnection,
rocketchat_server_id: i32,
Expand All @@ -100,10 +112,7 @@ impl Room {
}

/// Indicates if a room is bridged.
pub fn is_bridged(connection: &SqliteConnection,
rocketchat_server_id: i32,
rocketchat_room_id: String)
-> Result<bool> {
pub fn is_bridged(connection: &SqliteConnection, rocketchat_server_id: i32, rocketchat_room_id: String) -> Result<bool> {
match Room::find_by_rocketchat_room_id(connection, rocketchat_server_id, rocketchat_room_id)? {
Some(room) => Ok(room.is_bridged),
None => Ok(false),
Expand Down Expand Up @@ -154,6 +163,35 @@ impl Room {
Ok(users)
}

/// Returns all `Users`s in the room that are not virtual users.
pub fn non_virtual_users(&self, connection: &SqliteConnection) -> Result<Vec<User>> {
let rocketchat_server = match self.rocketchat_server(connection)? {
Some(rocketchat_server) => rocketchat_server,
None => {
return self.users(connection);
}
};

let users: Vec<User> =
users::table.filter(
users::matrix_user_id.eq_any(
UserInRoom::belonging_to(self).select(users_in_rooms::matrix_user_id)
).and(users::matrix_user_id.eq_any(
UserOnRocketchatServer::belonging_to(&rocketchat_server).filter(
users_on_rocketchat_servers::is_virtual_user.eq(false)
).select(users_on_rocketchat_servers::matrix_user_id)
))).load(connection).chain_err(|| ErrorKind::DBSelectError)?;
Ok(users)
}

/// Update the is_bridged flag for the room.
pub fn set_is_bridged(&self, connection: &SqliteConnection, is_bridged: bool) -> Result<()> {
diesel::update(rooms::table.find(&self.matrix_room_id)).set(rooms::is_bridged.eq(is_bridged))
.execute(connection)
.chain_err(|| ErrorKind::DBUpdateError)?;
Ok(())
}

/// Delete a room, this also deletes any users_in_rooms relations for that room.
pub fn delete(&self, connection: &SqliteConnection) -> Result<()> {
diesel::delete(UserInRoom::belonging_to(self)).execute(connection).chain_err(|| ErrorKind::DBDeleteError)?;
Expand Down
4 changes: 3 additions & 1 deletion src/matrix-rocketchat/db/user.rs
Expand Up @@ -10,7 +10,9 @@ use i18n::*;
use super::schema::users;

/// A Matrix `User`.
#[derive(Debug, Queryable)]
#[derive(Associations, Debug, Identifiable, Queryable)]
#[primary_key(matrix_user_id)]
#[table_name="users"]
pub struct User {
/// The users unique id on the Matrix server.
pub matrix_user_id: UserId,
Expand Down
18 changes: 14 additions & 4 deletions src/matrix-rocketchat/db/user_in_room.rs
Expand Up @@ -10,8 +10,8 @@ use super::schema::users_in_rooms;
/// Join table for users that participate in a room.
#[derive(Associations, Debug, Identifiable, Queryable)]
#[belongs_to(Room, foreign_key = "matrix_room_id")]
#[table_name="users_in_rooms"]
#[primary_key(matrix_user_id, matrix_room_id)]
#[table_name="users_in_rooms"]
pub struct UserInRoom {
/// The users unique id on the Matrix server.
pub matrix_user_id: UserId,
Expand All @@ -36,9 +36,7 @@ pub struct NewUserInRoom {
impl UserInRoom {
/// Insert a new `UserInRoom` into the database.
pub fn insert(connection: &SqliteConnection, user_in_room: &NewUserInRoom) -> Result<UserInRoom> {
diesel::insert(user_in_room).into(users_in_rooms::table)
.execute(connection)
.chain_err(|| ErrorKind::DBInsertError)?;
diesel::insert(user_in_room).into(users_in_rooms::table).execute(connection).chain_err(|| ErrorKind::DBInsertError)?;
UserInRoom::find(connection, &user_in_room.matrix_user_id, &user_in_room.matrix_room_id)
}

Expand All @@ -60,4 +58,16 @@ impl UserInRoom {
.chain_err(|| ErrorKind::DBSelectError)?;
Ok(user_in_room.into_iter().next())
}

/// Delete a user_in_room.
pub fn delete(&self, connection: &SqliteConnection) -> Result<()> {
diesel::delete(
users_in_rooms::table.filter(
users_in_rooms::matrix_user_id.eq(&self.matrix_user_id).and(users_in_rooms::matrix_room_id.eq(&self.matrix_room_id))
)
).execute(connection).chain_err(|| ErrorKind::DBDeleteError)?;

Ok(())

}
}
7 changes: 5 additions & 2 deletions src/matrix-rocketchat/db/user_on_rocketchat_server.rs
Expand Up @@ -5,10 +5,13 @@ use ruma_identifiers::UserId;

use errors::*;
use super::schema::users_on_rocketchat_servers;
use super::User;
use super::{RocketchatServer, User};

/// A user on a Rocket.Chat server.
#[derive(Debug, Queryable)]
#[derive(Associations, Debug, Identifiable, Queryable)]
#[belongs_to(RocketchatServer, foreign_key = "rocketchat_server_id")]
#[primary_key(matrix_user_id, rocketchat_server_id)]
#[table_name="users_on_rocketchat_servers"]
pub struct UserOnRocketchatServer {
/// Flag to indicate if the user is only used to send messages from Rocket.Chat
pub is_virtual_user: bool,
Expand Down
15 changes: 11 additions & 4 deletions src/matrix-rocketchat/errors.rs
Expand Up @@ -213,6 +213,16 @@ error_chain!{
display("Bridging the channel {} failed, because the user hasn't joined it on Rocket.Chat", channel_name)
}

UnbridgeOfNotBridgedRoom(display_name: String) {
description("Room with the given display name could not be found")
display("No room with display_name {} found", display_name)
}

RoomNotEmpty(display_name: String, users: String) {
description("Non virtual users are in the room")
display("The room {} has matrix users ({}) in it, cannot unbridge", display_name, users)
}

ReadConfigError {
description("Error when reading the config content to a string")
display("Could not read config content to string")
Expand Down Expand Up @@ -353,10 +363,7 @@ impl From<Error> for IronError {

impl<'a> Modifier<Response> for &'a Error {
fn modify(self, response: &mut Response) {
let mut causes = Vec::with_capacity(self.error_chain.iter().count() - 1);
for err in self.error_chain.iter().skip(1) {
causes.push(format!("{}", err));
}
let causes = self.error_chain.iter().skip(1).map(|e| format!("{}", e)).collect();

let resp = ErrorResponse {
error: format!("{}", self),
Expand Down

0 comments on commit ffac0fd

Please sign in to comment.