[fractal] API: Use EventId



commit 88bace4d20bb423a099433e928b5cf1bca3db041
Author: Alejandro Domínguez <adomu net-c com>
Date:   Tue Apr 28 07:29:45 2020 +0200

    API: Use EventId

 fractal-gtk/src/actions/global.rs                  | 14 +++---
 fractal-gtk/src/actions/message.rs                 | 21 ++------
 fractal-gtk/src/appop/message.rs                   | 25 +++++-----
 fractal-gtk/src/appop/notify.rs                    |  4 +-
 fractal-gtk/src/cache/state.rs                     | 10 +++-
 fractal-gtk/src/uitypes.rs                         |  4 +-
 fractal-gtk/src/widgets/media_viewer.rs            |  5 +-
 fractal-gtk/src/widgets/message.rs                 | 45 ++++++++++++-----
 fractal-gtk/src/widgets/message_menu.rs            |  8 ++--
 fractal-matrix-api/src/backend/media.rs            | 12 ++---
 fractal-matrix-api/src/backend/room.rs             | 35 +++++++-------
 fractal-matrix-api/src/backend/sync.rs             |  7 ++-
 fractal-matrix-api/src/backend/types.rs            |  8 ++--
 fractal-matrix-api/src/error.rs                    |  3 +-
 fractal-matrix-api/src/model/event.rs              |  4 +-
 fractal-matrix-api/src/model/message.rs            | 56 ++++++++++++++--------
 fractal-matrix-api/src/model/room.rs               | 18 +++----
 fractal-matrix-api/src/r0/context/get_context.rs   |  4 +-
 .../src/r0/message/create_message_event.rs         |  4 +-
 .../src/r0/read_marker/set_read_marker.rs          |  6 +--
 fractal-matrix-api/src/r0/redact/redact_event.rs   |  8 ++--
 fractal-matrix-api/src/util.rs                     |  4 +-
 22 files changed, 169 insertions(+), 136 deletions(-)
---
diff --git a/fractal-gtk/src/actions/global.rs b/fractal-gtk/src/actions/global.rs
index 0095d648..0d5b1315 100644
--- a/fractal-gtk/src/actions/global.rs
+++ b/fractal-gtk/src/actions/global.rs
@@ -8,7 +8,7 @@ use crate::appop::AppOp;
 use crate::i18n::i18n;
 use crate::widgets::FileDialog::open;
 use crate::App;
-use fractal_api::identifiers::RoomId;
+use fractal_api::identifiers::{EventId, RoomId};
 use fractal_api::types::Message;
 use gio::prelude::*;
 use gio::SimpleAction;
@@ -354,16 +354,16 @@ pub fn new(app: &gtk::Application, op: &Arc<Mutex<AppOp>>) {
     //op.lock().unwrap().mark_active_room_messages();
 }
 
-fn get_room_id(data: Option<&glib::Variant>) -> Option<RoomId> {
+pub fn get_room_id(data: Option<&glib::Variant>) -> Option<RoomId> {
     data?.get_str().and_then(|rid| rid.try_into().ok())
 }
 
-fn get_message(data: Option<&glib::Variant>) -> Option<Message> {
-    get_message_by_id(data.as_ref()?.get_str()?)
+pub fn get_event_id(data: Option<&glib::Variant>) -> Option<EventId> {
+    data?.get_str().and_then(|evid| evid.try_into().ok())
 }
 
-/* TODO: get message from stroage once implemented */
-fn get_message_by_id(id: &str) -> Option<Message> {
+/* TODO: get message from storage once implemented */
+pub fn get_message_by_id(id: &EventId) -> Option<Message> {
     let op = App::get_op()?;
     let op = op.lock().unwrap();
     let room_id = op.active_room.as_ref()?;
@@ -371,7 +371,7 @@ fn get_message_by_id(id: &str) -> Option<Message> {
 }
 
 fn open_viewer(data: Option<&glib::Variant>) -> Option<()> {
-    let msg = get_message(data)?;
+    let msg = get_event_id(data).as_ref().and_then(get_message_by_id)?;
     let op = App::get_op()?;
     let mut op = op.lock().unwrap();
     op.create_media_viewer(msg);
diff --git a/fractal-gtk/src/actions/message.rs b/fractal-gtk/src/actions/message.rs
index 29b5e224..b0174602 100644
--- a/fractal-gtk/src/actions/message.rs
+++ b/fractal-gtk/src/actions/message.rs
@@ -5,7 +5,6 @@ use fractal_api::r0::AccessToken;
 use fractal_api::util::{dw_media, ContentType, ResultExpectLog};
 use log::error;
 use std::cell::RefCell;
-use std::convert::TryFrom;
 use std::fs;
 use std::process::Command;
 use std::rc::Rc;
@@ -30,6 +29,8 @@ use glib::source::Continue;
 use gtk;
 use gtk::prelude::*;
 
+use super::global::{get_event_id, get_message_by_id, get_room_id};
+
 use crate::widgets::ErrorDialog;
 use crate::widgets::FileDialog::save;
 use crate::widgets::SourceDialog;
@@ -278,22 +279,8 @@ pub fn new(
     actions
 }
 
-fn get_message(data: Option<&glib::Variant>) -> Option<Message> {
-    get_message_by_id(data?.get_str()?)
-}
-
-/* TODO: get message from stroage once implemented */
-fn get_message_by_id(id: &str) -> Option<Message> {
-    let op = App::get_op()?;
-    let op = op.lock().unwrap();
-    let room_id = op.active_room.as_ref()?;
-    op.get_message_by_id(room_id, id)
-}
-
-fn get_room_id(data: Option<&glib::Variant>) -> Option<RoomId> {
-    data.as_ref()?
-        .get_str()
-        .and_then(|rid| RoomId::try_from(rid).ok())
+fn get_message(id: Option<&glib::Variant>) -> Option<Message> {
+    get_event_id(id).as_ref().and_then(get_message_by_id)
 }
 
 fn request_more_messages(
diff --git a/fractal-gtk/src/appop/message.rs b/fractal-gtk/src/appop/message.rs
index 8c290d3f..876b317d 100644
--- a/fractal-gtk/src/appop/message.rs
+++ b/fractal-gtk/src/appop/message.rs
@@ -1,6 +1,6 @@
 use comrak::{markdown_to_html, ComrakOptions};
 use fractal_api::backend::room;
-use fractal_api::identifiers::RoomId;
+use fractal_api::identifiers::{EventId, RoomId};
 use fractal_api::util::ResultExpectLog;
 use gdk_pixbuf::Pixbuf;
 use gio::prelude::FileExt;
@@ -34,12 +34,10 @@ pub struct TmpMsg {
 }
 
 impl AppOp {
-    pub fn get_message_by_id(&self, room_id: &RoomId, id: &str) -> Option<Message> {
+    pub fn get_message_by_id(&self, room_id: &RoomId, id: &EventId) -> Option<Message> {
         let room = self.rooms.get(room_id)?;
-        room.messages
-            .iter()
-            .find(|m| m.id == id.to_string())
-            .cloned()
+        let id = Some(id);
+        room.messages.iter().find(|m| m.id.as_ref() == id).cloned()
     }
 
     /// This function is used to mark as read the last message of a room when the focus comes in,
@@ -143,7 +141,7 @@ impl AppOp {
             last_message.receipt.insert(uid, 0);
 
             let room_id = last_message.room.clone();
-            let event_id = last_message.id.clone();
+            let event_id = last_message.id.clone()?;
             let tx = self.backend.clone();
             thread::spawn(move || {
                 match room::mark_as_read(
@@ -167,7 +165,7 @@ impl AppOp {
         None
     }
 
-    pub fn msg_sent(&mut self, _txid: String, evid: String) {
+    pub fn msg_sent(&mut self, _txid: String, evid: Option<EventId>) {
         if let Some(ref mut m) = self.msg_queue.pop() {
             if let Some(ref w) = m.widget {
                 w.destroy();
@@ -244,7 +242,7 @@ impl AppOp {
             if let Some(sender) = self.login_data.as_ref().map(|ld| ld.uid.clone()) {
                 let body = msg.clone();
                 let mtype = String::from("m.text");
-                let mut m = Message::new(room, sender, body, mtype);
+                let mut m = Message::new(room, sender, body, mtype, None);
 
                 if msg.starts_with("/me ") {
                     m.body = msg.trim_start_matches("/me ").to_owned();
@@ -313,7 +311,8 @@ impl AppOp {
                         .unwrap_or_default();
                     let path_string = path.to_str().unwrap_or_default();
 
-                    let mut m = Message::new(room, sender, body.to_string(), mtype.to_string());
+                    let mut m =
+                        Message::new(room, sender, body.to_string(), mtype.to_string(), None);
                     let info = match mtype {
                         "m.image" => get_image_media_info(path_string, mime.as_ref()),
                         "m.audio" => get_audio_video_media_info(path_string, mime.as_ref()),
@@ -377,8 +376,8 @@ impl AppOp {
                     .builder
                     .get_object("main_window")
                     .expect("Can't find main_window in ui file.");
-                if let Some(app) = window.get_application() {
-                    self.notify(app, &msg.room, &msg.id);
+                if let (Some(app), Some(event_id)) = (window.get_application(), msg.id.as_ref()) {
+                    self.notify(app, &msg.room, event_id);
                 }
             }
 
@@ -429,7 +428,7 @@ impl AppOp {
         }
     }
 
-    pub fn remove_message(&mut self, room_id: RoomId, id: String) -> Option<()> {
+    pub fn remove_message(&mut self, room_id: RoomId, id: EventId) -> Option<()> {
         let message = self.get_message_by_id(&room_id, &id);
 
         if let Some(msg) = message {
diff --git a/fractal-gtk/src/appop/notify.rs b/fractal-gtk/src/appop/notify.rs
index 7e870229..3dee055b 100644
--- a/fractal-gtk/src/appop/notify.rs
+++ b/fractal-gtk/src/appop/notify.rs
@@ -1,4 +1,4 @@
-use fractal_api::identifiers::RoomId;
+use fractal_api::identifiers::{EventId, RoomId};
 use gio::ApplicationExt;
 use gio::FileExt;
 use gio::Notification;
@@ -42,7 +42,7 @@ impl AppOp {
         inapp.set_reveal_child(false);
     }
 
-    pub fn notify(&self, app: gtk::Application, room_id: &RoomId, id: &str) -> Option<()> {
+    pub fn notify(&self, app: gtk::Application, room_id: &RoomId, id: &EventId) -> Option<()> {
         let server_url = self.login_data.clone()?.server_url;
         let msg = self.get_message_by_id(room_id, id)?;
         let r = self.rooms.get(room_id)?;
diff --git a/fractal-gtk/src/cache/state.rs b/fractal-gtk/src/cache/state.rs
index 61a7751e..95d69417 100644
--- a/fractal-gtk/src/cache/state.rs
+++ b/fractal-gtk/src/cache/state.rs
@@ -87,7 +87,15 @@ impl Model for AppRoom {
 
 impl Model for AppMsg {
     fn key(&self) -> String {
-        format!("msg:{}:{}", self.msg.room, self.msg.id)
+        format!(
+            "msg:{}:{}",
+            self.msg.room,
+            self.msg
+                .id
+                .as_ref()
+                .map(|evid| evid.to_string())
+                .unwrap_or_default(),
+        )
     }
 }
 
diff --git a/fractal-gtk/src/uitypes.rs b/fractal-gtk/src/uitypes.rs
index 549463f6..f73f15d1 100644
--- a/fractal-gtk/src/uitypes.rs
+++ b/fractal-gtk/src/uitypes.rs
@@ -2,14 +2,14 @@ use crate::types::Message;
 use crate::widgets;
 use chrono::prelude::DateTime;
 use chrono::prelude::Local;
-use fractal_api::identifiers::UserId;
+use fractal_api::identifiers::{EventId, UserId};
 
 /* MessageContent contains all data needed to display one row
  * therefore it should contain only one Message body with one format
  * To-Do: this should be moved to a file collecting all structs used in the UI */
 #[derive(Debug, Clone)]
 pub struct MessageContent {
-    pub id: String,
+    pub id: Option<EventId>,
     pub sender: UserId,
     pub sender_name: Option<String>,
     pub mtype: RowType,
diff --git a/fractal-gtk/src/widgets/media_viewer.rs b/fractal-gtk/src/widgets/media_viewer.rs
index b43c37ec..a0f8af7a 100644
--- a/fractal-gtk/src/widgets/media_viewer.rs
+++ b/fractal-gtk/src/widgets/media_viewer.rs
@@ -614,7 +614,8 @@ impl Data {
         };
         let admin = self.admins.get(&self.uid).map(|n| *n).unwrap_or_default();
         let redactable = admin != 0 || self.uid == msg.sender;
-        let menu = MessageMenu::new(msg.id.as_str(), &mtype, &redactable, None, None);
+        let event_id = msg.id.as_ref();
+        let menu = MessageMenu::new(event_id, &mtype, &redactable, None, None);
         let popover = &menu.get_popover();
         let menu_button = self
             .builder
@@ -1041,7 +1042,7 @@ fn load_more_media(data: Rc<RefCell<Data>>, builder: gtk::Builder, backend: Send
 
     let msg = data.borrow().media_list[data.borrow().current_media_index].clone();
     let roomid = msg.room.clone();
-    let first_media_id = Some(msg.id.clone());
+    let first_media_id = unwrap_or_unit_return!(msg.id.clone());
     let prev_batch = data.borrow().prev_batch.clone();
     let server_url = data.borrow().server_url.clone();
     let access_token = data.borrow().access_token.clone();
diff --git a/fractal-gtk/src/widgets/message.rs b/fractal-gtk/src/widgets/message.rs
index 95fce8f8..d691f5c1 100644
--- a/fractal-gtk/src/widgets/message.rs
+++ b/fractal-gtk/src/widgets/message.rs
@@ -412,7 +412,12 @@ impl MessageBox {
         );
         download_btn.set_tooltip_text(Some(i18n("Save").as_str()));
 
-        let data = glib::Variant::from(msg.id.as_str());
+        let evid = msg
+            .id
+            .as_ref()
+            .map(|evid| evid.to_string())
+            .unwrap_or_default();
+        let data = glib::Variant::from(evid);
         download_btn.set_action_target_value(Some(&data));
         download_btn.set_action_name(Some("message.save_as"));
 
@@ -463,7 +468,12 @@ impl MessageBox {
         play_button.get_style_context().add_class("osd");
         play_button.get_style_context().add_class("play-icon");
         play_button.get_style_context().add_class("flat");
-        let data = glib::Variant::from(msg.id.as_str());
+        let evid = msg
+            .id
+            .as_ref()
+            .map(|evid| evid.to_string())
+            .unwrap_or_default();
+        let data = glib::Variant::from(evid);
         play_button.set_action_name(Some("app.open-media-viewer"));
         play_button.set_action_target_value(Some(&data));
         overlay.add_overlay(&play_button);
@@ -486,9 +496,9 @@ impl MessageBox {
         });
         overlay.add_overlay(&menu_button);
 
-        let id = msg.id.clone();
+        let evid = msg.id.as_ref();
         let redactable = msg.redactable.clone();
-        let menu = MessageMenu::new(id.as_str(), &RowType::Video, &redactable, None, None);
+        let menu = MessageMenu::new(evid, &RowType::Video, &redactable, None, None);
         menu_button.set_popover(Some(&menu.get_popover()));
 
         bx.pack_start(&overlay, true, true, 0);
@@ -518,7 +528,13 @@ impl MessageBox {
         );
         download_btn.set_tooltip_text(Some(i18n("Save").as_str()));
 
-        let data = glib::Variant::from(msg.id.as_str());
+        let evid = msg
+            .id
+            .as_ref()
+            .map(|evid| evid.to_string())
+            .unwrap_or_default();
+
+        let data = glib::Variant::from(&evid);
         download_btn.set_action_target_value(Some(&data));
         download_btn.set_action_name(Some("message.save_as"));
 
@@ -528,7 +544,7 @@ impl MessageBox {
         );
         open_btn.set_tooltip_text(Some(i18n("Open").as_str()));
 
-        let data = glib::Variant::from(msg.id.as_str());
+        let data = glib::Variant::from(&evid);
         open_btn.set_action_target_value(Some(&data));
         open_btn.set_action_name(Some("message.open_with"));
 
@@ -609,7 +625,6 @@ impl MessageBox {
     }
 
     fn connect_right_click_menu(&self, msg: &Message, label: Option<&gtk::Label>) -> Option<()> {
-        let id = msg.id.clone();
         let mtype = msg.mtype.clone();
         let redactable = msg.redactable.clone();
         let eventbox_weak = self.eventbox.downgrade();
@@ -620,29 +635,37 @@ impl MessageBox {
         };
 
         let evbox = eventbox_weak.clone();
-        let i = id.clone();
+        let id = msg.id.clone();
         widget.connect_button_press_event(move |w, e| {
             if e.get_button() == 3 {
                 let eventbox = upgrade_weak!(evbox, gtk::Inhibit(false));
-                MessageMenu::new(i.as_str(), &mtype, &redactable, Some(&eventbox), Some(w));
+                MessageMenu::new(id.as_ref(), &mtype, &redactable, Some(&eventbox), Some(w));
                 Inhibit(true)
             } else {
                 Inhibit(false)
             }
         });
 
+        let id = msg.id.clone();
         let widget_weak = widget.downgrade();
         self.gesture.connect_pressed(move |_, _, _| {
             let eventbox = upgrade_weak!(eventbox_weak);
             let widget = upgrade_weak!(widget_weak);
 
-            MessageMenu::new(&id, &mtype, &redactable, Some(&eventbox), Some(&widget));
+            MessageMenu::new(
+                id.as_ref(),
+                &mtype,
+                &redactable,
+                Some(&eventbox),
+                Some(&widget),
+            );
         });
         None
     }
 
     fn connect_media_viewer(&self, msg: &Message) -> Option<()> {
-        let data = glib::Variant::from(msg.id.as_str());
+        let evid = msg.id.as_ref()?.to_string();
+        let data = glib::Variant::from(evid);
         self.row.set_action_name(Some("app.open-media-viewer"));
         self.row.set_action_target_value(Some(&data));
         None
diff --git a/fractal-gtk/src/widgets/message_menu.rs b/fractal-gtk/src/widgets/message_menu.rs
index c1daf642..f815d48e 100644
--- a/fractal-gtk/src/widgets/message_menu.rs
+++ b/fractal-gtk/src/widgets/message_menu.rs
@@ -1,3 +1,4 @@
+use fractal_api::identifiers::EventId;
 use gdk;
 use gdk::prelude::*;
 use gtk;
@@ -21,7 +22,7 @@ struct Widgets {
 }
 
 impl Widgets {
-    pub fn new(id: &str, mtype: &RowType, redactable: &bool) -> Widgets {
+    pub fn new(id: Option<&EventId>, mtype: &RowType, redactable: &bool) -> Widgets {
         let builder = gtk::Builder::new();
         builder
             .add_from_resource("/org/gnome/Fractal/ui/message_menu.ui")
@@ -81,7 +82,8 @@ impl Widgets {
         copy_image_button.set_visible(mtype == &RowType::Image);
         copy_text_button.set_visible(mtype != &RowType::Image && mtype != &RowType::Video);
 
-        let data = glib::Variant::from(id);
+        let evid = id.map(|evid| evid.to_string()).unwrap_or_default();
+        let data = glib::Variant::from(evid);
         reply_button.set_action_target_value(Some(&data));
         open_with_button.set_action_target_value(Some(&data));
         view_source_button.set_action_target_value(Some(&data));
@@ -122,7 +124,7 @@ pub struct MessageMenu {
 
 impl MessageMenu {
     pub fn new(
-        id: &str,
+        id: Option<&EventId>,
         mtype: &RowType,
         redactable: &bool,
         widget: Option<&gtk::EventBox>,
diff --git a/fractal-matrix-api/src/backend/media.rs b/fractal-matrix-api/src/backend/media.rs
index 6a624071..8966a932 100644
--- a/fractal-matrix-api/src/backend/media.rs
+++ b/fractal-matrix-api/src/backend/media.rs
@@ -1,7 +1,7 @@
 use crate::backend::types::Backend;
 use crate::error::Error;
 use crate::globals;
-use ruma_identifiers::RoomId;
+use ruma_identifiers::{EventId, RoomId};
 use std::sync::mpsc::Sender;
 use url::Url;
 
@@ -38,20 +38,14 @@ pub fn get_media_list_async(
     baseu: Url,
     access_token: AccessToken,
     room_id: RoomId,
-    first_media_id: Option<String>,
+    first_media_id: EventId,
     prev_batch: Option<String>,
     tx: Sender<(Vec<Message>, String)>,
 ) {
     bk.thread_pool.run(move || {
         let media_list = prev_batch
             // FIXME: This should never be an empty token
-            .or_else(|| {
-                if let Some(ref id) = first_media_id {
-                    get_prev_batch_from(baseu.clone(), access_token.clone(), &room_id, id).ok()
-                } else {
-                    None
-                }
-            })
+            .or_else(|| get_prev_batch_from(baseu.clone(), access_token.clone(), &room_id, 
&first_media_id).ok())
             .and_then(|from| {
                 get_room_media_list(
                     baseu,
diff --git a/fractal-matrix-api/src/backend/room.rs b/fractal-matrix-api/src/backend/room.rs
index cbe76b07..ff13e978 100644
--- a/fractal-matrix-api/src/backend/room.rs
+++ b/fractal-matrix-api/src/backend/room.rs
@@ -1,7 +1,7 @@
 use log::error;
 use serde_json::json;
 
-use ruma_identifiers::{Error as IdError, RoomId, RoomIdOrAliasId, UserId};
+use ruma_identifiers::{Error as IdError, EventId, RoomId, RoomIdOrAliasId, UserId};
 use std::fs;
 use url::Url;
 
@@ -210,9 +210,11 @@ pub fn get_room_messages_from_msg(
     room_id: RoomId,
     msg: Message,
 ) -> Result<(Vec<Message>, RoomId, Option<String>), Error> {
+    let event_id = msg.id.as_ref().ok_or(Error::BackendError)?;
+
     // first of all, we calculate the from param using the context api, then we call the
     // normal get_room_messages
-    let from = get_prev_batch_from(base.clone(), access_token.clone(), &room_id, &msg.id)?;
+    let from = get_prev_batch_from(base.clone(), access_token.clone(), &room_id, event_id)?;
 
     get_room_messages(base, access_token, room_id, from)
 }
@@ -221,7 +223,7 @@ pub fn send_msg(
     base: Url,
     access_token: AccessToken,
     msg: Message,
-) -> Result<(String, String), Error> {
+) -> Result<(String, Option<EventId>), Error> {
     let room_id: RoomId = msg.room.clone();
 
     let params = CreateMessageEventParameters { access_token };
@@ -251,7 +253,9 @@ pub fn send_msg(
         body[k] = v;
     }
 
-    create_message_event(base, &params, &body, &room_id, "m.room.message", &msg.id)
+    let txn_id = msg.get_txn_id();
+
+    create_message_event(base, &params, &body, &room_id, "m.room.message", &txn_id)
         .map_err::<Error, _>(Into::into)
         .and_then(|request| {
             let response = HTTP_CLIENT
@@ -259,10 +263,9 @@ pub fn send_msg(
                 .execute(request)?
                 .json::<CreateMessageEventResponse>()?;
 
-            let evid = response.event_id.unwrap_or_default();
-            Ok((msg.id.clone(), evid))
+            Ok((txn_id.clone(), response.event_id))
         })
-        .or(Err(Error::SendMsgError(msg.id)))
+        .or(Err(Error::SendMsgError(txn_id)))
 }
 
 pub fn send_typing(
@@ -284,9 +287,10 @@ pub fn redact_msg(
     base: Url,
     access_token: AccessToken,
     msg: Message,
-) -> Result<(String, String), Error> {
-    let room_id = msg.room.clone();
-    let txn_id = msg.id.clone();
+) -> Result<(EventId, Option<EventId>), Error> {
+    let room_id = &msg.room;
+    let txn_id = msg.get_txn_id();
+    let event_id = msg.id.clone().ok_or(Error::BackendError)?;
 
     let params = RedactEventParameters { access_token };
 
@@ -294,7 +298,7 @@ pub fn redact_msg(
         reason: "Deletion requested by the sender".into(),
     };
 
-    redact_event(base, &params, &body, &room_id, &msg.id, &txn_id)
+    redact_event(base, &params, &body, room_id, &event_id, &txn_id)
         .map_err::<Error, _>(Into::into)
         .and_then(|request| {
             let response = HTTP_CLIENT
@@ -302,10 +306,9 @@ pub fn redact_msg(
                 .execute(request)?
                 .json::<RedactEventResponse>()?;
 
-            let evid = response.event_id.unwrap_or_default();
-            Ok((msg.id.clone(), evid))
+            Ok((event_id.clone(), response.event_id))
         })
-        .or(Err(Error::SendMsgRedactionError(msg.id)))
+        .or(Err(Error::SendMsgRedactionError(event_id)))
 }
 
 pub fn join_room(bk: &Backend, base: Url, access_token: AccessToken, room_id: RoomId) {
@@ -350,8 +353,8 @@ pub fn mark_as_read(
     base: Url,
     access_token: AccessToken,
     room_id: RoomId,
-    event_id: String,
-) -> Result<(RoomId, String), Error> {
+    event_id: EventId,
+) -> Result<(RoomId, EventId), Error> {
     let params = SetReadMarkerParameters { access_token };
 
     let body = SetReadMarkerBody {
diff --git a/fractal-matrix-api/src/backend/sync.rs b/fractal-matrix-api/src/backend/sync.rs
index c3e63311..b9e901f7 100644
--- a/fractal-matrix-api/src/backend/sync.rs
+++ b/fractal-matrix-api/src/backend/sync.rs
@@ -27,7 +27,7 @@ use reqwest::blocking::Client;
 use ruma_identifiers::UserId;
 use serde_json::value::from_value;
 use std::{
-    convert::TryFrom,
+    convert::{TryFrom, TryInto},
     thread,
     time::{self, Duration},
 };
@@ -197,8 +197,7 @@ pub fn sync(
                                     content: ev["content"].clone(),
                                     redacts: ev["redacts"]
                                         .as_str()
-                                        .map(Into::into)
-                                        .unwrap_or_default(),
+                                        .and_then(|r| r.try_into().ok()),
                                     stype: ev["type"].as_str().map(Into::into).unwrap_or_default(),
                                     id: ev["id"].as_str().map(Into::into).unwrap_or_default(),
                                 })
@@ -235,7 +234,7 @@ pub fn sync(
                                 "m.room.redaction" => {
                                     let _ = tx.send(BKResponse::RemoveMessage(Ok((
                                         ev.room.clone(),
-                                        ev.redacts,
+                                        ev.redacts.expect("Events of type m.room.redaction should have a 
'redacts' field"),
                                     ))));
                                 }
                                 _ => {
diff --git a/fractal-matrix-api/src/backend/types.rs b/fractal-matrix-api/src/backend/types.rs
index 5afd588b..cc197500 100644
--- a/fractal-matrix-api/src/backend/types.rs
+++ b/fractal-matrix-api/src/backend/types.rs
@@ -1,4 +1,4 @@
-use ruma_identifiers::{RoomId, UserId};
+use ruma_identifiers::{EventId, RoomId, UserId};
 use std::collections::HashMap;
 use std::sync::mpsc::Sender;
 use std::sync::{Arc, Condvar, Mutex};
@@ -27,7 +27,7 @@ pub enum BKCommand {
         Url,
         AccessToken,
         RoomId,
-        Option<String>,
+        EventId,
         Option<String>,
         Sender<(Vec<Message>, String)>,
     ),
@@ -56,10 +56,10 @@ pub enum BKResponse {
     RoomMemberEvent(Event),
     RoomMessages(Result<Vec<Message>, Error>),
     RoomMessagesInit(Vec<Message>),
-    SentMsg(Result<(String, String), Error>),
+    SentMsg(Result<(String, Option<EventId>), Error>),
     DirectorySearch(Result<Vec<Room>, Error>),
     JoinRoom(Result<(), Error>),
-    RemoveMessage(Result<(RoomId, String), Error>),
+    RemoveMessage(Result<(RoomId, EventId), Error>),
     RoomName(RoomId, String),
     RoomTopic(RoomId, String),
     MediaUrl(Url),
diff --git a/fractal-matrix-api/src/error.rs b/fractal-matrix-api/src/error.rs
index 28826476..72622b69 100644
--- a/fractal-matrix-api/src/error.rs
+++ b/fractal-matrix-api/src/error.rs
@@ -1,4 +1,5 @@
 use glib;
+use ruma_identifiers::EventId;
 use std::io;
 use std::time::SystemTimeError;
 
@@ -31,7 +32,7 @@ pub enum Error {
     NetworkError(reqwest::StatusCode),
     MatrixError(MatrixErrorCode, String),
     SendMsgError(String),
-    SendMsgRedactionError(String),
+    SendMsgRedactionError(EventId),
     TokenUsed,
     Denied,
     NotLoggedIn,
diff --git a/fractal-matrix-api/src/model/event.rs b/fractal-matrix-api/src/model/event.rs
index 787f9be3..7de9d45f 100644
--- a/fractal-matrix-api/src/model/event.rs
+++ b/fractal-matrix-api/src/model/event.rs
@@ -1,4 +1,4 @@
-use ruma_identifiers::{RoomId, UserId};
+use ruma_identifiers::{EventId, RoomId, UserId};
 use serde_json::Value as JsonValue;
 
 #[derive(Debug, Clone)]
@@ -7,7 +7,7 @@ pub struct Event {
     pub stype: String,
     pub room: RoomId,
     pub id: String,
-    pub redacts: String,
+    pub redacts: Option<EventId>,
     pub content: JsonValue,
 }
 
diff --git a/fractal-matrix-api/src/model/message.rs b/fractal-matrix-api/src/model/message.rs
index 451713e0..fb3658e3 100644
--- a/fractal-matrix-api/src/model/message.rs
+++ b/fractal-matrix-api/src/model/message.rs
@@ -1,14 +1,14 @@
 use chrono::prelude::*;
 use chrono::DateTime;
 use chrono::TimeZone;
-use ruma_identifiers::{Error as IdError, RoomId, UserId};
+use ruma_identifiers::{Error as IdError, EventId, RoomId, UserId};
 use serde::{Deserialize, Serialize};
 use serde_json::Value as JsonValue;
 use std::cmp::Ordering;
 use std::collections::HashMap;
 use std::convert::TryInto;
 
-//FIXME make properties privat
+//FIXME make properties private
 #[derive(Debug, Clone, Serialize, Deserialize)]
 pub struct Message {
     pub sender: UserId,
@@ -18,14 +18,19 @@ pub struct Message {
     pub room: RoomId,
     pub thumb: Option<String>,
     pub url: Option<String>,
-    pub id: String,
+    // FIXME: This should be a required field but it is mandatory
+    // to do it this way because because this struct is used both
+    // for received messages and messages to send. At the moment
+    // of writing this, using two separate data structures for each
+    // use case is just too difficult.
+    pub id: Option<EventId>,
     pub formatted_body: Option<String>,
     pub format: Option<String>,
     pub source: Option<String>,
     pub receipt: HashMap<UserId, i64>, // This `HashMap` associates the user ID with a timestamp
     pub redacted: bool,
     // The event ID of the message this is in reply to.
-    pub in_reply_to: Option<String>,
+    pub in_reply_to: Option<EventId>,
     // This can be used for the client to add more values to the message on sending
     // for example for images attachment the "info" field can be attached as
     // Some(json!({"info": {"h": 296, "w": 296, "mimetype": "image/png", "orientation": 0, "size": 8796}});
@@ -33,13 +38,13 @@ pub struct Message {
 }
 
 impl PartialEq for Message {
-    fn eq(&self, other: &Message) -> bool {
+    fn eq(&self, other: &Self) -> bool {
         self.id == other.id
     }
 }
 
 impl PartialOrd for Message {
-    fn partial_cmp(&self, other: &Message) -> Option<Ordering> {
+    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
         if self == other {
             Some(Ordering::Equal)
         } else {
@@ -49,10 +54,16 @@ impl PartialOrd for Message {
 }
 
 impl Message {
-    pub fn new(room: RoomId, sender: UserId, body: String, mtype: String) -> Self {
+    pub fn new(
+        room: RoomId,
+        sender: UserId,
+        body: String,
+        mtype: String,
+        id: Option<EventId>,
+    ) -> Self {
         let date = Local::now();
         Message {
-            id: get_txn_id(&room, &body, &date.to_string()),
+            id,
             sender,
             mtype,
             body,
@@ -70,6 +81,17 @@ impl Message {
         }
     }
 
+    /// Generates an unique transaction id for this message
+    /// The txn_id is generated using the md5sum of a concatenation of the message room id, the
+    /// message body and the date.
+    ///
+    /// 
https://matrix.org/docs/spec/client_server/r0.3.0.html#put-matrix-client-r0-rooms-roomid-send-eventtype-txnid
+    pub fn get_txn_id(&self) -> String {
+        let msg_str = format!("{}{}{}", self.room, self.body, self.date);
+        let digest = md5::compute(msg_str.as_bytes());
+        format!("{:x}", digest)
+    }
+
     /// List all supported types. By default a message map a m.room.message event, but there's
     /// other events that we want to show in the message history so we map other event types to our
     /// Message struct, like stickers
@@ -103,7 +125,7 @@ impl Message {
         let timestamp = msg["origin_server_ts"].as_i64().unwrap_or_default() / 1000;
         let server_timestamp: DateTime<Local> = Local.timestamp(timestamp, 0);
 
-        let id = msg["event_id"].as_str().unwrap_or_default();
+        let id: EventId = msg["event_id"].as_str().unwrap_or_default().try_into()?;
         let type_ = msg["type"].as_str().unwrap_or_default();
 
         let redacted = msg["unsigned"].get("redacted_because") != None;
@@ -112,7 +134,9 @@ impl Message {
             sender,
             date: server_timestamp,
             room: room_id.clone(),
-            id: id.to_string(),
+            // It is mandatory for a message event to have
+            // an event_id field
+            id: Some(id),
             mtype: type_.to_string(),
             body: String::new(),
             url: None,
@@ -161,7 +185,7 @@ impl Message {
                 // https://matrix.org/docs/spec/client_server/r0.4.0.html#rich-replies
                 self.in_reply_to = c["m.relates_to"]["m.in_reply_to"]["event_id"]
                     .as_str()
-                    .map(String::from);
+                    .and_then(|evid| evid.try_into().ok());
             }
             _ => {}
         };
@@ -208,13 +232,3 @@ impl Message {
         self.receipt = receipt;
     }
 }
-/// Generates an unique transaction id for this message
-/// The txn_id is generated using the md5sum of a concatenation of the message room id, the
-/// message body and the date.
-
-/// 
https://matrix.org/docs/spec/client_server/r0.3.0.html#put-matrix-client-r0-rooms-roomid-send-eventtype-txnid
-pub fn get_txn_id(room: &RoomId, body: &str, date: &str) -> String {
-    let msg = format!("{}{}{}", room, body, date);
-    let digest = md5::compute(msg.as_bytes());
-    format!("{:x}", digest)
-}
diff --git a/fractal-matrix-api/src/model/room.rs b/fractal-matrix-api/src/model/room.rs
index f30d5368..3f72d7fa 100644
--- a/fractal-matrix-api/src/model/room.rs
+++ b/fractal-matrix-api/src/model/room.rs
@@ -8,7 +8,7 @@ use crate::r0::sync::sync_events::Response as SyncResponse;
 use crate::util::get_user_avatar;
 use crate::util::parse_m_direct;
 use log::{debug, info};
-use ruma_identifiers::{Error as IdError, RoomId, UserId};
+use ruma_identifiers::{Error as IdError, EventId, RoomId, UserId};
 use serde::{Deserialize, Serialize};
 use std::collections::{HashMap, HashSet};
 use std::convert::{TryFrom, TryInto};
@@ -191,8 +191,7 @@ impl Room {
             if let Some(ev) = dataevs
                 .into_iter()
                 .find(|x| x["type"] == "m.fully_read")
-                .and_then(|fread| fread["content"]["event_id"].as_str())
-                .map(ToOwned::to_owned)
+                .and_then(|fread| fread["content"]["event_id"].as_str()?.try_into().ok())
             {
                 r.add_receipt_from_fully_read(user_id.clone(), ev);
             }
@@ -278,12 +277,13 @@ impl Room {
     }
 
     pub fn add_receipt_from_json(&mut self, mut events: Vec<&JsonValue>) {
-        let receipts: HashMap<String, HashMap<UserId, i64>> = events
+        let receipts: HashMap<EventId, HashMap<UserId, i64>> = events
             .pop()
             .and_then(|ev| ev["content"].as_object())
             .into_iter()
             .flatten()
             .filter_map(|(mid, obj)| {
+                let event_id = mid.as_str().try_into().ok()?;
                 let receipts = obj["m.read"]
                     .as_object()?
                     .iter()
@@ -298,22 +298,24 @@ impl Room {
                     .collect::<Result<HashMap<UserId, i64>, IdError>>()
                     .ok()?;
 
-                Some((mid.to_string(), receipts))
+                Some((event_id, receipts))
             })
             .collect();
 
         for msg in self.messages.iter_mut() {
-            if let Some(r) = receipts.get(&msg.id) {
+            if let Some(r) = msg.id.as_ref().and_then(|evid| receipts.get(evid)) {
                 msg.set_receipt(r.clone());
             }
         }
     }
 
-    pub fn add_receipt_from_fully_read(&mut self, uid: UserId, evid: String) {
+    pub fn add_receipt_from_fully_read(&mut self, uid: UserId, event_id: EventId) {
+        let event_id = Some(event_id);
+
         let _ = self
             .messages
             .iter_mut()
-            .filter(|msg| msg.id == evid)
+            .filter(|msg| msg.id == event_id)
             .map(|msg| msg.receipt.insert(uid.clone(), 0));
     }
 }
diff --git a/fractal-matrix-api/src/r0/context/get_context.rs 
b/fractal-matrix-api/src/r0/context/get_context.rs
index f2fbcd4f..2d574032 100644
--- a/fractal-matrix-api/src/r0/context/get_context.rs
+++ b/fractal-matrix-api/src/r0/context/get_context.rs
@@ -5,7 +5,7 @@ use crate::r0::AccessToken;
 use reqwest::blocking::Client;
 use reqwest::blocking::Request;
 use reqwest::Error;
-use ruma_identifiers::RoomId;
+use ruma_identifiers::{EventId, RoomId};
 use serde::{Deserialize, Serialize};
 use serde_json::Value as JsonValue;
 use url::Url;
@@ -38,7 +38,7 @@ pub fn request(
     base: Url,
     params: &Parameters,
     room_id: &RoomId,
-    event_id: &str, // TODO: Use EventId
+    event_id: &EventId,
 ) -> Result<Request, Error> {
     let url = base
         .join(&format!(
diff --git a/fractal-matrix-api/src/r0/message/create_message_event.rs 
b/fractal-matrix-api/src/r0/message/create_message_event.rs
index e578329e..4e3c6b92 100644
--- a/fractal-matrix-api/src/r0/message/create_message_event.rs
+++ b/fractal-matrix-api/src/r0/message/create_message_event.rs
@@ -2,7 +2,7 @@ use crate::r0::AccessToken;
 use reqwest::blocking::Client;
 use reqwest::blocking::Request;
 use reqwest::Error;
-use ruma_identifiers::RoomId;
+use ruma_identifiers::{EventId, RoomId};
 use serde::{Deserialize, Serialize};
 use serde_json::Value as JsonValue;
 use url::Url;
@@ -14,7 +14,7 @@ pub struct Parameters {
 
 #[derive(Clone, Debug, Deserialize)]
 pub struct Response {
-    pub event_id: Option<String>,
+    pub event_id: Option<EventId>,
 }
 
 pub fn request(
diff --git a/fractal-matrix-api/src/r0/read_marker/set_read_marker.rs 
b/fractal-matrix-api/src/r0/read_marker/set_read_marker.rs
index b7e6c6ba..1cb4e217 100644
--- a/fractal-matrix-api/src/r0/read_marker/set_read_marker.rs
+++ b/fractal-matrix-api/src/r0/read_marker/set_read_marker.rs
@@ -2,7 +2,7 @@ use crate::r0::AccessToken;
 use reqwest::blocking::Client;
 use reqwest::blocking::Request;
 use reqwest::Error;
-use ruma_identifiers::RoomId;
+use ruma_identifiers::{EventId, RoomId};
 use serde::Serialize;
 use url::Url;
 
@@ -14,9 +14,9 @@ pub struct Parameters {
 #[derive(Clone, Debug, Serialize)]
 pub struct Body {
     #[serde(rename = "m.fully_read")]
-    pub fully_read: String, // TODO: Use EventId
+    pub fully_read: EventId,
     #[serde(rename = "m.read")]
-    pub read: Option<String>, // TODO: Use EventId
+    pub read: Option<EventId>,
 }
 
 pub fn request(
diff --git a/fractal-matrix-api/src/r0/redact/redact_event.rs 
b/fractal-matrix-api/src/r0/redact/redact_event.rs
index e8af4955..1d4c784d 100644
--- a/fractal-matrix-api/src/r0/redact/redact_event.rs
+++ b/fractal-matrix-api/src/r0/redact/redact_event.rs
@@ -2,7 +2,7 @@ use crate::r0::AccessToken;
 use reqwest::blocking::Client;
 use reqwest::blocking::Request;
 use reqwest::Error;
-use ruma_identifiers::RoomId;
+use ruma_identifiers::{EventId, RoomId};
 use serde::{Deserialize, Serialize};
 use url::Url;
 
@@ -19,7 +19,7 @@ pub struct Body {
 
 #[derive(Clone, Debug, Deserialize)]
 pub struct Response {
-    pub event_id: Option<String>,
+    pub event_id: Option<EventId>,
 }
 
 pub fn request(
@@ -27,13 +27,13 @@ pub fn request(
     params: &Parameters,
     body: &Body,
     room_id: &RoomId,
-    event_type: &str, // TODO: Use EventType
+    event_id: &EventId,
     txn_id: &str,
 ) -> Result<Request, Error> {
     let url = base
         .join(&format!(
             "_matrix/client/r0/rooms/{}/redact/{}/{}",
-            room_id, event_type, txn_id,
+            room_id, event_id, txn_id,
         ))
         .expect("Malformed URL in redact_event");
 
diff --git a/fractal-matrix-api/src/util.rs b/fractal-matrix-api/src/util.rs
index 68f2d0ac..07c1be00 100644
--- a/fractal-matrix-api/src/util.rs
+++ b/fractal-matrix-api/src/util.rs
@@ -6,7 +6,7 @@ use serde::de::DeserializeOwned;
 use serde_json::Value as JsonValue;
 
 use directories::ProjectDirs;
-use ruma_identifiers::{Error as IdError, RoomId, UserId};
+use ruma_identifiers::{Error as IdError, EventId, RoomId, UserId};
 use std::collections::HashMap;
 use std::convert::TryFrom;
 use std::io::Read;
@@ -116,7 +116,7 @@ pub fn get_prev_batch_from(
     base: Url,
     access_token: AccessToken,
     room_id: &RoomId,
-    event_id: &str,
+    event_id: &EventId,
 ) -> Result<String, Error> {
     let params = GetContextParameters {
         access_token,



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]