Skip to content

Commit

Permalink
Do not store the UserInRoom in the database anymore
Browse files Browse the repository at this point in the history
  • Loading branch information
exul committed Aug 19, 2017
1 parent 3329fd6 commit a934bb8
Show file tree
Hide file tree
Showing 31 changed files with 883 additions and 851 deletions.
4 changes: 2 additions & 2 deletions assets/translations.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -72,9 +72,8 @@ en:
internal_error: "An internal error occurred"
handlers:
welcome: "Your Rocket.Chat <-> Matrix application service is running"
rocketchat_login_successful: "You are logged in. Return to your Matrix client and follow the instructions there."
rocketchat_login_successful: "You are logged in. Return to your Matrix client and enter help in the admin room for more instructions."
errors:
admin_room_for_rocketchat_server_not_found: "No admin room found that is connected to the Rocket.Chat server ${rocketchat_url}"
authentication_failed: "Authentication failed!"
connect_without_rocketchat_server_id: "You have to provide an id to connect to a Rocket.Chat server. It can contain any alphanumeric character and `_`. For example `connect https://rocketchat.example.com my_token rocketchat_example`"
connect_with_invalid_rocketchat_server_id: "The provided Rocket.Chat server ID `${rocketchat_server_id}` is not valid, it can only contain lowercase alphanumeric characters and `_`. The maximum length is ${max_rocketchat_server_id_length} characters."
Expand All @@ -86,6 +85,7 @@ en:
rocketchat_token_missing: "A token is needed to connect new Rocket.Chat servers"
rocketchat_server_already_connected: "The Rocket.Chat server ${rocketchat_url} is already connected, connect without a token if you want to connect to the server"
rocketchat_server_id_already_in_use: "The provided ID `${rocketchat_server_id}` is already in use, please choose another one."
rocketchat_server_not_found: "Rocket.Chat server ${rocketchat_url} not found, it is probably not connected."
rocketchat_server_unreachable: "Could not reach Rocket.Chat server ${rocketchat_url}"
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"
Expand Down
6 changes: 4 additions & 2 deletions src/matrix-rocketchat/api/matrix/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use ruma_client_api::Endpoint;
use ruma_client_api::unversioned::get_supported_versions::{Endpoint as GetSupportedVersionsEndpoint,
Response as GetSupportedVersionsResponse};
use ruma_events::room::member::MemberEvent;
use ruma_identifiers::{RoomId, UserId};
use ruma_identifiers::{RoomAliasId, RoomId, UserId};
use serde_json;
use slog::Logger;

Expand All @@ -21,6 +21,8 @@ pub trait MatrixApi: Send + Sync + MatrixApiClone {
fn create_room(&self, room_name: Option<String>, room_alias_name: Option<String>, creator_id: &UserId) -> Result<RoomId>;
/// Forget a room.
fn forget_room(&self, matrix_room_id: RoomId) -> Result<()>;
/// Resolve the room alias for a room and return the Room ID if it exists.
fn get_alias(&self, matrix_room_alias: RoomAliasId) -> Result<Option<RoomId>>;
/// Get the `user_id` of the user that created the room.
fn get_room_creator(&self, matrix_room_id: RoomId) -> Result<UserId>;
/// Get the list of members for this room.
Expand All @@ -30,7 +32,7 @@ pub trait MatrixApi: Send + Sync + MatrixApiClone {
/// Join a room with a user.
fn join(&self, matrix_room_id: RoomId, matrix_user_id: UserId) -> Result<()>;
/// Leave a room.
fn leave_room(&self, matrix_room_id: RoomId) -> Result<()>;
fn leave_room(&self, matrix_room_id: RoomId, matrix_user_id: UserId) -> Result<()>;
/// Register a user.
fn register(&self, user_id_local_part: String) -> Result<()>;
/// Send a text message to a room.
Expand Down
34 changes: 31 additions & 3 deletions src/matrix-rocketchat/api/matrix/r0.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ use std::convert::TryFrom;
use pulldown_cmark::{Options, Parser, html};
use reqwest::StatusCode;
use ruma_client_api::Endpoint;
use ruma_client_api::r0::alias;
use ruma_client_api::r0::alias::get_alias::{self, Endpoint as GetAliasEndpoint};
use ruma_client_api::r0::account::register::{self, Endpoint as RegisterEndpoint};
use ruma_client_api::r0::membership::forget_room::{self, Endpoint as ForgetRoomEndpoint};
use ruma_client_api::r0::membership::invite_user::{self, Endpoint as InviteUserEndpoint};
Expand All @@ -18,7 +20,7 @@ use ruma_client_api::r0::sync::get_state_events_for_empty_key::{self, Endpoint a
use ruma_events::EventType;
use ruma_events::room::member::MemberEvent;
use ruma_events::room::message::MessageType;
use ruma_identifiers::{EventId, RoomId, UserId};
use ruma_identifiers::{EventId, RoomAliasId, RoomId, UserId};
use serde_json::Map;
use slog::Logger;
use serde_json::{self, Value};
Expand Down Expand Up @@ -107,6 +109,29 @@ impl super::MatrixApi for MatrixApi {
Ok(())
}

fn get_alias(&self, matrix_room_alias: RoomAliasId) -> Result<Option<RoomId>> {
let path_params = alias::PathParams { room_alias: matrix_room_alias };
let endpoint = self.base_url.clone() + &GetAliasEndpoint::request_path(path_params);
let params = self.params_hash();

let (body, status_code) = RestApi::call_matrix(ForgetRoomEndpoint::method(), &endpoint, "{}", &params)?;
if status_code == StatusCode::NotFound {
return Ok(None);
} else if !status_code.is_success() {
return Err(build_error(&endpoint, &body, &status_code));
}

let get_alias_response: get_alias::Response = serde_json::from_str(&body).chain_err(|| {
ErrorKind::InvalidJSON(format!(
"Could not deserialize response from Matrix get_alias API endpoint: \
`{}`",
body
))
})?;

Ok(Some(get_alias_response.room_id))
}

fn get_room_creator(&self, matrix_room_id: RoomId) -> Result<UserId> {
let path_params = get_state_events_for_empty_key::PathParams {
room_id: matrix_room_id,
Expand Down Expand Up @@ -194,10 +219,13 @@ impl super::MatrixApi for MatrixApi {
Ok(())
}

fn leave_room(&self, matrix_room_id: RoomId) -> Result<()> {
fn leave_room(&self, matrix_room_id: RoomId, matrix_user_id: UserId) -> Result<()> {
let path_params = leave_room::PathParams { room_id: matrix_room_id };
let endpoint = self.base_url.clone() + &LeaveRoomEndpoint::request_path(path_params);
let params = self.params_hash();
let user_id = matrix_user_id.to_string();
let mut params = self.params_hash();
params.insert("user_id", &user_id);


let (body, status_code) = RestApi::call_matrix(LeaveRoomEndpoint::method(), &endpoint, "{}", &params)?;
if !status_code.is_success() {
Expand Down
6 changes: 6 additions & 0 deletions src/matrix-rocketchat/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,4 +55,10 @@ impl Config {
let user_id = format!("@{}:{}", &self.sender_localpart, &self.hs_domain);
UserId::try_from(&user_id).chain_err(|| ErrorKind::InvalidUserId(user_id)).map_err(Error::from)
}

/// Check if the user ID is part of the application service namespace
pub fn is_application_service_user(&self, matrix_user_id: &UserId) -> bool {
let id_prefix = format!("@{}", self.sender_localpart);
matrix_user_id.to_string().starts_with(&id_prefix)
}
}
3 changes: 0 additions & 3 deletions src/matrix-rocketchat/db/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,11 @@ pub mod room;
pub mod schema;
/// `User` entry
pub mod user;
/// `UserInRoom` entry
pub mod user_in_room;
/// `UserOnRocketchatServer` entry
pub mod user_on_rocketchat_server;

pub use self::connection_pool::ConnectionPool;
pub use self::rocketchat_server::{NewRocketchatServer, RocketchatServer};
pub use self::room::{NewRoom, Room};
pub use self::user::{NewUser, User};
pub use self::user_in_room::{NewUserInRoom, UserInRoom};
pub use self::user_on_rocketchat_server::{NewUserOnRocketchatServer, UserOnRocketchatServer};
37 changes: 2 additions & 35 deletions src/matrix-rocketchat/db/rocketchat_server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,10 @@ use diesel;
use diesel::prelude::*;
use diesel::sqlite::SqliteConnection;
use iron::typemap::Key;
use ruma_identifiers::UserId;

use i18n::*;
use errors::*;
use super::{Room, User, UserInRoom, UserOnRocketchatServer};
use super::schema::{rocketchat_servers, rooms, users_in_rooms, users_on_rocketchat_servers};
use super::UserOnRocketchatServer;
use super::schema::{rocketchat_servers, users_on_rocketchat_servers};

/// A Rocket.Chat server.
#[derive(Associations, Debug, Identifiable, Queryable)]
Expand Down Expand Up @@ -102,37 +100,6 @@ impl RocketchatServer {
.chain_err(|| ErrorKind::DBSelectError)?;
Ok(users_on_rocketchat_server)
}

/// Get the admin room for this Rocket.Chat server and a given user.
pub fn admin_room_for_user(&self, connection: &SqliteConnection, matrix_user_id: &UserId) -> Result<Option<Room>> {
let user = match User::find_by_matrix_user_id(connection, matrix_user_id)? {
Some(user) => user,
None => return Ok(None),
};

let rooms = rooms::table
.filter(rooms::is_admin_room.eq(true).and(rooms::matrix_room_id.eq_any(UserInRoom::belonging_to(&user).select(
users_in_rooms::matrix_room_id,
))))
.load::<Room>(connection)
.chain_err(|| ErrorKind::DBSelectError)?;
Ok(rooms.into_iter().next())
}

/// Same as admin_room_for_user but returns an error if no room is found.
pub fn admin_room_for_user_or_err(&self, connection: &SqliteConnection, matrix_user_id: &UserId) -> Result<Room> {
match self.admin_room_for_user(connection, matrix_user_id)? {
Some(room) => Ok(room),
None => {
Err(user_error!(
ErrorKind::AdminRoomForRocketchatServerNotFound(self.rocketchat_url.clone()),
t!(["errors", "admin_room_for_rocketchat_server_not_found"]).with_vars(vec![
("rocketchat_url", self.rocketchat_url.clone()),
])
))
}
}
}
}

impl Key for RocketchatServer {
Expand Down
54 changes: 19 additions & 35 deletions src/matrix-rocketchat/db/room.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
use diesel;
use diesel::prelude::*;
use diesel::sqlite::SqliteConnection;
use ruma_events::room::member::MembershipState;
use ruma_identifiers::{RoomId, UserId};

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

/// A room that is managed by the application service. This can be either a bridged room or an
/// admin room.
Expand Down Expand Up @@ -107,12 +109,13 @@ impl Room {
/// Indicates if the room is bridged for a given user.
pub fn is_bridged_for_user(
connection: &SqliteConnection,
matrix_api: &MatrixApi,
rocketchat_server_id: String,
rocketchat_room_id: String,
matrix_user_id: &UserId,
) -> Result<bool> {
if let Some(room) = Room::find_by_rocketchat_room_id(connection, rocketchat_server_id, rocketchat_room_id)? {
Ok(room.is_bridged && room.users(connection)?.iter().any(|u| &u.matrix_user_id == matrix_user_id))
Ok(room.is_bridged && room.user_ids(matrix_api)?.iter().any(|id| id == matrix_user_id))
} else {
Ok(false)
}
Expand Down Expand Up @@ -163,37 +166,19 @@ impl Room {
self.rocketchat_server_id.is_some()
}

/// Returns all `User`s in the room.
pub fn users(&self, connection: &SqliteConnection) -> Result<Vec<User>> {
let users: Vec<User> = users::table
.filter(users::matrix_user_id.eq_any(UserInRoom::belonging_to(self).select(users_in_rooms::matrix_user_id)))
.load(connection)
.chain_err(|| ErrorKind::DBSelectError)?;
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)
/// Users that are currently in the room.
pub fn user_ids(&self, matrix_api: &MatrixApi) -> Result<Vec<UserId>> {
let member_events = matrix_api.get_room_members(self.matrix_room_id.clone())?;
let user_ids = member_events
.into_iter()
.filter_map(|member_event| if member_event.content.membership == MembershipState::Join {
Some(member_event.user_id)
} else {
None
})
.collect();

Ok(user_ids)
}

/// Update the is_bridged flag for the room.
Expand All @@ -208,7 +193,6 @@ impl Room {

/// 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)?;
diesel::delete(rooms::table.filter(rooms::matrix_room_id.eq(self.matrix_room_id.clone())))
.execute(connection)
.chain_err(|| ErrorKind::DBDeleteError)?;
Expand Down
2 changes: 0 additions & 2 deletions src/matrix-rocketchat/db/schema.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,6 @@ table! {
users_in_rooms (matrix_user_id, matrix_room_id) {
matrix_user_id -> Text,
matrix_room_id -> Text,
created_at -> Timestamp,
updated_at -> Timestamp,
}
}

Expand Down
76 changes: 0 additions & 76 deletions src/matrix-rocketchat/db/user_in_room.rs

This file was deleted.

0 comments on commit a934bb8

Please sign in to comment.