Skip to content

Commit

Permalink
Show notice if user cannot post message
Browse files Browse the repository at this point in the history
  • Loading branch information
aaravlu committed Nov 21, 2024
1 parent 4ba3294 commit eef4f2d
Show file tree
Hide file tree
Showing 3 changed files with 122 additions and 26 deletions.
2 changes: 0 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -197,5 +197,3 @@ appdata_paths = [
"$APPDATA/$PUBLISHER/$PRODUCTNAME",
"$LOCALAPPDATA/$PRODUCTNAME",
]
[profile.dev]
debug = 0
44 changes: 43 additions & 1 deletion src/home/room_screen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -805,7 +805,7 @@ live_design! {
location_preview = <LocationPreview> { }

// Below that, display a view that holds the message input bar and send button.
<View> {
bottom_input = <View> {
width: Fill, height: Fit
flow: Right,
align: {y: 0.5},
Expand Down Expand Up @@ -912,6 +912,24 @@ live_design! {
icon_walk: {width: 18.0, height: Fit},
}
}
no_send_permisson_notice = <View> {
visible: false
show_bg: true
draw_bg: {
color: #EFEFEF
}
padding: {left: 75}
align: {y: 0.5}
width: Fill, height: 31,

<Label> {
draw_text: {
color: #111111
text_style: <THEME_FONT_ITALIC>{font_size: 12.2}
}
text: "You don't have permission to post to this room"
}
}
}

// The top space should be displayed on top of the timeline
Expand Down Expand Up @@ -1460,6 +1478,9 @@ impl RoomScreen {
///
/// Redraws this RoomScreen view if any updates were applied.
fn process_timeline_updates(&mut self, cx: &mut Cx, portal_list: &PortalListRef) {
let bottom_input = self.view(id!(bottom_input));
let no_send_permisson_notice = self.view(id!(no_send_permisson_notice));

let top_space = self.view(id!(top_space));
let jump_to_bottom = self.jump_to_bottom_button(id!(jump_to_bottom));
let curr_first_id = portal_list.first_id();
Expand Down Expand Up @@ -1688,6 +1709,17 @@ impl RoomScreen {
// if the list of typing users gets updated many times in a row.
typing_users = users;
}

TimelineUpdate::PostPermission(can_post) => {
if can_post {
bottom_input.set_visible(true);
no_send_permisson_notice.set_visible(false)
}
else {
bottom_input.set_visible(false);
no_send_permisson_notice.set_visible(true)
}
}
}
}

Expand Down Expand Up @@ -1809,6 +1841,8 @@ impl RoomScreen {
/// Invoke this when this timeline is being shown,
/// e.g., when the user navigates to this timeline.
fn show_timeline(&mut self, cx: &mut Cx) {
self.check_user_post_permission();

let room_id = self.room_id.clone()
.expect("BUG: Timeline::show_timeline(): no room_id was set.");
// just an optional sanity check
Expand Down Expand Up @@ -2071,6 +2105,13 @@ impl RoomScreen {
}
tl.last_scrolled_index = first_index;
}

/// Send request as `MatrixRequest` to check post permission.
fn check_user_post_permission(&self) {
if let Some(room_id) = self.room_id.clone() {
submit_async_request(MatrixRequest::CheckUserPostPermission { room_id })
}
}
}

impl RoomScreenRef {
Expand Down Expand Up @@ -2146,6 +2187,7 @@ pub enum TimelineUpdate {
/// The list of users (their displayable name) who are currently typing in this room.
users: Vec<String>,
},
PostPermission(bool)
}

/// The global set of all timeline states, one entry per room.
Expand Down
102 changes: 79 additions & 23 deletions src/sliding_sync.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,10 @@ use matrix_sdk::{
config::RequestConfig, event_handler::EventHandlerDropGuard, media::MediaRequest, room::{Receipts, RoomMember}, ruma::{
api::client::{receipt::create_receipt::v3::ReceiptType, session::get_login_types::v3::LoginType}, events::{
receipt::ReceiptThread, room::{
message::{ForwardThread, RoomMessageEventContent}, MediaSource
message::{ForwardThread, RoomMessageEventContent}, power_levels::RoomPowerLevelsEventContent, MediaSource
}, FullStateEventContent
}, MilliSecondsSinceUnixEpoch, OwnedEventId, OwnedMxcUri, OwnedRoomAliasId, OwnedRoomId, OwnedUserId, UserId
}, sliding_sync::VersionBuilder, Client, Room, Error
}, sliding_sync::VersionBuilder, Client, Error, Room
};
use matrix_sdk_ui::{
room_list_service::{self, RoomListLoadingState},
Expand Down Expand Up @@ -102,7 +102,7 @@ async fn build_client(
let homeserver_url = cli.homeserver.as_deref()
.unwrap_or("https://matrix-client.matrix.org/");
// .unwrap_or("https://matrix.org/");

let mut builder = Client::builder()
.server_name_or_homeserver_url(homeserver_url)
// Use a sqlite database to persist the client's encryption setup.
Expand Down Expand Up @@ -180,7 +180,7 @@ async fn login(
bail!("Failed to login as {}: {login_result:?}", cli.username);
}
}

LoginRequest::LoginBySSOSuccess(client, client_session) => {
if let Err(e) = persistent_state::save_session(&client, client_session).await {
error!("Failed to save session state to storage: {e:?}");
Expand Down Expand Up @@ -226,7 +226,7 @@ async fn populate_login_types(
}

/// Which direction to paginate in.
///
///
/// * `Forwards` will retrieve later events (towards the end of the timeline),
/// which only works if the timeline is *focused* on a specific event.
/// * `Backwards`: the more typical choice, in which earlier events are retrieved
Expand Down Expand Up @@ -349,6 +349,10 @@ pub enum MatrixRequest {
FullyReadReceipt{
room_id: OwnedRoomId,
event_id: OwnedEventId,
},
/// Sends checking that if user has permission to post in the given room upon entering.
CheckUserPostPermission{
room_id: OwnedRoomId,
}
}

Expand All @@ -366,7 +370,7 @@ pub enum LoginRequest{
LoginBySSOSuccess(Client, ClientSessionPersisted),
LoginByCli,
HomeserverLoginTypesQuery(String),

}
/// Information needed to log in to a Matrix homeserver.
pub struct LoginByPassword {
Expand Down Expand Up @@ -766,7 +770,30 @@ async fn async_worker(
Err(_e) => error!("Failed to send fully read receipt to room {room_id}, event {event_id}; error: {_e:?}"),
}
});
}
},

MatrixRequest::CheckUserPostPermission { room_id } => {
let (timeline, sender) = {
let all_room_info = ALL_ROOM_INFO.lock().unwrap();
let Some(room_info) = all_room_info.get(&room_id) else {
log!("BUG: room info not found for fetch members request {room_id}");
continue;
};

(room_info.timeline.clone(), room_info.timeline_update_sender.clone())
};

let Some(client) = CLIENT.get() else { continue };
let Some(user_id) = client.user_id() else { continue };

let _check_user_send_permission_task = Handle::current().spawn(async move {
let room = timeline.room();
let can_user_post_message = room.can_user_send_message(user_id, matrix_sdk::ruma::events::MessageLikeEventType::Message).await.unwrap_or(true);
if let Err(_) = sender.send(TimelineUpdate::PostPermission(can_user_post_message)) {
error!("Failed to send the result of user send permission")
}
});
}
}
}

Expand All @@ -790,7 +817,7 @@ pub fn start_matrix_tokio() -> Result<()> {
// Create a channel to be used between UI thread(s) and the async worker thread.
let (sender, receiver) = tokio::sync::mpsc::unbounded_channel::<MatrixRequest>();
REQUEST_SENDER.set(sender).expect("BUG: REQUEST_SENDER already set!");

let (login_sender, login_receiver) = tokio::sync::mpsc::channel(1);
// Start a high-level async task that will start and monitor all other tasks.
let _monitor = rt.spawn(async move {
Expand Down Expand Up @@ -933,7 +960,7 @@ pub fn is_user_ignored(user_id: &UserId) -> bool {


/// Returns three channel endpoints related to the timeline for the given room.
///
///
/// 1. A timeline update sender.
/// 2. The timeline update receiver, which is a singleton, and can only be taken once.
/// 3. A `tokio::watch` sender that can be used to send requests to the timeline subscriber handler.
Expand Down Expand Up @@ -1256,7 +1283,7 @@ async fn update_room(
if let Some(old_latest_event) = old_room.latest_event().await {
if new_latest_event.timestamp() > old_latest_event.timestamp() {
log!("Updating latest event for room {}", new_room_id);
room_avatar_changed = update_latest_event(new_room_id.clone(), &new_latest_event);
(room_avatar_changed, _) = update_latest_event(new_room_id.clone(), &new_latest_event);
}
}
}
Expand Down Expand Up @@ -1615,7 +1642,7 @@ async fn timeline_subscriber_handler(
} else {
found_target_event_id = find_target_event(&mut target_event_id, std::iter::once(&value));
}

clear_cache = true;
timeline_items.push_front(value);
reobtain_latest_event |= latest_event.is_none();
Expand Down Expand Up @@ -1694,7 +1721,7 @@ async fn timeline_subscriber_handler(
if index <= *i {
*i = i.saturating_sub(1);
}
}
}
timeline_items.remove(index);
if LOG_TIMELINE_DIFFS { log!("timeline_subscriber: room {room_id} diff Remove at {index}. Changes: {index_of_first_change}..{index_of_last_change}"); }
reobtain_latest_event = true;
Expand All @@ -1721,16 +1748,16 @@ async fn timeline_subscriber_handler(
}
}
}

if num_updates > 0 {
let new_latest_event = if reobtain_latest_event {
timeline.latest_event().await
} else {
None
};

let changed_indices = index_of_first_change..index_of_last_change;

if LOG_TIMELINE_DIFFS {
log!("timeline_subscriber: applied {num_updates} updates for room {room_id}, timeline now has {} items. is_append? {is_append}, clear_cache? {clear_cache}. Changes: {changed_indices:?}.", timeline_items.len());
}
Expand All @@ -1756,15 +1783,18 @@ async fn timeline_subscriber_handler(

// Send a Makepad-level signal to update this room's timeline UI view.
SignalToUI::set_ui_signal();

// Update the latest event for this room.
if let Some(new_latest) = new_latest_event {
if latest_event.as_ref().map_or(true, |ev| ev.timestamp() < new_latest.timestamp()) {
let room_avatar_changed = update_latest_event(room_id.clone(), &new_latest);
let (room_avatar_changed, can_user_post_message) = update_latest_event(room_id.clone(), &new_latest);
latest_event = Some(new_latest);
if room_avatar_changed {
spawn_fetch_room_avatar(room.clone());
}
if let Err(_) = timeline_update_sender.send(TimelineUpdate::PostPermission(can_user_post_message)) {
error!("Failed to send the result of user send permission")
}
}
}
}
Expand Down Expand Up @@ -1793,8 +1823,9 @@ async fn timeline_subscriber_handler(
fn update_latest_event(
room_id: OwnedRoomId,
event_tl_item: &EventTimelineItem,
) -> bool {
) -> (bool, bool) {
let mut room_avatar_changed = false;
let mut can_user_post_message = true;

let (timestamp, latest_message_text) = get_latest_event_details(event_tl_item, &room_id);

Expand All @@ -1810,6 +1841,9 @@ fn update_latest_event(
AnyOtherFullStateEventContent::RoomAvatar(_avatar_event) => {
room_avatar_changed = true;
}
AnyOtherFullStateEventContent::RoomPowerLevels(user_power_level_event) => {
can_user_post_message = check_post_permission_from_event(user_power_level_event)
}
_ => { }
}
_ => { }
Expand All @@ -1819,7 +1853,7 @@ fn update_latest_event(
timestamp,
latest_message_text,
});
room_avatar_changed
(room_avatar_changed, can_user_post_message)
}


Expand Down Expand Up @@ -1875,10 +1909,10 @@ async fn spawn_sso_server(
let mut cli = Cli::default();
cli.homeserver = (!homeserver_url.is_empty()).then_some(homeserver_url);
Handle::current().spawn(async move {
let Ok((client, client_session)) = build_client(&cli, app_data_dir()).await else {
Cx::post_action(LoginAction::LoginFailure("Failed to establish client".to_string()));
return;
};
let Ok((client, client_session)) = build_client(&cli, app_data_dir()).await else {
Cx::post_action(LoginAction::LoginFailure("Failed to establish client".to_string()));
return;
};
let mut is_logged_in = false;
match client
.matrix_auth()
Expand Down Expand Up @@ -1931,3 +1965,25 @@ async fn spawn_sso_server(
Cx::post_action(LoginAction::SsoPending(false));
});
}

/// Check if user can post message from event.
fn check_post_permission_from_event(full_state_event_content: &FullStateEventContent<RoomPowerLevelsEventContent>) -> bool {
let mut can_user_post_message = true;

match full_state_event_content {
FullStateEventContent::Original { content, prev_content: _ } => {
if let Some(client) = CLIENT.get() {
if let Some(user_id) = client.user_id() {
if let Some(power) = content.users.get(user_id) {
if power.is_negative() {
can_user_post_message = false
}
}
}
};
},
_ => { }
}

can_user_post_message
}

0 comments on commit eef4f2d

Please sign in to comment.