mirror of
https://github.com/youwen5/iamb.git
synced 2025-06-20 05:39:52 -07:00
Support redacting messages (#5)
This commit is contained in:
parent
d13d4b9f7f
commit
56ec90523c
6 changed files with 132 additions and 8 deletions
|
@ -69,7 +69,7 @@ two other TUI clients and Element Web:
|
||||||
| Send formatted messages (markdown) | :x: ([#10]) | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: |
|
| Send formatted messages (markdown) | :x: ([#10]) | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: |
|
||||||
| Rich Text Editor for formatted messages | :x: | :x: | :x: | :heavy_check_mark: |
|
| Rich Text Editor for formatted messages | :x: | :x: | :x: | :heavy_check_mark: |
|
||||||
| Display formatted messages | :x: ([#10]) | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: |
|
| Display formatted messages | :x: ([#10]) | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: |
|
||||||
| Redacting | :x: ([#5]) | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: |
|
| Redacting | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: |
|
||||||
| Multiple Matrix Accounts | :heavy_check_mark: | :x: | :heavy_check_mark: | :x: |
|
| Multiple Matrix Accounts | :heavy_check_mark: | :x: | :heavy_check_mark: | :x: |
|
||||||
| New user registration | :x: | :x: | :x: | :heavy_check_mark: |
|
| New user registration | :x: | :x: | :x: | :heavy_check_mark: |
|
||||||
| VOIP | :x: | :x: | :x: | :heavy_check_mark: |
|
| VOIP | :x: | :x: | :x: | :heavy_check_mark: |
|
||||||
|
|
|
@ -63,6 +63,7 @@ pub enum VerifyAction {
|
||||||
pub enum MessageAction {
|
pub enum MessageAction {
|
||||||
Cancel,
|
Cancel,
|
||||||
Download(Option<String>, bool),
|
Download(Option<String>, bool),
|
||||||
|
Redact(Option<String>),
|
||||||
Reply,
|
Reply,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -144,6 +144,19 @@ fn iamb_cancel(desc: CommandDescription, ctx: &mut ProgContext) -> ProgResult {
|
||||||
return Ok(step);
|
return Ok(step);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn iamb_redact(desc: CommandDescription, ctx: &mut ProgContext) -> ProgResult {
|
||||||
|
let args = desc.arg.strings()?;
|
||||||
|
|
||||||
|
if args.len() > 1 {
|
||||||
|
return Result::Err(CommandError::InvalidArgument);
|
||||||
|
}
|
||||||
|
|
||||||
|
let ract = IambAction::from(MessageAction::Redact(args.into_iter().next()));
|
||||||
|
let step = CommandStep::Continue(ract.into(), ctx.context.take());
|
||||||
|
|
||||||
|
return Ok(step);
|
||||||
|
}
|
||||||
|
|
||||||
fn iamb_reply(desc: CommandDescription, ctx: &mut ProgContext) -> ProgResult {
|
fn iamb_reply(desc: CommandDescription, ctx: &mut ProgContext) -> ProgResult {
|
||||||
if !desc.arg.text.is_empty() {
|
if !desc.arg.text.is_empty() {
|
||||||
return Result::Err(CommandError::InvalidArgument);
|
return Result::Err(CommandError::InvalidArgument);
|
||||||
|
@ -259,6 +272,7 @@ fn add_iamb_commands(cmds: &mut ProgramCommands) {
|
||||||
cmds.add_command(ProgramCommand { names: vec!["invite".into()], f: iamb_invite });
|
cmds.add_command(ProgramCommand { names: vec!["invite".into()], f: iamb_invite });
|
||||||
cmds.add_command(ProgramCommand { names: vec!["join".into()], f: iamb_join });
|
cmds.add_command(ProgramCommand { names: vec!["join".into()], f: iamb_join });
|
||||||
cmds.add_command(ProgramCommand { names: vec!["members".into()], f: iamb_members });
|
cmds.add_command(ProgramCommand { names: vec!["members".into()], f: iamb_members });
|
||||||
|
cmds.add_command(ProgramCommand { names: vec!["redact".into()], f: iamb_redact });
|
||||||
cmds.add_command(ProgramCommand { names: vec!["reply".into()], f: iamb_reply });
|
cmds.add_command(ProgramCommand { names: vec!["reply".into()], f: iamb_reply });
|
||||||
cmds.add_command(ProgramCommand { names: vec!["rooms".into()], f: iamb_rooms });
|
cmds.add_command(ProgramCommand { names: vec!["rooms".into()], f: iamb_rooms });
|
||||||
cmds.add_command(ProgramCommand { names: vec!["set".into()], f: iamb_set });
|
cmds.add_command(ProgramCommand { names: vec!["set".into()], f: iamb_set });
|
||||||
|
@ -429,4 +443,25 @@ mod tests {
|
||||||
let res = cmds.input_cmd("invite @user:example.com", ctx.clone());
|
let res = cmds.input_cmd("invite @user:example.com", ctx.clone());
|
||||||
assert_eq!(res, Err(CommandError::InvalidArgument));
|
assert_eq!(res, Err(CommandError::InvalidArgument));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_cmd_redact() {
|
||||||
|
let mut cmds = setup_commands();
|
||||||
|
let ctx = ProgramContext::default();
|
||||||
|
|
||||||
|
let res = cmds.input_cmd("redact", ctx.clone()).unwrap();
|
||||||
|
let act = IambAction::Message(MessageAction::Redact(None));
|
||||||
|
assert_eq!(res, vec![(act.into(), ctx.clone())]);
|
||||||
|
|
||||||
|
let res = cmds.input_cmd("redact Removed", ctx.clone()).unwrap();
|
||||||
|
let act = IambAction::Message(MessageAction::Redact(Some("Removed".into())));
|
||||||
|
assert_eq!(res, vec![(act.into(), ctx.clone())]);
|
||||||
|
|
||||||
|
let res = cmds.input_cmd("redact \"Removed\"", ctx.clone()).unwrap();
|
||||||
|
let act = IambAction::Message(MessageAction::Redact(Some("Removed".into())));
|
||||||
|
assert_eq!(res, vec![(act.into(), ctx.clone())]);
|
||||||
|
|
||||||
|
let res = cmds.input_cmd("redact Removed Removed", ctx.clone());
|
||||||
|
assert_eq!(res, Err(CommandError::InvalidArgument));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,16 +11,23 @@ use unicode_segmentation::UnicodeSegmentation;
|
||||||
use unicode_width::UnicodeWidthStr;
|
use unicode_width::UnicodeWidthStr;
|
||||||
|
|
||||||
use matrix_sdk::ruma::{
|
use matrix_sdk::ruma::{
|
||||||
events::room::message::{
|
events::{
|
||||||
MessageType,
|
room::{
|
||||||
OriginalRoomMessageEvent,
|
message::{
|
||||||
RedactedRoomMessageEvent,
|
MessageType,
|
||||||
RoomMessageEvent,
|
OriginalRoomMessageEvent,
|
||||||
RoomMessageEventContent,
|
RedactedRoomMessageEvent,
|
||||||
|
RoomMessageEvent,
|
||||||
|
RoomMessageEventContent,
|
||||||
|
},
|
||||||
|
redaction::SyncRoomRedactionEvent,
|
||||||
|
},
|
||||||
|
Redact,
|
||||||
},
|
},
|
||||||
MilliSecondsSinceUnixEpoch,
|
MilliSecondsSinceUnixEpoch,
|
||||||
OwnedEventId,
|
OwnedEventId,
|
||||||
OwnedUserId,
|
OwnedUserId,
|
||||||
|
RoomVersionId,
|
||||||
UInt,
|
UInt,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -323,10 +330,34 @@ impl MessageEvent {
|
||||||
pub fn show(&self) -> Cow<'_, str> {
|
pub fn show(&self) -> Cow<'_, str> {
|
||||||
match self {
|
match self {
|
||||||
MessageEvent::Original(ev) => show_room_content(&ev.content),
|
MessageEvent::Original(ev) => show_room_content(&ev.content),
|
||||||
MessageEvent::Redacted(_) => Cow::Borrowed("[redacted]"),
|
MessageEvent::Redacted(ev) => {
|
||||||
|
let reason = ev
|
||||||
|
.unsigned
|
||||||
|
.redacted_because
|
||||||
|
.as_ref()
|
||||||
|
.and_then(|e| e.as_original())
|
||||||
|
.and_then(|r| r.content.reason.as_ref());
|
||||||
|
|
||||||
|
if let Some(r) = reason {
|
||||||
|
Cow::Owned(format!("[Redacted: {:?}]", r))
|
||||||
|
} else {
|
||||||
|
Cow::Borrowed("[Redacted]")
|
||||||
|
}
|
||||||
|
},
|
||||||
MessageEvent::Local(content) => show_room_content(content),
|
MessageEvent::Local(content) => show_room_content(content),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn redact(&mut self, redaction: SyncRoomRedactionEvent, version: &RoomVersionId) {
|
||||||
|
match self {
|
||||||
|
MessageEvent::Redacted(_) => return,
|
||||||
|
MessageEvent::Local(_) => return,
|
||||||
|
MessageEvent::Original(ev) => {
|
||||||
|
let redacted = ev.clone().redact(redaction, version);
|
||||||
|
*self = MessageEvent::Redacted(Box::new(redacted));
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn show_room_content(content: &RoomMessageEventContent) -> Cow<'_, str> {
|
fn show_room_content(content: &RoomMessageEventContent) -> Cow<'_, str> {
|
||||||
|
|
|
@ -224,6 +224,33 @@ impl ChatState {
|
||||||
|
|
||||||
Err(IambError::NoAttachment.into())
|
Err(IambError::NoAttachment.into())
|
||||||
},
|
},
|
||||||
|
MessageAction::Redact(reason) => {
|
||||||
|
let room = store
|
||||||
|
.application
|
||||||
|
.worker
|
||||||
|
.client
|
||||||
|
.get_joined_room(self.id())
|
||||||
|
.ok_or(IambError::NotJoined)?;
|
||||||
|
|
||||||
|
let event_id = match &msg.event {
|
||||||
|
MessageEvent::Original(ev) => ev.event_id.clone(),
|
||||||
|
MessageEvent::Local(_) => {
|
||||||
|
self.scrollback.get_key(info).ok_or(IambError::NoSelectedMessage)?.1
|
||||||
|
},
|
||||||
|
MessageEvent::Redacted(_) => {
|
||||||
|
let msg = "";
|
||||||
|
let err = UIError::Failure(msg.into());
|
||||||
|
|
||||||
|
return Err(err);
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
let event_id = event_id.as_ref();
|
||||||
|
let reason = reason.as_deref();
|
||||||
|
let _ = room.redact(event_id, reason, None).await.map_err(IambError::from)?;
|
||||||
|
|
||||||
|
Ok(None)
|
||||||
|
},
|
||||||
MessageAction::Reply => {
|
MessageAction::Reply => {
|
||||||
self.reply_to = self.scrollback.get_key(info);
|
self.reply_to = self.scrollback.get_key(info);
|
||||||
self.focus = RoomFocus::MessageBar;
|
self.focus = RoomFocus::MessageBar;
|
||||||
|
|
|
@ -35,6 +35,7 @@ use matrix_sdk::{
|
||||||
room::{
|
room::{
|
||||||
message::{MessageType, RoomMessageEventContent},
|
message::{MessageType, RoomMessageEventContent},
|
||||||
name::RoomNameEventContent,
|
name::RoomNameEventContent,
|
||||||
|
redaction::{OriginalSyncRoomRedactionEvent, SyncRoomRedactionEvent},
|
||||||
topic::RoomTopicEventContent,
|
topic::RoomTopicEventContent,
|
||||||
},
|
},
|
||||||
typing::SyncTypingEvent,
|
typing::SyncTypingEvent,
|
||||||
|
@ -46,6 +47,7 @@ use matrix_sdk::{
|
||||||
OwnedRoomId,
|
OwnedRoomId,
|
||||||
OwnedRoomOrAliasId,
|
OwnedRoomOrAliasId,
|
||||||
OwnedUserId,
|
OwnedUserId,
|
||||||
|
RoomVersionId,
|
||||||
},
|
},
|
||||||
Client,
|
Client,
|
||||||
DisplayName,
|
DisplayName,
|
||||||
|
@ -547,6 +549,34 @@ impl ClientWorker {
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
let _ = self.client.add_event_handler(
|
||||||
|
|ev: OriginalSyncRoomRedactionEvent,
|
||||||
|
room: MatrixRoom,
|
||||||
|
store: Ctx<AsyncProgramStore>| {
|
||||||
|
async move {
|
||||||
|
let room_id = room.room_id();
|
||||||
|
let room_info = room.clone_info();
|
||||||
|
let room_version = room_info.room_version().unwrap_or(&RoomVersionId::V1);
|
||||||
|
|
||||||
|
let mut locked = store.lock().await;
|
||||||
|
let info = locked.application.get_room_info(room_id.to_owned());
|
||||||
|
|
||||||
|
// XXX: need to store a mapping of EventId -> MessageKey somewhere
|
||||||
|
// to avoid having to iterate over the messages here.
|
||||||
|
for ((_, id), msg) in info.messages.iter_mut().rev() {
|
||||||
|
if id != &ev.redacts {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
let ev = SyncRoomRedactionEvent::Original(ev);
|
||||||
|
msg.event.redact(ev, room_version);
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
let _ = self.client.add_event_handler(
|
let _ = self.client.add_event_handler(
|
||||||
|ev: OriginalSyncKeyVerificationStartEvent,
|
|ev: OriginalSyncKeyVerificationStartEvent,
|
||||||
client: Client,
|
client: Client,
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue