[fractal] API: Use UserId from ruma-identifiers for stronger validation
- From: Daniel Garcia Moreno <danigm src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [fractal] API: Use UserId from ruma-identifiers for stronger validation
- Date: Wed, 26 Feb 2020 07:12:15 +0000 (UTC)
commit 923748082d54ad6cf829f10f29e622fc1f1ee3dd
Author: Alejandro Domínguez <adomu net-c com>
Date: Fri Jan 17 15:54:27 2020 +0100
API: Use UserId from ruma-identifiers for stronger validation
The crate ruma-identifiers was updated to support
historical IDs, so it can be safely used now
fractal-gtk/src/actions/account_settings.rs | 3 +-
fractal-gtk/src/app/backend_loop.rs | 6 +-
fractal-gtk/src/appop/account.rs | 14 +-
fractal-gtk/src/appop/invite.rs | 4 +-
fractal-gtk/src/appop/login.rs | 3 +-
fractal-gtk/src/appop/member.rs | 41 +++---
fractal-gtk/src/appop/message.rs | 2 +-
fractal-gtk/src/appop/mod.rs | 4 +-
fractal-gtk/src/appop/room.rs | 15 +-
fractal-gtk/src/appop/user.rs | 12 +-
fractal-gtk/src/cache/mod.rs | 21 ++-
fractal-gtk/src/cache/state.rs | 3 +-
fractal-gtk/src/passwd.rs | 30 ++--
fractal-gtk/src/uitypes.rs | 3 +-
fractal-gtk/src/widgets/autocomplete.rs | 2 +-
fractal-gtk/src/widgets/avatar.rs | 18 +--
fractal-gtk/src/widgets/member.rs | 8 +-
fractal-gtk/src/widgets/members_list.rs | 31 ++--
fractal-gtk/src/widgets/message.rs | 20 +--
fractal-gtk/src/widgets/room_settings.rs | 38 ++---
fractal-matrix-api/src/backend/media.rs | 2 +-
fractal-matrix-api/src/backend/mod.rs | 8 +-
fractal-matrix-api/src/backend/register.rs | 11 +-
fractal-matrix-api/src/backend/room.rs | 130 +++++++++--------
fractal-matrix-api/src/backend/sync.rs | 98 +++++++------
fractal-matrix-api/src/backend/types.rs | 38 ++---
fractal-matrix-api/src/backend/user.rs | 31 ++--
fractal-matrix-api/src/cache.rs | 31 ++--
fractal-matrix-api/src/model/event.rs | 4 +-
fractal-matrix-api/src/model/member.rs | 24 ++-
fractal-matrix-api/src/model/message.rs | 24 +--
fractal-matrix-api/src/model/room.rs | 161 ++++++++++++---------
fractal-matrix-api/src/r0/account/login.rs | 3 +-
fractal-matrix-api/src/r0/account/register.rs | 3 +-
.../src/r0/membership/invite_user.rs | 4 +-
.../src/r0/profile/get_display_name.rs | 3 +-
fractal-matrix-api/src/r0/profile/get_profile.rs | 3 +-
.../src/r0/profile/set_avatar_url.rs | 3 +-
.../src/r0/profile/set_display_name.rs | 3 +-
fractal-matrix-api/src/r0/search/user.rs | 3 +-
.../src/r0/sync/get_joined_members.rs | 4 +-
fractal-matrix-api/src/r0/sync/sync_events.rs | 6 +-
fractal-matrix-api/src/r0/tag/create_tag.rs | 4 +-
fractal-matrix-api/src/r0/tag/delete_tag.rs | 4 +-
fractal-matrix-api/src/r0/typing.rs | 4 +-
fractal-matrix-api/src/util.rs | 28 ++--
46 files changed, 476 insertions(+), 439 deletions(-)
---
diff --git a/fractal-gtk/src/actions/account_settings.rs b/fractal-gtk/src/actions/account_settings.rs
index e37f07cf..468cb679 100644
--- a/fractal-gtk/src/actions/account_settings.rs
+++ b/fractal-gtk/src/actions/account_settings.rs
@@ -1,4 +1,5 @@
use crate::i18n::i18n;
+use fractal_api::identifiers::UserId;
use fractal_api::r0::AccessToken;
use fractal_api::url::Url;
use gio::prelude::*;
@@ -21,7 +22,7 @@ pub fn new(
backend: &Sender<BKCommand>,
server_url: Url,
access_token: AccessToken,
- uid: String,
+ uid: UserId,
) -> gio::SimpleActionGroup {
let actions = SimpleActionGroup::new();
// TODO create two stats loading interaction and connect it to the avatar box
diff --git a/fractal-gtk/src/app/backend_loop.rs b/fractal-gtk/src/app/backend_loop.rs
index 8627597f..c86494ac 100644
--- a/fractal-gtk/src/app/backend_loop.rs
+++ b/fractal-gtk/src/app/backend_loop.rs
@@ -93,7 +93,7 @@ pub fn backend_loop(rx: Receiver<BKResponse>) {
let s = Some(since);
APPOP!(synced, (s));
}
- BKResponse::Rooms(rooms, default) => {
+ BKResponse::Rooms(Ok((rooms, default))) => {
let clear_room_list = true;
APPOP!(set_rooms, (rooms, clear_room_list));
// Open the newly joined room
@@ -102,7 +102,7 @@ pub fn backend_loop(rx: Receiver<BKResponse>) {
APPOP!(set_active_room_by_id, (room_id));
}
}
- BKResponse::UpdateRooms(rooms) => {
+ BKResponse::UpdateRooms(Ok(rooms)) => {
let clear_room_list = false;
APPOP!(set_rooms, (rooms, clear_room_list));
}
@@ -116,7 +116,7 @@ pub fn backend_loop(rx: Receiver<BKResponse>) {
BKResponse::RoomMembers(Ok((room, members))) => {
APPOP!(set_room_members, (room, members));
}
- BKResponse::RoomMessages(msgs) => {
+ BKResponse::RoomMessages(Ok(msgs)) => {
APPOP!(show_room_messages, (msgs));
}
BKResponse::RoomMessagesTo(Ok((msgs, room, prev_batch))) => {
diff --git a/fractal-gtk/src/appop/account.rs b/fractal-gtk/src/appop/account.rs
index fafb3d5d..c5b102e8 100644
--- a/fractal-gtk/src/appop/account.rs
+++ b/fractal-gtk/src/appop/account.rs
@@ -289,7 +289,7 @@ impl AppOp {
stack.set_visible_child_name("loading");
self.get_three_pid();
- uid.set_text(&login_data.uid);
+ uid.set_text(&login_data.uid.to_string());
device_id.set_text(&self.device_id.clone().unwrap_or_default());
homeserver.set_text(login_data.server_url.as_str());
name.set_text(&login_data.username.unwrap_or_default());
@@ -502,7 +502,13 @@ impl AppOp {
let w = widgets::Avatar::avatar_new(Some(100));
avatar.add(&w);
- let data = w.circle(login_data.uid.clone(), login_data.username, 100, None, None);
+ let data = w.circle(
+ login_data.uid.to_string(),
+ login_data.username,
+ 100,
+ None,
+ None,
+ );
download_to_cache(
self.backend.clone(),
login_data.server_url,
@@ -635,7 +641,7 @@ impl AppOp {
let _ = self.backend.send(BKCommand::ChangePassword(
login_data.server_url,
login_data.access_token,
- login_data.uid,
+ login_data.uid.localpart().into(),
old.to_string(),
new.to_string(),
));
@@ -743,7 +749,7 @@ impl AppOp {
let _ = backend.send(BKCommand::AccountDestruction(
login_data.server_url.clone(),
login_data.access_token.clone(),
- login_data.uid.clone(),
+ login_data.uid.localpart().into(),
password.to_string(),
));
}
diff --git a/fractal-gtk/src/appop/invite.rs b/fractal-gtk/src/appop/invite.rs
index d1e467a4..43ae39a3 100644
--- a/fractal-gtk/src/appop/invite.rs
+++ b/fractal-gtk/src/appop/invite.rs
@@ -1,6 +1,6 @@
use crate::i18n::{i18n, i18n_k};
-use fractal_api::identifiers::RoomId;
+use fractal_api::identifiers::{RoomId, UserId};
use gtk;
use gtk::prelude::*;
@@ -80,7 +80,7 @@ impl AppOp {
}
}
- pub fn rm_from_invite(&mut self, uid: String) {
+ pub fn rm_from_invite(&mut self, uid: UserId) {
let idx = self.invite_list.iter().position(|x| x.0.uid == uid);
if let Some(i) = idx {
self.invite_list.remove(i);
diff --git a/fractal-gtk/src/appop/login.rs b/fractal-gtk/src/appop/login.rs
index 98394540..0050017d 100644
--- a/fractal-gtk/src/appop/login.rs
+++ b/fractal-gtk/src/appop/login.rs
@@ -1,5 +1,6 @@
use log::error;
+use fractal_api::identifiers::UserId;
use fractal_api::r0::AccessToken;
use fractal_api::url::Url;
@@ -25,7 +26,7 @@ use super::LoginData;
impl AppOp {
pub fn bk_login(
&mut self,
- uid: String,
+ uid: UserId,
access_token: AccessToken,
device: Option<String>,
server_url: Url,
diff --git a/fractal-gtk/src/appop/member.rs b/fractal-gtk/src/appop/member.rs
index c638337b..91104d67 100644
--- a/fractal-gtk/src/appop/member.rs
+++ b/fractal-gtk/src/appop/member.rs
@@ -1,9 +1,10 @@
use fractal_api::clone;
-use fractal_api::identifiers::RoomId;
+use fractal_api::identifiers::{RoomId, UserId};
use gtk;
use gtk::prelude::*;
use std::collections::HashMap;
+use std::convert::TryFrom;
use crate::actions::AppState;
use crate::appop::AppOp;
@@ -23,16 +24,11 @@ pub enum SearchType {
impl AppOp {
pub fn member_level(&self, member: &Member) -> i32 {
- if let Some(r) = self
- .active_room
+ self.active_room
.as_ref()
- .and_then(|a_room| self.rooms.get(a_room))
- {
- if let Some(level) = r.admins.get(&member.uid) {
- return *level;
- }
- }
- 0
+ .and_then(|a_room| self.rooms.get(a_room)?.admins.get(&member.uid))
+ .copied()
+ .unwrap_or(0)
}
pub fn set_room_members(&mut self, room_id: RoomId, members: Vec<Member>) {
@@ -55,10 +51,10 @@ impl AppOp {
// NOTE: maybe we should show this events in the message list to notify enters and leaves
// to the user
- let sender = ev.sender.clone();
+ let sender = ev.sender;
match ev.content["membership"].as_str() {
Some("leave") => {
- if let Some(r) = self.rooms.get_mut(&ev.room.clone()) {
+ if let Some(r) = self.rooms.get_mut(&ev.room) {
r.members.remove(&sender);
}
}
@@ -70,7 +66,7 @@ impl AppOp {
alias: Some(String::from(
ev.content["displayname"].as_str().unwrap_or_default(),
)),
- uid: sender.clone(),
+ uid: sender,
};
if let Some(r) = self.rooms.get_mut(&ev.room.clone()) {
r.members.insert(m.uid.clone(), m.clone());
@@ -160,16 +156,17 @@ impl AppOp {
}
scroll.hide();
- let t = term.unwrap_or_default();
- let uid_in_term = t.contains("@") && t.contains(":");
+ let uid_term = term.and_then(|t| UserId::try_from(t.as_str()).ok());
// Adding a new user if the user
- if uid_in_term && !users.iter().find(|u| u.uid == t).is_some() {
- let member = Member {
- avatar: None,
- alias: None,
- uid: t,
- };
- users.insert(0, member);
+ if let Some(uid) = uid_term {
+ if let None = users.iter().find(|u| u.uid == uid) {
+ let member = Member {
+ avatar: None,
+ alias: None,
+ uid,
+ };
+ users.insert(0, member);
+ }
}
for (i, u) in users.iter().enumerate() {
diff --git a/fractal-gtk/src/appop/message.rs b/fractal-gtk/src/appop/message.rs
index a56952a4..59a0671f 100644
--- a/fractal-gtk/src/appop/message.rs
+++ b/fractal-gtk/src/appop/message.rs
@@ -478,7 +478,7 @@ impl AppOp {
if let Some(user) = login_data.username {
highlights.push(user);
}
- highlights.push(login_data.uid.clone());
+ highlights.push(login_data.uid.to_string());
highlights.push(String::from("message_menu"));
RowType::Mention
diff --git a/fractal-gtk/src/appop/mod.rs b/fractal-gtk/src/appop/mod.rs
index 6fab3629..aa3e8cfe 100644
--- a/fractal-gtk/src/appop/mod.rs
+++ b/fractal-gtk/src/appop/mod.rs
@@ -3,7 +3,7 @@ use std::collections::HashMap;
use std::rc::Rc;
use std::sync::mpsc::Sender;
-use fractal_api::identifiers::RoomId;
+use fractal_api::identifiers::{RoomId, UserId};
use fractal_api::r0::AccessToken;
use gtk;
@@ -49,7 +49,7 @@ use self::message::TmpMsg;
#[derive(Clone, Debug)]
pub struct LoginData {
pub access_token: AccessToken,
- pub uid: String,
+ pub uid: UserId,
pub username: Option<String>,
pub avatar: Option<String>,
pub server_url: Url,
diff --git a/fractal-gtk/src/appop/room.rs b/fractal-gtk/src/appop/room.rs
index 3e146e54..eed2314f 100644
--- a/fractal-gtk/src/appop/room.rs
+++ b/fractal-gtk/src/appop/room.rs
@@ -173,14 +173,11 @@ impl AppOp {
.downcast::<gtk::Stack>()
.unwrap();
- let user_power = match room.admins.get(&login_data.uid) {
- Some(p) => *p,
- None => room
- .power_levels
- .get("users_default")
- .map(|x| *x)
- .unwrap_or(-1),
- };
+ let user_power = room
+ .admins
+ .get(&login_data.uid)
+ .copied()
+ .unwrap_or(room.default_power_level);
// No room admin information, assuming normal
if user_power >= 0 || room.admins.len() == 0 {
@@ -423,7 +420,7 @@ impl AppOp {
if *m != login_data.uid {
//FIXME: Find a better solution
// create a symlink from user avatar to room avatar (works only on unix)
- if let Ok(source) = cache_dir_path(None, m) {
+ if let Ok(source) = cache_dir_path(None, &m.to_string()) {
if let Ok(dest) = cache_dir_path(None, &room_id.to_string()) {
let _ = fs::symlink(source, dest);
}
diff --git a/fractal-gtk/src/appop/user.rs b/fractal-gtk/src/appop/user.rs
index 73398a6b..766bc332 100644
--- a/fractal-gtk/src/appop/user.rs
+++ b/fractal-gtk/src/appop/user.rs
@@ -53,7 +53,7 @@ impl AppOp {
.get_object::<gtk::Label>("user_info_uid")
.expect("Can't find user_info_avatar in ui file.");
- uid.set_text(&login_data.uid);
+ uid.set_text(&login_data.uid.to_string());
name.set_text(&login_data.username.clone().unwrap_or_default());
/* remove all old avatar from the popover */
@@ -63,7 +63,7 @@ impl AppOp {
let w = widgets::Avatar::avatar_new(Some(40));
let data = w.circle(
- login_data.uid.clone(),
+ login_data.uid.to_string(),
login_data.username.clone(),
40,
None,
@@ -86,7 +86,13 @@ impl AppOp {
match login_data.avatar.clone() {
Some(_) => {
let w = widgets::Avatar::avatar_new(Some(24));
- let data = w.circle(login_data.uid.clone(), login_data.username, 24, None, None);
+ let data = w.circle(
+ login_data.uid.to_string(),
+ login_data.username,
+ 24,
+ None,
+ None,
+ );
download_to_cache(
self.backend.clone(),
login_data.server_url.clone(),
diff --git a/fractal-gtk/src/cache/mod.rs b/fractal-gtk/src/cache/mod.rs
index 1bbc22f0..1238dd3a 100644
--- a/fractal-gtk/src/cache/mod.rs
+++ b/fractal-gtk/src/cache/mod.rs
@@ -6,6 +6,7 @@ use serde::{Deserialize, Serialize};
use crate::types::Room;
use crate::types::RoomList;
use failure::Error;
+use fractal_api::identifiers::UserId;
use std::collections::HashMap;
use crate::globals;
@@ -32,7 +33,7 @@ pub struct CacheData {
pub since: Option<String>,
pub rooms: RoomList,
pub username: String,
- pub uid: String,
+ pub uid: UserId,
pub device_id: String,
}
@@ -40,7 +41,7 @@ pub fn store(
rooms: &RoomList,
since: Option<String>,
username: String,
- uid: String,
+ uid: UserId,
device_id: String,
) -> Result<(), Error> {
// don't store all messages in the cache
@@ -100,15 +101,11 @@ pub fn load() -> Result<CacheData, Error> {
pub fn download_to_cache(
backend: Sender<BKCommand>,
server_url: Url,
- name: String,
+ uid: UserId,
data: Rc<RefCell<AvatarData>>,
) {
let (tx, rx) = channel::<(String, String)>();
- let _ = backend.send(BKCommand::GetUserInfoAsync(
- server_url,
- name.clone(),
- Some(tx),
- ));
+ let _ = backend.send(BKCommand::GetUserInfoAsync(server_url, uid, Some(tx)));
gtk::timeout_add(50, move || match rx.try_recv() {
Err(TryRecvError::Empty) => gtk::Continue(true),
@@ -124,13 +121,13 @@ pub fn download_to_cache(
pub fn download_to_cache_username(
backend: Sender<BKCommand>,
server_url: Url,
- uid: &str,
+ uid: UserId,
label: gtk::Label,
avatar: Option<Rc<RefCell<AvatarData>>>,
) {
let (tx, rx): (Sender<String>, Receiver<String>) = channel();
backend
- .send(BKCommand::GetUserNameAsync(server_url, uid.to_string(), tx))
+ .send(BKCommand::GetUserNameAsync(server_url, uid, tx))
.unwrap();
gtk::timeout_add(50, move || match rx.try_recv() {
Err(TryRecvError::Empty) => gtk::Continue(true),
@@ -152,14 +149,14 @@ pub fn download_to_cache_username(
pub fn download_to_cache_username_emote(
backend: Sender<BKCommand>,
server_url: Url,
- uid: &str,
+ uid: UserId,
text: &str,
label: gtk::Label,
avatar: Option<Rc<RefCell<AvatarData>>>,
) {
let (tx, rx): (Sender<String>, Receiver<String>) = channel();
backend
- .send(BKCommand::GetUserNameAsync(server_url, uid.to_string(), tx))
+ .send(BKCommand::GetUserNameAsync(server_url, uid, tx))
.unwrap();
let text = text.to_string();
gtk::timeout_add(50, move || match rx.try_recv() {
diff --git a/fractal-gtk/src/cache/state.rs b/fractal-gtk/src/cache/state.rs
index 2456c56c..61a7751e 100644
--- a/fractal-gtk/src/cache/state.rs
+++ b/fractal-gtk/src/cache/state.rs
@@ -13,6 +13,7 @@ use std::sync::{Arc, Mutex, MutexGuard};
use crate::types::Message;
use crate::types::Room;
+use fractal_api::identifiers::UserId;
use fractal_api::util::cache_dir_path;
// Models
@@ -24,7 +25,7 @@ use fractal_api::util::cache_dir_path;
pub struct AppState {
pub since: Option<String>,
pub username: String,
- pub uid: String,
+ pub uid: UserId,
pub device_id: String,
}
diff --git a/fractal-gtk/src/passwd.rs b/fractal-gtk/src/passwd.rs
index 0428e84b..eef37a29 100644
--- a/fractal-gtk/src/passwd.rs
+++ b/fractal-gtk/src/passwd.rs
@@ -1,4 +1,5 @@
use fractal_api::derror;
+use fractal_api::identifiers::{Error as IdError, UserId};
use fractal_api::r0::AccessToken;
use fractal_api::url::ParseError;
use fractal_api::url::Url;
@@ -8,6 +9,7 @@ use secret_service;
pub enum Error {
SecretServiceError,
UrlParseError(ParseError),
+ IdParseError(IdError),
}
impl From<ParseError> for Error {
@@ -16,6 +18,12 @@ impl From<ParseError> for Error {
}
}
+impl From<IdError> for Error {
+ fn from(err: IdError) -> Error {
+ Error::IdParseError(err)
+ }
+}
+
derror!(secret_service::SsError, Error::SecretServiceError);
pub trait PasswordStorage {
@@ -37,19 +45,21 @@ pub trait PasswordStorage {
ss_storage::get_pass()
}
- fn store_token(&self, uid: String, token: AccessToken) -> Result<(), Error> {
+ fn store_token(&self, uid: UserId, token: AccessToken) -> Result<(), Error> {
ss_storage::store_token(uid, token)
}
- fn get_token(&self) -> Result<(Option<AccessToken>, String), Error> {
+ fn get_token(&self) -> Result<(Option<AccessToken>, UserId), Error> {
ss_storage::get_token()
}
}
mod ss_storage {
use super::Error;
+ use fractal_api::identifiers::UserId;
use fractal_api::r0::AccessToken;
use fractal_api::url::Url;
+ use std::convert::TryFrom;
use super::secret_service::EncryptionType;
use super::secret_service::SecretService;
@@ -73,7 +83,7 @@ mod ss_storage {
Ok(())
}
- pub fn store_token(uid: String, token: AccessToken) -> Result<(), Error> {
+ pub fn store_token(uid: UserId, token: AccessToken) -> Result<(), Error> {
let ss = SecretService::new(EncryptionType::Dh)?;
let collection = ss.get_default_collection()?;
let key = "fractal-token";
@@ -84,17 +94,17 @@ mod ss_storage {
// create new item
collection.unlock()?;
collection.create_item(
- key, // label
- vec![("uid", &uid)], // properties
- token.to_string().as_bytes(), // secret
- true, // replace item with same attributes
- "text/plain", // secret content type
+ key, // label
+ vec![("uid", &uid.to_string())], // properties
+ token.to_string().as_bytes(), // secret
+ true, // replace item with same attributes
+ "text/plain", // secret content type
)?;
Ok(())
}
- pub fn get_token() -> Result<(Option<AccessToken>, String), Error> {
+ pub fn get_token() -> Result<(Option<AccessToken>, UserId), Error> {
let ss = SecretService::new(EncryptionType::Dh)?;
let collection = ss.get_default_collection()?;
let allpass = collection.get_all_items()?;
@@ -120,7 +130,7 @@ mod ss_storage {
.iter()
.find(|&ref x| x.0 == "uid")
.ok_or(Error::SecretServiceError)?;
- let uid = attr.1.clone();
+ let uid = UserId::try_from(attr.1.as_str())?;
Ok((token, uid))
}
diff --git a/fractal-gtk/src/uitypes.rs b/fractal-gtk/src/uitypes.rs
index 68089a48..549463f6 100644
--- a/fractal-gtk/src/uitypes.rs
+++ b/fractal-gtk/src/uitypes.rs
@@ -2,6 +2,7 @@ use crate::types::Message;
use crate::widgets;
use chrono::prelude::DateTime;
use chrono::prelude::Local;
+use fractal_api::identifiers::UserId;
/* MessageContent contains all data needed to display one row
* therefore it should contain only one Message body with one format
@@ -9,7 +10,7 @@ use chrono::prelude::Local;
#[derive(Debug, Clone)]
pub struct MessageContent {
pub id: String,
- pub sender: String,
+ pub sender: UserId,
pub sender_name: Option<String>,
pub mtype: RowType,
pub body: String,
diff --git a/fractal-gtk/src/widgets/autocomplete.rs b/fractal-gtk/src/widgets/autocomplete.rs
index 0406f425..2afa0cac 100644
--- a/fractal-gtk/src/widgets/autocomplete.rs
+++ b/fractal-gtk/src/widgets/autocomplete.rs
@@ -499,7 +499,7 @@ impl Autocomplete {
let mut count = 0;
for (_, m) in r.members.iter() {
let alias = &m.alias.clone().unwrap_or_default().to_lowercase();
- let uid = &m.uid.clone().to_lowercase()[1..];
+ let uid = m.uid.localpart().to_lowercase();
if alias.starts_with(&w) || uid.starts_with(&w) {
list.push(m.clone());
count = count + 1;
diff --git a/fractal-gtk/src/widgets/avatar.rs b/fractal-gtk/src/widgets/avatar.rs
index 4ab4d399..f188ec21 100644
--- a/fractal-gtk/src/widgets/avatar.rs
+++ b/fractal-gtk/src/widgets/avatar.rs
@@ -19,7 +19,7 @@ pub enum AvatarBadgeColor {
pub type Avatar = gtk::Overlay;
pub struct AvatarData {
- uid: String,
+ id: String,
username: Option<String>,
size: i32,
cache: Option<Pixbuf>,
@@ -31,13 +31,13 @@ impl AvatarData {
pub fn redraw_fallback(&mut self, username: Option<String>) {
self.username = username.clone();
/* This function should never fail */
- self.fallback = letter_avatar::generate::new(self.uid.clone(), username, self.size as f64)
+ self.fallback = letter_avatar::generate::new(self.id.clone(), username, self.size as f64)
.expect("this function should never fail");
self.widget.queue_draw();
}
pub fn redraw_pixbuf(&mut self) {
- let path = cache_dir_path(None, &self.uid).unwrap_or_default();
+ let path = cache_dir_path(None, self.id.as_str()).unwrap_or_default();
self.cache = load_pixbuf(&path, self.size);
self.widget.queue_draw();
}
@@ -49,7 +49,7 @@ pub trait AvatarExt {
fn create_da(&self, size: Option<i32>) -> DrawingArea;
fn circle(
&self,
- uid: String,
+ id: String,
username: Option<String>,
size: i32,
badge: Option<AvatarBadgeColor>,
@@ -84,14 +84,14 @@ impl AvatarExt for gtk::Overlay {
b
}
/// # Arguments
- /// * `uid` - Matrix ID
+ /// * `id` - User or Room ID
/// * `username` - Full name
/// * `size` - Size of the avatar
/// * `badge_color` - Badge color. None for no badge
/// * `badge_size` - Badge size. None for size / 3
fn circle(
&self,
- uid: String,
+ id: String,
username: Option<String>,
size: i32,
badge_color: Option<AvatarBadgeColor>,
@@ -99,7 +99,7 @@ impl AvatarExt for gtk::Overlay {
) -> Rc<RefCell<AvatarData>> {
self.clean();
let da = self.create_da(Some(size));
- let path = cache_dir_path(None, &uid).unwrap_or_default();
+ let path = cache_dir_path(None, id.as_str()).unwrap_or_default();
let user_avatar = load_pixbuf(&path, size);
let uname = username.clone();
/* remove IRC postfix from the username */
@@ -109,7 +109,7 @@ impl AvatarExt for gtk::Overlay {
None
};
/* This function should never fail */
- let fallback = letter_avatar::generate::new(uid.clone(), username, size as f64)
+ let fallback = letter_avatar::generate::new(id.clone(), username, size as f64)
.expect("this function should never fail");
// Power level badge setup
@@ -130,7 +130,7 @@ impl AvatarExt for gtk::Overlay {
}
let data = AvatarData {
- uid: uid.clone(),
+ id,
username: uname,
size: size,
cache: user_avatar,
diff --git a/fractal-gtk/src/widgets/member.rs b/fractal-gtk/src/widgets/member.rs
index 0d219f38..9d291d6e 100644
--- a/fractal-gtk/src/widgets/member.rs
+++ b/fractal-gtk/src/widgets/member.rs
@@ -32,7 +32,7 @@ impl<'a> MemberBox<'a> {
let w = gtk::Box::new(gtk::Orientation::Horizontal, 5);
let v = gtk::Box::new(gtk::Orientation::Vertical, 0);
- uid.set_text(&self.member.uid);
+ uid.set_text(&self.member.uid.to_string());
uid.set_valign(gtk::Align::Start);
uid.set_halign(gtk::Align::Start);
uid.get_style_context().add_class("member-uid");
@@ -40,7 +40,7 @@ impl<'a> MemberBox<'a> {
username.set_text(&self.member.get_alias());
let mut alias = self.member.get_alias();
alias.push_str("\n");
- alias.push_str(&self.member.uid);
+ alias.push_str(&self.member.uid.to_string());
username.set_tooltip_text(Some(&alias[..]));
username.set_margin_end(5);
username.set_ellipsize(pango::EllipsizeMode::End);
@@ -55,7 +55,7 @@ impl<'a> MemberBox<'a> {
_ => None,
};
let data = avatar.circle(
- self.member.uid.clone(),
+ self.member.uid.to_string(),
Some(alias.clone()),
globals::USERLIST_ICON_SIZE,
badge,
@@ -95,7 +95,7 @@ impl<'a> MemberBox<'a> {
let avatar = widgets::Avatar::avatar_new(Some(globals::PILL_ICON_SIZE));
let data = avatar.circle(
- self.member.uid.clone(),
+ self.member.uid.to_string(),
Some(self.member.get_alias()),
globals::PILL_ICON_SIZE,
None,
diff --git a/fractal-gtk/src/widgets/members_list.rs b/fractal-gtk/src/widgets/members_list.rs
index 78bf8253..c4f351b5 100644
--- a/fractal-gtk/src/widgets/members_list.rs
+++ b/fractal-gtk/src/widgets/members_list.rs
@@ -1,4 +1,5 @@
use fractal_api::clone;
+use fractal_api::identifiers::UserId;
use std::cell::RefCell;
use std::collections::hash_map::HashMap;
use std::rc::Rc;
@@ -18,24 +19,21 @@ pub struct MembersList {
search_entry: gtk::SearchEntry,
error: gtk::Label,
members: Vec<Member>,
- admins: HashMap<String, i32>,
- power_levels: HashMap<String, i32>,
+ admins: HashMap<UserId, i32>,
}
impl MembersList {
pub fn new(
- m: Vec<Member>,
- admins: HashMap<String, i32>,
- power_levels: HashMap<String, i32>,
- entry: gtk::SearchEntry,
+ members: Vec<Member>,
+ admins: HashMap<UserId, i32>,
+ search_entry: gtk::SearchEntry,
) -> MembersList {
MembersList {
container: gtk::ListBox::new(),
error: gtk::Label::new(None),
- members: m,
- search_entry: entry,
- admins: admins,
- power_levels: power_levels,
+ members,
+ search_entry,
+ admins,
}
}
@@ -61,7 +59,7 @@ impl MembersList {
/* removes the content of the row with index i */
#[allow(dead_code)]
- pub fn update(&self, uid: String) -> Option<()> {
+ pub fn update(&self, uid: UserId) -> Option<()> {
let mut index = None;
for (i, member) in self.members.iter().enumerate() {
if member.uid == uid {
@@ -147,7 +145,7 @@ fn load_row_content(member: Member, power_level: Option<i32>) -> gtk::Box {
// Avatar
let avatar = widgets::Avatar::avatar_new(Some(40));
avatar.circle(
- member.uid.clone(),
+ member.uid.to_string(),
member.alias.clone(),
40,
badge_color,
@@ -183,7 +181,7 @@ fn load_row_content(member: Member, power_level: Option<i32>) -> gtk::Box {
}
// matrix ID + power level
- let uid = gtk::Label::new(Some(member.uid.as_str()));
+ let uid = gtk::Label::new(Some(&member.uid.to_string()));
uid.set_xalign(0.);
uid.set_line_wrap(true);
uid.set_line_wrap_mode(pango::WrapMode::Char);
@@ -209,14 +207,11 @@ fn load_row_content(member: Member, power_level: Option<i32>) -> gtk::Box {
fn add_rows(
container: gtk::ListBox,
members: Vec<Member>,
- admins: HashMap<String, i32>,
+ admins: HashMap<UserId, i32>,
) -> Option<usize> {
/* Load just enough members to fill atleast the visible list */
for member in members.iter() {
- let admin = match admins.get(&member.uid) {
- Some(pl) => Some(*pl),
- None => None,
- };
+ let admin = admins.get(&member.uid).copied();
container.insert(&create_row(member.clone(), admin)?, -1);
}
None
diff --git a/fractal-gtk/src/widgets/message.rs b/fractal-gtk/src/widgets/message.rs
index b79f46b9..9df9b563 100644
--- a/fractal-gtk/src/widgets/message.rs
+++ b/fractal-gtk/src/widgets/message.rs
@@ -217,7 +217,7 @@ impl MessageBox {
let avatar = widgets::Avatar::avatar_new(Some(globals::MSG_ICON_SIZE));
let data = avatar.circle(
- uid.clone(),
+ uid.to_string(),
alias.clone(),
globals::MSG_ICON_SIZE,
None,
@@ -226,7 +226,7 @@ impl MessageBox {
if let Some(name) = alias {
self.username.set_text(&name);
} else {
- self.username.set_text(&uid);
+ self.username.set_text(&uid.to_string());
}
download_to_cache(
@@ -238,7 +238,7 @@ impl MessageBox {
download_to_cache_username(
self.backend.clone(),
self.server_url.clone(),
- &uid,
+ uid,
self.username.clone(),
Some(data.clone()),
);
@@ -246,9 +246,7 @@ impl MessageBox {
avatar
}
- fn build_room_msg_username(&self, sender: &str) -> gtk::Label {
- let uname = String::from(sender);
-
+ fn build_room_msg_username(&self, uname: String) -> gtk::Label {
self.username.set_text(&uname);
self.username.set_justify(gtk::Justification::Left);
self.username.set_halign(gtk::Align::Start);
@@ -581,7 +579,8 @@ impl MessageBox {
// +----------+------+
let info = gtk::Box::new(gtk::Orientation::Horizontal, 0);
- let username = self.build_room_msg_username(&msg.sender);
+ let username =
+ self.build_room_msg_username(msg.sender_name.clone().unwrap_or(msg.sender.to_string()));
let date = self.build_room_msg_date(&msg.date);
self.username_event_box.add(&username);
@@ -595,10 +594,7 @@ impl MessageBox {
fn build_room_msg_emote(&self, msg: &Message) -> gtk::Box {
let bx = gtk::Box::new(gtk::Orientation::Horizontal, 0);
/* Use MXID till we have a alias */
- let sname = msg
- .sender_name
- .clone()
- .unwrap_or(String::from(msg.sender.clone()));
+ let sname = msg.sender_name.clone().unwrap_or(msg.sender.to_string());
let msg_label = gtk::Label::new(None);
let body: &str = &msg.body;
let markup = markup_text(body);
@@ -606,7 +602,7 @@ impl MessageBox {
download_to_cache_username_emote(
self.backend.clone(),
self.server_url.clone(),
- &sname,
+ msg.sender.clone(),
&markup,
msg_label.clone(),
None,
diff --git a/fractal-gtk/src/widgets/room_settings.rs b/fractal-gtk/src/widgets/room_settings.rs
index 8f10f602..44c97ce4 100644
--- a/fractal-gtk/src/widgets/room_settings.rs
+++ b/fractal-gtk/src/widgets/room_settings.rs
@@ -1,4 +1,5 @@
use fractal_api::clone;
+use fractal_api::identifiers::UserId;
use fractal_api::r0::AccessToken;
use std::cell::RefCell;
use std::rc::Rc;
@@ -13,7 +14,6 @@ use gtk::prelude::*;
use crate::actions;
use crate::actions::{ButtonState, StateExt};
use crate::backend::BKCommand;
-use crate::cache::download_to_cache;
use crate::types::Member;
use crate::util::markup_text;
use crate::widgets;
@@ -25,7 +25,7 @@ use fractal_api::types::Room;
pub struct RoomSettings {
actions: gio::SimpleActionGroup,
room: Room,
- uid: String,
+ uid: UserId,
builder: gtk::Builder,
members_list: Option<MembersList>,
backend: Sender<BKCommand>,
@@ -37,7 +37,7 @@ impl RoomSettings {
pub fn new(
window: >k::Window,
backend: Sender<BKCommand>,
- uid: String,
+ uid: UserId,
room: Room,
server_url: Url,
access_token: AccessToken,
@@ -100,7 +100,7 @@ impl RoomSettings {
}
#[allow(dead_code)]
- pub fn update_members_list(&self, uid: String) -> Option<()> {
+ pub fn update_members_list(&self, uid: UserId) -> Option<()> {
self.members_list.clone()?.update(uid);
None
}
@@ -195,7 +195,7 @@ impl RoomSettings {
let mut is_room = true;
let mut is_group = false;
let members: Vec<Member> = self.room.members.values().cloned().collect();
- let power = *self.room.admins.get(&self.uid.clone()).unwrap_or(&0);
+ let power = self.room.admins.get(&self.uid).copied().unwrap_or(0);
let edit = power >= 50 && !self.room.direct;
@@ -203,6 +203,8 @@ impl RoomSettings {
is_room = false;
is_group = false;
self.get_direct_partner_uid(members.clone())
+ .as_ref()
+ .map(ToString::to_string)
} else {
/* we don't have private groups yet
let description = Some(format!("Private Group · {} members", members.len()));
@@ -231,7 +233,7 @@ impl RoomSettings {
}
/* returns the uid of the fisrt member in the room, ignoring the current user */
- fn get_direct_partner_uid(&self, members: Vec<Member>) -> Option<String> {
+ fn get_direct_partner_uid(&self, members: Vec<Member>) -> Option<UserId> {
members
.iter()
.map(|m| m.uid.clone())
@@ -410,7 +412,7 @@ impl RoomSettings {
None
}
- fn room_settings_show_avatar(&self, edit: bool) -> Option<()> {
+ fn room_settings_show_avatar(&self, edit: bool) {
let container = self
.builder
.get_object::<gtk::Box>("room_settings_avatar_box")
@@ -426,20 +428,19 @@ impl RoomSettings {
}
}
+ let _ = self.backend.send(BKCommand::GetRoomAvatar(
+ self.server_url.clone(),
+ self.access_token.clone(),
+ self.room.id.clone(),
+ ));
let image = widgets::Avatar::avatar_new(Some(100));
- let data = image.circle(
+ let _data = image.circle(
self.room.id.to_string(),
self.room.name.clone(),
100,
None,
None,
);
- download_to_cache(
- self.backend.clone(),
- self.server_url.clone(),
- self.room.id.to_string(),
- data,
- );
if edit {
let overlay = self
@@ -469,8 +470,6 @@ impl RoomSettings {
avatar_btn.hide();
container.add(&image);
}
-
- return None;
}
pub fn update_room_name(&mut self) -> Option<()> {
@@ -649,12 +648,7 @@ impl RoomSettings {
)
.as_str(),
);
- let list = widgets::MembersList::new(
- members.clone(),
- self.room.admins.clone(),
- self.room.power_levels.clone(),
- entry,
- );
+ let list = widgets::MembersList::new(members.clone(), self.room.admins.clone(), entry);
let w = list.create()?;
b.add(&w);
self.members_list = Some(list);
diff --git a/fractal-matrix-api/src/backend/media.rs b/fractal-matrix-api/src/backend/media.rs
index 83d3ce3c..835aa531 100644
--- a/fractal-matrix-api/src/backend/media.rs
+++ b/fractal-matrix-api/src/backend/media.rs
@@ -117,7 +117,7 @@ fn get_room_media_list(
}
let evs = array.unwrap().iter().rev();
- let media_list = Message::from_json_events_iter(room_id, evs);
+ let media_list = Message::from_json_events_iter(room_id, evs)?;
Ok((media_list, prev_batch))
}
diff --git a/fractal-matrix-api/src/backend/mod.rs b/fractal-matrix-api/src/backend/mod.rs
index 02aefcd9..0fc92df3 100644
--- a/fractal-matrix-api/src/backend/mod.rs
+++ b/fractal-matrix-api/src/backend/mod.rs
@@ -158,7 +158,7 @@ impl Backend {
Ok(BKCommand::ChangePassword(
server,
access_token,
- username,
+ user,
old_password,
new_password,
)) => {
@@ -166,7 +166,7 @@ impl Backend {
let query = user::change_password(
server,
access_token,
- username,
+ user,
old_password,
new_password,
);
@@ -174,9 +174,9 @@ impl Backend {
.expect_log("Connection closed");
});
}
- Ok(BKCommand::AccountDestruction(server, access_token, username, password)) => {
+ Ok(BKCommand::AccountDestruction(server, access_token, user, password)) => {
thread::spawn(move || {
- let query = user::account_destruction(server, access_token, username, password);
+ let query = user::account_destruction(server, access_token, user, password);
tx.send(BKResponse::AccountDestruction(query))
.expect_log("Connection closed");
});
diff --git a/fractal-matrix-api/src/backend/register.rs b/fractal-matrix-api/src/backend/register.rs
index a03b343c..8d50ea1f 100644
--- a/fractal-matrix-api/src/backend/register.rs
+++ b/fractal-matrix-api/src/backend/register.rs
@@ -52,9 +52,9 @@ pub fn guest(bk: &Backend, server: Url, id_url: Url) {
let dev = response.device_id;
if let Some(tk) = response.access_token {
- tx.send(BKResponse::Token(uid, tk, dev, server, id_url)) // TODO: Use UserId and
DeviceId
+ tx.send(BKResponse::Token(uid, tk, dev, server, id_url)) // TODO: Use DeviceId
.expect_log("Connection closed");
- tx.send(BKResponse::Rooms(vec![], None))
+ tx.send(BKResponse::Rooms(Ok((vec![], None))))
.expect_log("Connection closed");
} else {
tx.send(BKResponse::GuestLoginError(Error::BackendError))
@@ -104,11 +104,10 @@ pub fn login(bk: &Backend, user: String, password: String, server: Url, id_url:
match query {
Ok(response) => {
- let uid = response.user_id.unwrap_or(user);
let dev = response.device_id;
- if let (Some(tk), false) = (response.access_token, uid.is_empty()) {
- tx.send(BKResponse::Token(uid, tk, dev, server, id_url)) // TODO: Use UserId and
DeviceId
+ if let (Some(tk), Some(uid)) = (response.access_token, response.user_id) {
+ tx.send(BKResponse::Token(uid, tk, dev, server, id_url)) // TODO: Use DeviceId
.expect_log("Connection closed");
} else {
tx.send(BKResponse::LoginError(Error::BackendError))
@@ -164,7 +163,7 @@ pub fn register(bk: &Backend, user: String, password: String, server: Url, id_ur
let dev = response.device_id;
if let Some(tk) = response.access_token {
- tx.send(BKResponse::Token(uid, tk, dev, server, id_url)) // TODO: Use UserId
+ tx.send(BKResponse::Token(uid, tk, dev, server, id_url)) // TODO: Use DeviceId
.expect_log("Connection closed");
}
}
diff --git a/fractal-matrix-api/src/backend/room.rs b/fractal-matrix-api/src/backend/room.rs
index d031afe3..0c9004b0 100644
--- a/fractal-matrix-api/src/backend/room.rs
+++ b/fractal-matrix-api/src/backend/room.rs
@@ -1,8 +1,7 @@
use log::error;
use serde_json::json;
-use ruma_identifiers::RoomId;
-use ruma_identifiers::RoomIdOrAliasId;
+use ruma_identifiers::{Error as IdError, RoomId, RoomIdOrAliasId, UserId};
use std::fs;
use std::sync::mpsc::Sender;
use url::Url;
@@ -220,9 +219,12 @@ pub fn get_room_messages(
|r: JsonValue| {
let array = r["chunk"].as_array();
let evs = array.unwrap().iter().rev();
- let list = Message::from_json_events_iter(&room_id, evs);
let prev_batch = r["end"].as_str().map(String::from);
- tx.send(BKResponse::RoomMessagesTo(Ok((list, room_id, prev_batch))))
+ let query = Message::from_json_events_iter(&room_id, evs)
+ .map(|list| (list, room_id, prev_batch))
+ .map_err(Into::into);
+
+ tx.send(BKResponse::RoomMessagesTo(query))
.expect_log("Connection closed");
},
|err| {
@@ -277,32 +279,38 @@ fn parse_context(
|r: JsonValue| {
let mut id: Option<String> = None;
- let mut ms: Vec<Message> = vec![];
- let array = r["events_before"].as_array();
- for msg in array.unwrap().iter().rev() {
- if id.is_none() {
- id = Some(msg["event_id"].as_str().unwrap_or_default().to_string());
+ let ms: Result<Vec<Message>, _> = r["events_before"]
+ .as_array()
+ .into_iter()
+ .flatten()
+ .rev()
+ .inspect(|msg| {
+ if id.is_none() {
+ id = Some(msg["event_id"].as_str().unwrap_or_default().to_string());
+ }
+ })
+ .filter(|msg| Message::supported_event(&&msg))
+ .map(|msg| Message::parse_room_message(&room_id, msg))
+ .collect();
+
+ match ms {
+ Ok(msgs) if msgs.is_empty() && id.is_some() => {
+ // there's no messages so we'll try with a bigger context
+ if let Err(err) =
+ parse_context(tx.clone(), tk, baseu, room_id, &id.unwrap(), limit * 2)
+ {
+ tx.send(BKResponse::RoomMessagesTo(Err(err)))
+ .expect_log("Connection closed");
+ }
}
-
- if !Message::supported_event(&&msg) {
- continue;
+ Ok(msgs) => {
+ tx.send(BKResponse::RoomMessagesTo(Ok((msgs, room_id, None))))
+ .expect_log("Connection closed");
}
-
- let m = Message::parse_room_message(&room_id, msg);
- ms.push(m);
- }
-
- if ms.is_empty() && id.is_some() {
- // there's no messages so we'll try with a bigger context
- if let Err(err) =
- parse_context(tx.clone(), tk, baseu, room_id, &id.unwrap(), limit * 2)
- {
- tx.send(BKResponse::RoomMessagesTo(Err(err)))
+ Err(err) => {
+ tx.send(BKResponse::RoomMessagesTo(Err(err.into())))
.expect_log("Connection closed");
}
- } else {
- tx.send(BKResponse::RoomMessagesTo(Ok((ms, room_id, None))))
- .expect_log("Connection closed");
}
},
|err| {
@@ -386,13 +394,13 @@ pub fn send_msg(
pub fn send_typing(
base: Url,
access_token: AccessToken,
- userid: String,
+ user_id: UserId,
room_id: RoomId,
) -> Result<(), Error> {
let params = TypingNotificationParameters { access_token };
let body = TypingNotificationBody::Typing(Duration::from_secs(4));
- send_typing_notification(base, &room_id, &userid, ¶ms, &body)
+ send_typing_notification(base, &room_id, &user_id, ¶ms, &body)
.map_err(Into::into)
.and_then(|request| {
HTTP_CLIENT
@@ -775,34 +783,36 @@ pub fn new_room(
Ok(())
}
-pub fn update_direct_chats(url: Url, data: Arc<Mutex<BackendData>>, user: String, room_id: RoomId) {
+fn update_direct_chats(url: Url, data: Arc<Mutex<BackendData>>, user_id: UserId, room_id: RoomId) {
get!(
url.clone(),
|r: JsonValue| {
- let mut directs: HashMap<String, Vec<String>> = HashMap::new();
- let direct_obj = r.as_object().unwrap();
-
- direct_obj.iter().for_each(|(userid, rooms)| {
- let roomlist: Vec<String> = rooms
- .as_array()
- .unwrap()
- .iter()
- .map(|x| x.as_str().unwrap().to_string())
- .collect();
- directs.insert(userid.clone(), roomlist);
- });
-
- if directs.contains_key(&user) {
- if let Some(v) = directs.get_mut(&user) {
- v.push(room_id.to_string())
- };
- } else {
- directs.insert(user, vec![room_id.to_string()]);
- }
- data.lock().unwrap().m_direct = directs.clone();
+ let directs: Result<HashMap<UserId, Vec<RoomId>>, IdError> = r
+ .as_object()
+ .into_iter()
+ .flatten()
+ .map(|(uid, rooms)| {
+ let roomlist = rooms
+ .as_array()
+ .unwrap()
+ .iter()
+ .map(|x| RoomId::try_from(x.as_str().unwrap_or_default()))
+ .collect::<Result<Vec<RoomId>, IdError>>()?;
+ Ok((UserId::try_from(uid.as_str())?, roomlist))
+ })
+ .collect();
+
+ if let Ok(mut directs) = directs {
+ if let Some(v) = directs.get_mut(&user_id) {
+ v.push(room_id);
+ } else {
+ directs.insert(user_id, vec![room_id]);
+ }
+ data.lock().unwrap().m_direct = directs.clone();
- let attrs = json!(directs.clone());
- put!(url, &attrs, |_| {}, |err| error!("{:?}", err));
+ let attrs = json!(directs);
+ put!(url, &attrs, |_| {}, |err| error!("{:?}", err));
+ }
},
|err| {
error!("Can't set m.direct: {:?}", err);
@@ -814,7 +824,7 @@ pub fn direct_chat(
bk: &Backend,
base: Url,
access_token: AccessToken,
- userid: String,
+ user_id: UserId,
user: Member,
internal_id: RoomId,
) -> Result<(), Error> {
@@ -836,7 +846,7 @@ pub fn direct_chat(
let direct_url = bk.url(
base,
&access_token,
- &format!("user/{}/account_data/m.direct", userid),
+ &format!("user/{}/account_data/m.direct", user_id),
vec![],
)?;
@@ -877,17 +887,17 @@ pub fn direct_chat(
pub fn add_to_fav(
base: Url,
access_token: AccessToken,
- userid: String,
+ user_id: UserId,
room_id: RoomId,
tofav: bool,
) -> Result<(RoomId, bool), Error> {
let request_res = if tofav {
let params = CreateTagParameters { access_token };
let body = CreateTagBody { order: Some(0.5) };
- create_tag(base, &userid, &room_id, "m.favourite", ¶ms, &body)
+ create_tag(base, &user_id, &room_id, "m.favourite", ¶ms, &body)
} else {
let params = DeleteTagParameters { access_token };
- delete_tag(base, &userid, &room_id, "m.favourite", ¶ms)
+ delete_tag(base, &user_id, &room_id, "m.favourite", ¶ms)
};
request_res
@@ -905,7 +915,7 @@ pub fn invite(
base: Url,
access_token: AccessToken,
room_id: RoomId,
- user_id: String,
+ user_id: UserId,
) -> Result<(), Error> {
let params = InviteUserParameters { access_token };
let body = InviteUserBody { user_id };
@@ -925,7 +935,7 @@ pub fn set_language(
bk: &Backend,
access_token: AccessToken,
server: Url,
- userid: String,
+ user_id: UserId,
room_id: RoomId,
input_language: String,
) -> Result<(), Error> {
@@ -934,7 +944,7 @@ pub fn set_language(
&access_token,
&format!(
"user/{}/rooms/{}/account_data/org.gnome.fractal.language",
- userid, room_id,
+ user_id, room_id,
),
vec![],
)?;
diff --git a/fractal-matrix-api/src/backend/sync.rs b/fractal-matrix-api/src/backend/sync.rs
index 99625106..27120bd3 100644
--- a/fractal-matrix-api/src/backend/sync.rs
+++ b/fractal-matrix-api/src/backend/sync.rs
@@ -23,8 +23,10 @@ use crate::util::ResultExpectLog;
use log::error;
use reqwest::Client;
+use ruma_identifiers::UserId;
use serde_json::value::from_value;
use std::{
+ convert::TryFrom,
thread,
time::{self, Duration},
};
@@ -34,7 +36,7 @@ pub fn sync(
bk: &Backend,
base: Url,
access_token: AccessToken,
- userid: String,
+ user_id: UserId,
since: Option<String>,
initial: bool,
) {
@@ -111,18 +113,22 @@ pub fn sync(
let join = &response.rooms.join;
// New rooms
- let rs = Room::from_sync_response(&response, &userid, &base);
+ let rs = Room::from_sync_response(&response, user_id.clone(), &base)
+ .map_err(Into::into);
tx.send(BKResponse::UpdateRooms(rs))
.expect_log("Connection closed");
// Message events
let msgs = join
.iter()
- .flat_map(|(k, room)| {
+ .try_fold(Vec::new(), |mut acum, (k, room)| {
let events = room.timeline.events.iter();
- Message::from_json_events_iter(&k, events).into_iter()
+ Message::from_json_events_iter(&k, events).map(|msgs| {
+ acum.extend(msgs);
+ acum
+ })
})
- .collect();
+ .map_err(Into::into);
tx.send(BKResponse::RoomMessages(msgs))
.expect_log("Connection closed");
@@ -141,34 +147,34 @@ pub fn sync(
.iter()
.map(|(k, room)| {
let ephemerals = &room.ephemeral.events;
- let mut typing_room: Room =
- Room::new(k.clone(), RoomMembership::Joined(RoomTag::None));
- let mut typing: Vec<Member> = Vec::new();
- for event in ephemerals.iter() {
- if let Some(typing_users) = event
- .get("content")
- .and_then(|x| x.get("user_ids"))
- .and_then(|x| x.as_array())
- {
- for user in typing_users {
- let user: String = from_value(user.to_owned()).unwrap();
- // ignoring the user typing notifications
- if user == userid {
- continue;
- }
- typing.push(Member {
- uid: user,
- alias: None,
- avatar: None,
- });
+ let typing: Vec<Member> = ephemerals.iter()
+ .flat_map(|event| {
+ event
+ .get("content")
+ .and_then(|x| x.get("user_ids"))
+ .and_then(|x| x.as_array())
+ .unwrap_or(&vec![])
+ .to_owned()
+ })
+ .filter_map(|user| from_value(user).ok())
+ // ignoring the user typing notifications
+ .filter(|user| *user != user_id)
+ .map(|uid| {
+ Member {
+ uid,
+ alias: None,
+ avatar: None,
}
- }
+ })
+ .collect();
+
+ Room {
+ typing_users: typing,
+ ..Room::new(k.clone(), RoomMembership::Joined(RoomTag::None))
}
- typing_room.typing_users = typing;
- typing_room
})
.collect();
- tx.send(BKResponse::UpdateRooms(rooms))
+ tx.send(BKResponse::UpdateRooms(Ok(rooms)))
.expect_log("Connection closed");
// Other events
@@ -180,10 +186,13 @@ pub fn sync(
.filter(|x| x["type"] != "m.room.message")
.map(move |ev| Event {
room: k.clone(),
- sender: ev["sender"]
- .as_str()
- .map(Into::into)
- .unwrap_or_default(),
+ sender: UserId::try_from(
+ ev["sender"].as_str().unwrap_or_default(),
+ )
+ .unwrap(),
+ // TODO: Correct error management is too hard here,
+ // needs refactoring, but this workaround
+ // is enough
content: ev["content"].clone(),
redacts: ev["redacts"]
.as_str()
@@ -234,16 +243,21 @@ pub fn sync(
}
});
} else {
- data.lock().unwrap().m_direct = parse_m_direct(&response.account_data.events);
+ if let Ok(m_direct) = parse_m_direct(&response.account_data.events) {
+ data.lock().unwrap().m_direct = m_direct;
+ }
- let rooms = Room::from_sync_response(&response, &userid, &base);
- let def = data
- .lock()
- .unwrap()
- .join_to_room
- .as_ref()
- .and_then(|jtr| rooms.iter().find(|x| x.id == *jtr).cloned());
- tx.send(BKResponse::Rooms(rooms, def))
+ let rooms_def =
+ Room::from_sync_response(&response, user_id, &base)
+ .map(|rooms| {
+ let def =
+ data.lock().unwrap().join_to_room.as_ref().and_then(|jtr| {
+ rooms.iter().find(|x| x.id == *jtr).cloned()
+ });
+ (rooms, def)
+ })
+ .map_err(Into::into);
+ tx.send(BKResponse::Rooms(rooms_def))
.expect_log("Connection closed");
}
diff --git a/fractal-matrix-api/src/backend/types.rs b/fractal-matrix-api/src/backend/types.rs
index a66cfe45..9297b708 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;
+use ruma_identifiers::{RoomId, UserId};
use std::collections::HashMap;
use std::sync::mpsc::Sender;
use std::sync::{Arc, Condvar, Mutex};
@@ -25,8 +25,8 @@ pub enum BKCommand {
Register(String, String, Url, Url),
#[allow(dead_code)]
Guest(Url, Url),
- GetUsername(Url, String),
- SetUserName(Url, AccessToken, String, String),
+ GetUsername(Url, UserId),
+ SetUserName(Url, AccessToken, UserId, String),
GetThreePID(Url, AccessToken),
GetTokenEmail(Url, AccessToken, Url, String, String),
GetTokenPhone(Url, AccessToken, Url, String, String),
@@ -35,9 +35,9 @@ pub enum BKCommand {
DeleteThreePID(Url, AccessToken, Medium, String),
ChangePassword(Url, AccessToken, String, String, String),
AccountDestruction(Url, AccessToken, String, String),
- GetAvatar(Url, String),
- SetUserAvatar(Url, AccessToken, String, String),
- Sync(Url, AccessToken, String, Option<String>, bool),
+ GetAvatar(Url, UserId),
+ SetUserAvatar(Url, AccessToken, UserId, String),
+ Sync(Url, AccessToken, UserId, Option<String>, bool),
GetRoomMembers(Url, AccessToken, RoomId),
GetRoomMessages(Url, AccessToken, RoomId, String),
GetRoomMessagesFromMsg(Url, AccessToken, RoomId, Message),
@@ -56,11 +56,11 @@ pub enum BKCommand {
GetFileAsync(Url, Sender<String>),
GetAvatarAsync(Url, Option<Member>, Sender<String>),
GetMedia(Url, String),
- GetUserInfoAsync(Url, String, Option<Sender<(String, String)>>),
- GetUserNameAsync(Url, String, Sender<String>),
+ GetUserInfoAsync(Url, UserId, Option<Sender<(String, String)>>),
+ GetUserNameAsync(Url, UserId, Sender<String>),
SendMsg(Url, AccessToken, Message),
SendMsgRedaction(Url, AccessToken, Message),
- SendTyping(Url, AccessToken, String, RoomId),
+ SendTyping(Url, AccessToken, UserId, RoomId),
SetRoom(Url, AccessToken, RoomId),
ShutDown,
DirectoryProtocols(Url, AccessToken),
@@ -73,20 +73,20 @@ pub enum BKCommand {
SetRoomAvatar(Url, AccessToken, RoomId, String),
AttachFile(Url, AccessToken, Message),
NewRoom(Url, AccessToken, String, RoomType, RoomId),
- DirectChat(Url, AccessToken, String, Member, RoomId),
- AddToFav(Url, AccessToken, String, RoomId, bool),
+ DirectChat(Url, AccessToken, UserId, Member, RoomId),
+ AddToFav(Url, AccessToken, UserId, RoomId, bool),
AcceptInv(Url, AccessToken, RoomId),
RejectInv(Url, AccessToken, RoomId),
UserSearch(Url, AccessToken, String),
- Invite(Url, AccessToken, RoomId, String),
- ChangeLanguage(AccessToken, Url, String, RoomId, String),
+ Invite(Url, AccessToken, RoomId, UserId),
+ ChangeLanguage(AccessToken, Url, UserId, RoomId, String),
SendBKResponse(BKResponse),
}
#[derive(Debug)]
pub enum BKResponse {
ShutDown,
- Token(String, AccessToken, Option<String>, Url, Url),
+ Token(UserId, AccessToken, Option<String>, Url, Url),
Logout(Result<(), Error>),
Name(Result<Option<String>, Error>),
SetUserName(Result<String, Error>),
@@ -101,13 +101,13 @@ pub enum BKResponse {
Avatar(Result<String, Error>),
SetUserAvatar(Result<String, Error>),
Sync(Result<String, Error>),
- Rooms(Vec<Room>, Option<Room>),
- UpdateRooms(Vec<Room>),
+ Rooms(Result<(Vec<Room>, Option<Room>), Error>),
+ UpdateRooms(Result<Vec<Room>, Error>),
RoomDetail(Result<(RoomId, String, String), Error>),
RoomAvatar(Result<(RoomId, Option<Url>), Error>),
NewRoomAvatar(RoomId),
RoomMemberEvent(Event),
- RoomMessages(Vec<Message>),
+ RoomMessages(Result<Vec<Message>, Error>),
RoomMessagesInit(Vec<Message>),
RoomMessagesTo(Result<(Vec<Message>, RoomId, Option<String>), Error>),
RoomMembers(Result<(RoomId, Vec<Member>), Error>),
@@ -151,7 +151,7 @@ pub enum RoomType {
pub struct BackendData {
pub rooms_since: String,
pub join_to_room: Option<RoomId>,
- pub m_direct: HashMap<String, Vec<String>>,
+ pub m_direct: HashMap<UserId, Vec<RoomId>>,
}
#[derive(Clone)]
@@ -161,7 +161,7 @@ pub struct Backend {
pub internal_tx: Option<Sender<BKCommand>>,
// user info cache, uid -> (name, avatar)
- pub user_info_cache: CacheMap<Arc<Mutex<(String, String)>>>,
+ pub user_info_cache: CacheMap<UserId, Arc<Mutex<(String, String)>>>,
// semaphore to limit the number of threads downloading images
pub limit_threads: Arc<(Mutex<u8>, Condvar)>,
}
diff --git a/fractal-matrix-api/src/backend/user.rs b/fractal-matrix-api/src/backend/user.rs
index a76953da..4450169c 100644
--- a/fractal-matrix-api/src/backend/user.rs
+++ b/fractal-matrix-api/src/backend/user.rs
@@ -1,3 +1,4 @@
+use ruma_identifiers::UserId;
use std::fs;
use url::Url;
@@ -5,7 +6,6 @@ use crate::backend::types::Backend;
use crate::error::Error;
use crate::util::cache_dir_path;
use crate::util::dw_media;
-use crate::util::encode_uid;
use crate::util::get_user_avatar;
use crate::util::semaphore;
use crate::util::ContentType;
@@ -66,8 +66,8 @@ use crate::r0::Medium;
use crate::r0::ThreePIDCredentials;
use crate::types::Member;
-pub fn get_username(base: Url, uid: String) -> Result<Option<String>, Error> {
- get_display_name(base, &encode_uid(&uid))
+pub fn get_username(base: Url, uid: UserId) -> Result<Option<String>, Error> {
+ get_display_name(base, &uid)
.map_err(Into::into)
.and_then(|request| {
HTTP_CLIENT
@@ -81,8 +81,8 @@ pub fn get_username(base: Url, uid: String) -> Result<Option<String>, Error> {
// FIXME: This function manages errors *really* wrong and isn't more async
// than the normal function. It should be removed.
-pub fn get_username_async(base: Url, uid: String) -> String {
- get_display_name(base, &encode_uid(&uid))
+pub fn get_username_async(base: Url, uid: UserId) -> String {
+ get_display_name(base, &uid)
.map_err::<Error, _>(Into::into)
.and_then(|request| {
HTTP_CLIENT
@@ -93,13 +93,13 @@ pub fn get_username_async(base: Url, uid: String) -> String {
})
.ok()
.and_then(|response| response.displayname)
- .unwrap_or(uid)
+ .unwrap_or(uid.to_string())
}
pub fn set_username(
base: Url,
access_token: AccessToken,
- uid: String,
+ uid: UserId,
username: String,
) -> Result<String, Error> {
let params = SetDisplayNameParameters { access_token };
@@ -107,7 +107,7 @@ pub fn set_username(
displayname: Some(username.clone()),
};
- set_display_name(base, ¶ms, &body, &encode_uid(&uid))
+ set_display_name(base, ¶ms, &body, &uid)
.map_err(Into::into)
.and_then(|request| {
HTTP_CLIENT
@@ -339,7 +339,7 @@ pub fn account_destruction(
.and(Ok(()))
}
-pub fn get_avatar(base: Url, userid: String) -> Result<String, Error> {
+pub fn get_avatar(base: Url, userid: UserId) -> Result<String, Error> {
get_user_avatar(&base, &userid).map(|(_, fname)| fname)
}
@@ -360,7 +360,7 @@ pub fn get_avatar_async(bk: &Backend, base: Url, member: Option<Member>, tx: Sen
pub fn set_user_avatar(
base: Url,
access_token: AccessToken,
- id: String,
+ uid: UserId,
avatar: String,
) -> Result<String, Error> {
let params_upload = CreateContentParameters {
@@ -386,7 +386,7 @@ pub fn set_user_avatar(
avatar_url: Some(upload_response.content_uri),
};
- set_avatar_url(base, ¶ms_avatar, &body, &encode_uid(&id))
+ set_avatar_url(base, ¶ms_avatar, &body, &uid)
.map_err(Into::into)
.and_then(|request| {
HTTP_CLIENT
@@ -401,12 +401,11 @@ pub fn set_user_avatar(
pub fn get_user_info_async(
bk: &mut Backend,
baseu: Url,
- uid: String,
+ uid: UserId,
tx: Option<Sender<(String, String)>>,
) {
- if let Some(info) = bk.user_info_cache.get(&uid) {
+ if let Some(info) = bk.user_info_cache.get(&uid).cloned() {
if let Some(tx) = tx.clone() {
- let info = info.clone();
thread::spawn(move || {
let i = info.lock().unwrap().clone();
tx.send(i).expect_log("Connection closed");
@@ -455,12 +454,12 @@ pub fn search(
.map(|response| response.results.into_iter().map(Into::into).collect())
}
-fn get_user_avatar_img(baseu: &Url, userid: &str, avatar: &str) -> Result<String, Error> {
+fn get_user_avatar_img(baseu: &Url, userid: &UserId, avatar: &str) -> Result<String, Error> {
if avatar.is_empty() {
return Ok(String::new());
}
- let dest = cache_dir_path(None, &userid)?;
+ let dest = cache_dir_path(None, &userid.to_string())?;
dw_media(
baseu,
&avatar,
diff --git a/fractal-matrix-api/src/cache.rs b/fractal-matrix-api/src/cache.rs
index 3d39000e..1615c039 100644
--- a/fractal-matrix-api/src/cache.rs
+++ b/fractal-matrix-api/src/cache.rs
@@ -1,25 +1,27 @@
use std::collections::HashMap;
+use std::hash::Hash;
use std::time::Instant;
-pub struct CacheMap<T: Clone> {
- map: HashMap<String, (Instant, T)>,
+#[derive(Clone)]
+pub struct CacheMap<K: Clone, V: Clone> {
+ map: HashMap<K, (Instant, V)>,
timeout: u64,
}
-impl<T: Clone> CacheMap<T> {
- pub fn new() -> CacheMap<T> {
+impl<K: Clone + Eq + Hash, V: Clone> CacheMap<K, V> {
+ pub fn new() -> Self {
CacheMap {
map: HashMap::new(),
timeout: 10,
}
}
- pub fn timeout(mut self, timeout: u64) -> CacheMap<T> {
+ pub fn timeout(mut self, timeout: u64) -> Self {
self.timeout = timeout;
self
}
- pub fn get(&self, k: &String) -> Option<&T> {
+ pub fn get(&self, k: &K) -> Option<&V> {
match self.map.get(k) {
Some(t) => {
if t.0.elapsed().as_secs() >= self.timeout {
@@ -31,23 +33,8 @@ impl<T: Clone> CacheMap<T> {
}
}
- pub fn insert(&mut self, k: String, v: T) {
+ pub fn insert(&mut self, k: K, v: V) {
let now = Instant::now();
self.map.insert(k, (now, v));
}
}
-
-impl<T: Clone> Clone for CacheMap<T> {
- fn clone(&self) -> CacheMap<T> {
- let mut map: CacheMap<T> = CacheMap {
- map: HashMap::new(),
- timeout: self.timeout,
- };
-
- for (k, v) in self.map.iter() {
- map.map.insert(k.clone(), (v.0.clone(), v.1.clone()));
- }
-
- map
- }
-}
diff --git a/fractal-matrix-api/src/model/event.rs b/fractal-matrix-api/src/model/event.rs
index 83bdbf58..787f9be3 100644
--- a/fractal-matrix-api/src/model/event.rs
+++ b/fractal-matrix-api/src/model/event.rs
@@ -1,9 +1,9 @@
-use ruma_identifiers::RoomId;
+use ruma_identifiers::{RoomId, UserId};
use serde_json::Value as JsonValue;
#[derive(Debug, Clone)]
pub struct Event {
- pub sender: String,
+ pub sender: UserId,
pub stype: String,
pub room: RoomId,
pub id: String,
diff --git a/fractal-matrix-api/src/model/member.rs b/fractal-matrix-api/src/model/member.rs
index 160beae8..6d9913ab 100644
--- a/fractal-matrix-api/src/model/member.rs
+++ b/fractal-matrix-api/src/model/member.rs
@@ -1,5 +1,6 @@
use crate::r0::search::user::User;
use crate::r0::sync::get_joined_members::RoomMember;
+use ruma_identifiers::UserId;
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use url::Url;
@@ -7,10 +8,7 @@ use url::Url;
// TODO: Make this non-(de)serializable
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Member {
- // The mxid is either inside the json object, or outside of it.
- // Since we don't know, we always have to populate it manually
- #[serde(default)]
- pub uid: String,
+ pub uid: UserId,
#[serde(rename = "display_name")]
pub alias: Option<String>,
#[serde(rename = "avatar_url")]
@@ -24,7 +22,7 @@ impl Member {
return alias.clone();
}
}
- self.uid.clone()
+ self.uid.to_string()
}
}
@@ -44,19 +42,15 @@ impl From<User> for Member {
}
}
-impl From<(String, RoomMember)> for Member {
- fn from(uid_roommember: (String, RoomMember)) -> Self {
+impl From<(UserId, RoomMember)> for Member {
+ fn from((uid, roommember): (UserId, RoomMember)) -> Self {
Member {
- uid: uid_roommember.0,
- alias: uid_roommember.1.display_name,
- avatar: uid_roommember
- .1
- .avatar_url
- .as_ref()
- .map(ToString::to_string),
+ uid,
+ alias: roommember.display_name,
+ avatar: roommember.avatar_url.as_ref().map(ToString::to_string),
}
}
}
// hashmap userid -> Member
-pub type MemberList = HashMap<String, Member>;
+pub type MemberList = HashMap<UserId, Member>;
diff --git a/fractal-matrix-api/src/model/message.rs b/fractal-matrix-api/src/model/message.rs
index 884d5dbe..353cb139 100644
--- a/fractal-matrix-api/src/model/message.rs
+++ b/fractal-matrix-api/src/model/message.rs
@@ -1,16 +1,17 @@
use chrono::prelude::*;
use chrono::DateTime;
use chrono::TimeZone;
-use ruma_identifiers::RoomId;
+use ruma_identifiers::{Error as IdError, 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
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Message {
- pub sender: String,
+ pub sender: UserId,
pub mtype: String,
pub body: String,
pub date: DateTime<Local>,
@@ -21,7 +22,7 @@ pub struct Message {
pub formatted_body: Option<String>,
pub format: Option<String>,
pub source: Option<String>,
- pub receipt: HashMap<String, i64>, // This `HashMap` associates the user ID with a timestamp
+ 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>,
@@ -48,7 +49,7 @@ impl PartialOrd for Message {
}
impl Message {
- pub fn new(room: RoomId, sender: String, body: String, mtype: String) -> Self {
+ pub fn new(room: RoomId, sender: UserId, body: String, mtype: String) -> Self {
let date = Local::now();
Message {
id: get_txn_id(&room, &body, &date.to_string()),
@@ -96,8 +97,8 @@ impl Message {
///
/// * `roomid` - The message room id
/// * `msg` - The message event as Json
- pub fn parse_room_message(room_id: &RoomId, msg: &JsonValue) -> Message {
- let sender = msg["sender"].as_str().unwrap_or_default();
+ pub fn parse_room_message(room_id: &RoomId, msg: &JsonValue) -> Result<Message, IdError> {
+ let sender: UserId = msg["sender"].as_str().unwrap_or_default().try_into()?;
let timestamp = msg["origin_server_ts"].as_i64().unwrap_or_default() / 1000;
let server_timestamp: DateTime<Local> = Local.timestamp(timestamp, 0);
@@ -108,7 +109,7 @@ impl Message {
let redacted = msg["unsigned"].get("redacted_because") != None;
let mut message = Message {
- sender: sender.to_string(),
+ sender,
date: server_timestamp,
room: room_id.clone(),
id: id.to_string(),
@@ -132,7 +133,7 @@ impl Message {
_ => {}
};
- message
+ Ok(message)
}
fn parse_m_room_message(&mut self, c: &JsonValue) {
@@ -190,7 +191,10 @@ impl Message {
///
/// * `roomid` - The messages room id
/// * `events` - An iterator to the json events
- pub fn from_json_events_iter<'a, I>(room_id: &RoomId, events: I) -> Vec<Message>
+ pub fn from_json_events_iter<'a, I>(
+ room_id: &RoomId,
+ events: I,
+ ) -> Result<Vec<Message>, IdError>
where
I: Iterator<Item = &'a JsonValue>,
{
@@ -200,7 +204,7 @@ impl Message {
.collect()
}
- pub fn set_receipt(&mut self, receipt: HashMap<String, i64>) {
+ pub fn set_receipt(&mut self, receipt: HashMap<UserId, i64>) {
self.receipt = receipt;
}
}
diff --git a/fractal-matrix-api/src/model/room.rs b/fractal-matrix-api/src/model/room.rs
index e250c4e3..e49ee5d0 100644
--- a/fractal-matrix-api/src/model/room.rs
+++ b/fractal-matrix-api/src/model/room.rs
@@ -8,9 +8,10 @@ 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::RoomId;
+use ruma_identifiers::{Error as IdError, RoomId, UserId};
use serde::{Deserialize, Serialize};
use std::collections::{HashMap, HashSet};
+use std::convert::{TryFrom, TryInto};
use url::Url;
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
@@ -99,8 +100,8 @@ pub struct Room {
/// Hashmap with the room users power levels
/// the key will be the userid and the value will be the level
- pub admins: HashMap<String, i32>,
- pub power_levels: HashMap<String, i32>,
+ pub admins: HashMap<UserId, i32>,
+ pub default_power_level: i32,
}
impl Room {
@@ -124,13 +125,17 @@ impl Room {
typing_users: Default::default(),
language: Default::default(),
admins: Default::default(),
- power_levels: Default::default(),
+ default_power_level: -1,
}
}
- pub fn from_sync_response(response: &SyncResponse, userid: &str, baseu: &Url) -> Vec<Self> {
+ pub fn from_sync_response(
+ response: &SyncResponse,
+ user_id: UserId,
+ baseu: &Url,
+ ) -> Result<Vec<Self>, IdError> {
// getting the list of direct rooms
- let direct: HashSet<String> = parse_m_direct(&response.account_data.events)
+ let direct: HashSet<RoomId> = parse_m_direct(&response.account_data.events)?
.values()
.flatten()
.cloned()
@@ -154,17 +159,17 @@ impl Room {
.map(|lang| lang.to_string());
let mut r = Self {
- name: calculate_room_name(stevents, userid),
+ name: calculate_room_name(stevents, &user_id),
avatar: evc(stevents, "m.room.avatar", "url"),
alias: evc(stevents, "m.room.canonical_alias", "alias"),
topic: evc(stevents, "m.room.topic", "topic"),
- direct: direct.contains(&k.to_string()),
+ direct: direct.contains(&k),
notifications: room.unread_notifications.notification_count,
highlight: room.unread_notifications.highlight_count,
prev_batch: timeline.prev_batch.clone(),
- messages: Message::from_json_events_iter(&k, timeline.events.iter()),
- admins: get_admins(stevents),
- power_levels: get_power_levels(stevents),
+ messages: Message::from_json_events_iter(&k, timeline.events.iter())?,
+ admins: get_admins(stevents)?,
+ default_power_level: get_default_power_level(stevents),
members: stevents
.iter()
.filter(|x| x["type"] == "m.room.member")
@@ -187,25 +192,26 @@ impl Room {
.into_iter()
.find(|x| x["type"] == "m.fully_read")
.and_then(|fread| fread["content"]["event_id"].as_str())
+ .map(ToOwned::to_owned)
{
- r.add_receipt_from_fully_read(userid, ev);
+ r.add_receipt_from_fully_read(user_id.clone(), ev);
}
- r
+ Ok(r)
});
let left_rooms = response.rooms.leave.iter().map(|(k, room)| {
- if let Some(last_event) = room.timeline.events.last() {
- let leave_id = &last_event["sender"];
- if leave_id != userid {
+ let r = if let Some(last_event) = room.timeline.events.last() {
+ let leave_id = UserId::try_from(last_event["sender"].as_str().unwrap_or_default())?;
+ if leave_id != user_id {
let kick_reason = &last_event["content"]["reason"];
if let Some((kicker_alias, kicker_avatar)) =
- get_user_avatar(baseu, leave_id.as_str().unwrap_or_default()).ok()
+ get_user_avatar(baseu, &leave_id).ok()
{
let kicker = Member {
alias: Some(kicker_alias),
avatar: Some(kicker_avatar),
- uid: String::from(leave_id.as_str().unwrap_or_default()),
+ uid: leave_id,
};
let reason = Reason::Kicked(
String::from(kick_reason.as_str().unwrap_or_default()),
@@ -220,37 +226,51 @@ impl Room {
}
} else {
Self::new(k.clone(), RoomMembership::Left(Reason::None))
- }
- });
+ };
- let invited_rooms = response.rooms.invite.iter().filter_map(|(k, room)| {
- let stevents = &room.invite_state.events;
- if let Some((alias, avatar)) = stevents
- .iter()
- .find(|x| x["content"]["membership"] == "invite" && x["state_key"] == userid)
- .and_then(|ev| {
- get_user_avatar(baseu, ev["sender"].as_str().unwrap_or_default()).ok()
- })
- {
- let inv_sender = Member {
- alias: Some(alias),
- avatar: Some(avatar),
- uid: String::from(userid),
- };
-
- Some(Self {
- name: calculate_room_name(stevents, userid),
- avatar: evc(stevents, "m.room.avatar", "url"),
- alias: evc(stevents, "m.room.canonical_alias", "alias"),
- topic: evc(stevents, "m.room.topic", "topic"),
- direct: direct.contains(&k.to_string()),
- ..Self::new(k.clone(), RoomMembership::Invited(inv_sender))
- })
- } else {
- None
- }
+ Ok(r)
});
+ let invited_rooms = response
+ .rooms
+ .invite
+ .iter()
+ .map(|(k, room)| {
+ let stevents = &room.invite_state.events;
+ let alias_avatar: Result<Option<(String, String)>, IdError> = stevents
+ .iter()
+ .find(|x| {
+ x["content"]["membership"] == "invite"
+ && x["state_key"] == user_id.to_string().as_str()
+ })
+ .map_or(Ok(None), |ev| {
+ Ok(get_user_avatar(
+ baseu,
+ &UserId::try_from(ev["sender"].as_str().unwrap_or_default())?,
+ )
+ .ok())
+ });
+ if let Some((alias, avatar)) = alias_avatar? {
+ let inv_sender = Member {
+ alias: Some(alias),
+ avatar: Some(avatar),
+ uid: user_id.clone(),
+ };
+
+ Ok(Some(Self {
+ name: calculate_room_name(stevents, &user_id),
+ avatar: evc(stevents, "m.room.avatar", "url"),
+ alias: evc(stevents, "m.room.canonical_alias", "alias"),
+ topic: evc(stevents, "m.room.topic", "topic"),
+ direct: direct.contains(&k),
+ ..Self::new(k.clone(), RoomMembership::Invited(inv_sender))
+ }))
+ } else {
+ Ok(None)
+ }
+ })
+ .filter_map(Result::transpose);
+
joined_rooms
.chain(left_rooms)
.chain(invited_rooms)
@@ -258,7 +278,7 @@ impl Room {
}
pub fn add_receipt_from_json(&mut self, mut events: Vec<&JsonValue>) {
- let receipts: HashMap<String, HashMap<String, i64>> = events
+ let receipts: HashMap<String, HashMap<UserId, i64>> = events
.pop()
.and_then(|ev| ev["content"].as_object())
.into_iter()
@@ -273,29 +293,28 @@ impl Room {
if ts == 0 {
info!("Possibly malformed timestamp, working around synapse bug 4898");
};
- (uid.to_string(), ts)
+ Ok((UserId::try_from(uid.as_str())?, ts))
})
- .collect();
+ .collect::<Result<HashMap<UserId, i64>, IdError>>()
+ .ok()?;
Some((mid.to_string(), receipts))
})
.collect();
- if !receipts.is_empty() {
- for msg in self.messages.iter_mut() {
- if let Some(r) = receipts.get(&msg.id) {
- msg.set_receipt(r.clone());
- }
+ for msg in self.messages.iter_mut() {
+ if let Some(r) = receipts.get(&msg.id) {
+ msg.set_receipt(r.clone());
}
}
}
- pub fn add_receipt_from_fully_read(&mut self, uid: &str, evid: &str) {
+ pub fn add_receipt_from_fully_read(&mut self, uid: UserId, evid: String) {
let _ = self
.messages
.iter_mut()
- .filter(|msg| msg.id == evid.to_string())
- .map(|msg| msg.receipt.insert(uid.to_string(), 0));
+ .filter(|msg| msg.id == evid)
+ .map(|msg| msg.receipt.insert(uid.clone(), 0));
}
}
@@ -330,27 +349,32 @@ fn evc(events: &Vec<JsonValue>, t: &str, field: &str) -> Option<String> {
.map(Into::into)
}
-fn get_admins(stevents: &Vec<JsonValue>) -> HashMap<String, i32> {
+fn get_admins(stevents: &Vec<JsonValue>) -> Result<HashMap<UserId, i32>, IdError> {
stevents
.iter()
.filter(|x| x["type"] == "m.room.power_levels")
.filter_map(|ev| ev["content"]["users"].as_object())
.flatten()
- .map(|(k, v)| (k.clone(), v.as_i64().map(|v| v as i32).unwrap_or_default()))
+ .map(|(k, v)| {
+ Ok((
+ UserId::try_from(k.as_str())?,
+ v.as_i64().map(|v| v as i32).unwrap_or_default(),
+ ))
+ })
.collect()
}
-fn get_power_levels(stevents: &Vec<JsonValue>) -> HashMap<String, i32> {
+fn get_default_power_level(stevents: &Vec<JsonValue>) -> i32 {
stevents
.iter()
.filter(|x| x["type"] == "m.room.power_levels")
- .filter_map(|ev| ev["content"].as_object())
- .flatten()
- .map(|(k, v)| (k.clone(), v.as_i64().map(|v| v as i32).unwrap_or_default()))
- .collect()
+ .filter_map(|ev| ev["content"]["users_default"].as_i64())
+ .last()
+ .unwrap_or(-1) as i32
}
-fn calculate_room_name(events: &Vec<JsonValue>, userid: &str) -> Option<String> {
+fn calculate_room_name(events: &Vec<JsonValue>, user_id: &UserId) -> Option<String> {
+ let userid = user_id.to_string();
// looking for "m.room.name" event
if let Some(name) = events
.iter()
@@ -377,8 +401,9 @@ fn calculate_room_name(events: &Vec<JsonValue>, userid: &str) -> Option<String>
.iter()
.filter(|x| {
(x["type"] == "m.room.member"
- && ((x["content"]["membership"] == "join" && x["sender"] != userid)
- || (x["content"]["membership"] == "invite" && x["state_key"] != userid)))
+ && ((x["content"]["membership"] == "join" && x["sender"] != userid.as_str())
+ || (x["content"]["membership"] == "invite"
+ && x["state_key"] != userid.as_str())))
})
.take(3)
.map(|m| {
@@ -401,7 +426,7 @@ fn parse_room_member(msg: &JsonValue) -> Option<Member> {
let _ = c["membership"].as_str().filter(|&m| m == "join")?;
Some(Member {
- uid: msg["sender"].as_str().map(Into::into)?,
+ uid: msg["sender"].as_str().unwrap_or_default().try_into().ok()?,
alias: c["displayname"].as_str().map(Into::into),
avatar: c["avatar_url"].as_str().map(Into::into),
})
diff --git a/fractal-matrix-api/src/r0/account/login.rs b/fractal-matrix-api/src/r0/account/login.rs
index 28f1f617..14f3bfcc 100644
--- a/fractal-matrix-api/src/r0/account/login.rs
+++ b/fractal-matrix-api/src/r0/account/login.rs
@@ -4,6 +4,7 @@ use reqwest::Client;
use reqwest::Error;
use reqwest::Request;
use ruma_identifiers::DeviceId;
+use ruma_identifiers::UserId;
use serde::{Deserialize, Serialize};
use url::Url;
@@ -31,7 +32,7 @@ pub enum Auth {
#[derive(Clone, Debug, Deserialize)]
pub struct Response {
pub access_token: Option<AccessToken>,
- pub user_id: Option<String>,
+ pub user_id: Option<UserId>,
pub device_id: Option<DeviceId>,
}
diff --git a/fractal-matrix-api/src/r0/account/register.rs b/fractal-matrix-api/src/r0/account/register.rs
index 5c01a7f1..c072f24c 100644
--- a/fractal-matrix-api/src/r0/account/register.rs
+++ b/fractal-matrix-api/src/r0/account/register.rs
@@ -4,6 +4,7 @@ use reqwest::Client;
use reqwest::Error;
use reqwest::Request;
use ruma_identifiers::DeviceId;
+use ruma_identifiers::UserId;
use serde::{Deserialize, Serialize};
use std::ops::Not;
use url::Url;
@@ -54,7 +55,7 @@ pub struct Body {
#[derive(Clone, Debug, Deserialize)]
pub struct Response {
- pub user_id: String,
+ pub user_id: UserId,
pub access_token: Option<AccessToken>,
pub device_id: Option<DeviceId>,
}
diff --git a/fractal-matrix-api/src/r0/membership/invite_user.rs
b/fractal-matrix-api/src/r0/membership/invite_user.rs
index 7bb8c07e..1873928a 100644
--- a/fractal-matrix-api/src/r0/membership/invite_user.rs
+++ b/fractal-matrix-api/src/r0/membership/invite_user.rs
@@ -2,7 +2,7 @@ use crate::r0::AccessToken;
use reqwest::Client;
use reqwest::Error;
use reqwest::Request;
-use ruma_identifiers::RoomId;
+use ruma_identifiers::{RoomId, UserId};
use serde::Serialize;
use url::Url;
@@ -13,7 +13,7 @@ pub struct Parameters {
#[derive(Clone, Debug, Serialize)]
pub struct Body {
- pub user_id: String,
+ pub user_id: UserId,
}
pub fn request(
diff --git a/fractal-matrix-api/src/r0/profile/get_display_name.rs
b/fractal-matrix-api/src/r0/profile/get_display_name.rs
index a871b55c..0c8f3f19 100644
--- a/fractal-matrix-api/src/r0/profile/get_display_name.rs
+++ b/fractal-matrix-api/src/r0/profile/get_display_name.rs
@@ -1,6 +1,7 @@
use reqwest::Client;
use reqwest::Error;
use reqwest::Request;
+use ruma_identifiers::UserId;
use serde::Deserialize;
use url::Url;
@@ -9,7 +10,7 @@ pub struct Response {
pub displayname: Option<String>,
}
-pub fn request(base: Url, user_id: &str) -> Result<Request, Error> {
+pub fn request(base: Url, user_id: &UserId) -> Result<Request, Error> {
let url = base
.join(&format!(
"/_matrix/client/r0/profile/{}/displayname",
diff --git a/fractal-matrix-api/src/r0/profile/get_profile.rs
b/fractal-matrix-api/src/r0/profile/get_profile.rs
index 7af43940..6713a1f1 100644
--- a/fractal-matrix-api/src/r0/profile/get_profile.rs
+++ b/fractal-matrix-api/src/r0/profile/get_profile.rs
@@ -2,6 +2,7 @@ use crate::serde::option_url;
use reqwest::Client;
use reqwest::Error;
use reqwest::Request;
+use ruma_identifiers::UserId;
use serde::Deserialize;
use url::Url;
@@ -13,7 +14,7 @@ pub struct Response {
pub displayname: Option<String>,
}
-pub fn request(base: Url, user_id: &str) -> Result<Request, Error> {
+pub fn request(base: Url, user_id: &UserId) -> Result<Request, Error> {
let url = base
.join(&format!("/_matrix/client/r0/profile/{}", user_id))
.expect("Malformed URL in get_profile_avatar");
diff --git a/fractal-matrix-api/src/r0/profile/set_avatar_url.rs
b/fractal-matrix-api/src/r0/profile/set_avatar_url.rs
index 715235e1..dd6bb497 100644
--- a/fractal-matrix-api/src/r0/profile/set_avatar_url.rs
+++ b/fractal-matrix-api/src/r0/profile/set_avatar_url.rs
@@ -3,6 +3,7 @@ use crate::serde::option_url;
use reqwest::Client;
use reqwest::Error;
use reqwest::Request;
+use ruma_identifiers::UserId;
use serde::Serialize;
use url::Url;
@@ -21,7 +22,7 @@ pub fn request(
base: Url,
params: &Parameters,
body: &Body,
- user_id: &str,
+ user_id: &UserId,
) -> Result<Request, Error> {
let url = base
.join(&format!(
diff --git a/fractal-matrix-api/src/r0/profile/set_display_name.rs
b/fractal-matrix-api/src/r0/profile/set_display_name.rs
index a399042e..f3b54b05 100644
--- a/fractal-matrix-api/src/r0/profile/set_display_name.rs
+++ b/fractal-matrix-api/src/r0/profile/set_display_name.rs
@@ -2,6 +2,7 @@ use crate::r0::AccessToken;
use reqwest::Client;
use reqwest::Error;
use reqwest::Request;
+use ruma_identifiers::UserId;
use serde::Serialize;
use url::Url;
@@ -20,7 +21,7 @@ pub fn request(
base: Url,
params: &Parameters,
body: &Body,
- user_id: &str,
+ user_id: &UserId,
) -> Result<Request, Error> {
let url = base
.join(&format!(
diff --git a/fractal-matrix-api/src/r0/search/user.rs b/fractal-matrix-api/src/r0/search/user.rs
index 2fc55367..af5191c8 100644
--- a/fractal-matrix-api/src/r0/search/user.rs
+++ b/fractal-matrix-api/src/r0/search/user.rs
@@ -3,6 +3,7 @@ use crate::serde::option_url;
use reqwest::Client;
use reqwest::Error;
use reqwest::Request;
+use ruma_identifiers::UserId;
use serde::{Deserialize, Serialize};
use url::Url;
@@ -35,7 +36,7 @@ pub struct Response {
#[derive(Clone, Debug, Deserialize)]
pub struct User {
- pub user_id: String,
+ pub user_id: UserId,
#[serde(default)]
pub display_name: Option<String>,
#[serde(with = "option_url")]
diff --git a/fractal-matrix-api/src/r0/sync/get_joined_members.rs
b/fractal-matrix-api/src/r0/sync/get_joined_members.rs
index e8776c39..483aa388 100644
--- a/fractal-matrix-api/src/r0/sync/get_joined_members.rs
+++ b/fractal-matrix-api/src/r0/sync/get_joined_members.rs
@@ -3,7 +3,7 @@ use crate::serde::option_url;
use reqwest::Client;
use reqwest::Error;
use reqwest::Request;
-use ruma_identifiers::RoomId;
+use ruma_identifiers::{RoomId, UserId};
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use url::Url;
@@ -16,7 +16,7 @@ pub struct Parameters {
#[derive(Clone, Debug, Deserialize)]
pub struct Response {
#[serde(default)]
- pub joined: HashMap<String, RoomMember>,
+ pub joined: HashMap<UserId, RoomMember>,
}
#[derive(Clone, Debug, Deserialize)]
diff --git a/fractal-matrix-api/src/r0/sync/sync_events.rs b/fractal-matrix-api/src/r0/sync/sync_events.rs
index 5aaf9bc2..87be786f 100644
--- a/fractal-matrix-api/src/r0/sync/sync_events.rs
+++ b/fractal-matrix-api/src/r0/sync/sync_events.rs
@@ -3,7 +3,7 @@ use crate::r0::AccessToken;
use reqwest::Client;
use reqwest::Error;
use reqwest::Request;
-use ruma_identifiers::RoomId;
+use ruma_identifiers::{RoomId, UserId};
use serde::ser::SerializeMap;
use serde::{Deserialize, Serialize, Serializer};
use serde_json::Value as JsonValue;
@@ -217,9 +217,9 @@ pub struct ToDevice {
#[derive(Clone, Debug, Deserialize)]
pub struct DeviceLists {
#[serde(default)]
- pub changed: Vec<String>,
+ pub changed: Vec<UserId>,
#[serde(default)]
- pub left: Vec<String>,
+ pub left: Vec<UserId>,
}
pub fn request(base: Url, params: &Parameters) -> Result<Request, Error> {
diff --git a/fractal-matrix-api/src/r0/tag/create_tag.rs b/fractal-matrix-api/src/r0/tag/create_tag.rs
index e143d604..968b573e 100644
--- a/fractal-matrix-api/src/r0/tag/create_tag.rs
+++ b/fractal-matrix-api/src/r0/tag/create_tag.rs
@@ -2,7 +2,7 @@ use crate::r0::AccessToken;
use reqwest::Client;
use reqwest::Error;
use reqwest::Request;
-use ruma_identifiers::RoomId;
+use ruma_identifiers::{RoomId, UserId};
use serde::Serialize;
use url::Url;
@@ -20,7 +20,7 @@ pub struct Body {
pub fn request(
base: Url,
- user_id: &str,
+ user_id: &UserId,
room_id: &RoomId,
tag: &str,
params: &Parameters,
diff --git a/fractal-matrix-api/src/r0/tag/delete_tag.rs b/fractal-matrix-api/src/r0/tag/delete_tag.rs
index 6c116725..0a45efa1 100644
--- a/fractal-matrix-api/src/r0/tag/delete_tag.rs
+++ b/fractal-matrix-api/src/r0/tag/delete_tag.rs
@@ -2,7 +2,7 @@ use crate::r0::AccessToken;
use reqwest::Client;
use reqwest::Error;
use reqwest::Request;
-use ruma_identifiers::RoomId;
+use ruma_identifiers::{RoomId, UserId};
use serde::Serialize;
use url::Url;
@@ -13,7 +13,7 @@ pub struct Parameters {
pub fn request(
base: Url,
- user_id: &str,
+ user_id: &UserId,
room_id: &RoomId,
tag: &str,
params: &Parameters,
diff --git a/fractal-matrix-api/src/r0/typing.rs b/fractal-matrix-api/src/r0/typing.rs
index 473a023d..bf538e53 100644
--- a/fractal-matrix-api/src/r0/typing.rs
+++ b/fractal-matrix-api/src/r0/typing.rs
@@ -2,7 +2,7 @@ use crate::r0::AccessToken;
use reqwest::Client;
use reqwest::Error;
use reqwest::Request;
-use ruma_identifiers::RoomId;
+use ruma_identifiers::{RoomId, UserId};
use serde::ser::SerializeMap;
use serde::Serialize;
use serde::Serializer;
@@ -44,7 +44,7 @@ impl Serialize for Body {
pub fn request(
base: Url,
room_id: &RoomId,
- user_id: &str,
+ user_id: &UserId,
params: &Parameters,
body: &Body,
) -> Result<Request, Error> {
diff --git a/fractal-matrix-api/src/util.rs b/fractal-matrix-api/src/util.rs
index 202bda53..9a81e7d5 100644
--- a/fractal-matrix-api/src/util.rs
+++ b/fractal-matrix-api/src/util.rs
@@ -5,12 +5,12 @@ use serde_json::json;
use serde_json::Value as JsonValue;
use directories::ProjectDirs;
-use ruma_identifiers::RoomId;
+use ruma_identifiers::{Error as IdError, RoomId, UserId};
use std::collections::HashMap;
+use std::convert::TryFrom;
use std::io::Read;
use std::path::Path;
use std::path::PathBuf;
-use url::percent_encoding::{utf8_percent_encode, USERINFO_ENCODE_SET};
use url::Url;
use std::fs::{create_dir_all, write};
@@ -171,7 +171,7 @@ impl ContentType {
}
}
-pub fn parse_m_direct(events: &Vec<JsonValue>) -> HashMap<String, Vec<String>> {
+pub fn parse_m_direct(events: &Vec<JsonValue>) -> Result<HashMap<UserId, Vec<RoomId>>, IdError> {
events
.iter()
.find(|x| x["type"] == "m.direct")
@@ -179,14 +179,14 @@ pub fn parse_m_direct(events: &Vec<JsonValue>) -> HashMap<String, Vec<String>> {
.cloned()
.unwrap_or_default()
.iter()
- .map(|(k, v)| {
- let value = v
+ .map(|(uid, rid)| {
+ let value = rid
.as_array()
.unwrap_or(&vec![])
.iter()
- .map(|rid| rid.as_str().map(Into::into).unwrap_or_default())
- .collect();
- (k.clone(), value)
+ .map(|rid| RoomId::try_from(rid.as_str().unwrap_or_default()))
+ .collect::<Result<Vec<RoomId>, IdError>>()?;
+ Ok((UserId::try_from(uid.as_str())?, value))
})
.collect()
}
@@ -308,8 +308,8 @@ pub fn json_q(method: &str, url: Url, attrs: &JsonValue) -> Result<JsonValue, Er
}
}
-pub fn get_user_avatar(base: &Url, userid: &str) -> Result<(String, String), Error> {
- let response = get_profile(base.clone(), &encode_uid(userid))
+pub fn get_user_avatar(base: &Url, user_id: &UserId) -> Result<(String, String), Error> {
+ let response = get_profile(base.clone(), user_id)
.map_err::<Error, _>(Into::into)
.and_then(|request| {
HTTP_CLIENT
@@ -322,12 +322,12 @@ pub fn get_user_avatar(base: &Url, userid: &str) -> Result<(String, String), Err
let name = response
.displayname
.filter(|n| !n.is_empty())
- .unwrap_or(userid.to_string());
+ .unwrap_or(user_id.to_string());
let img = response
.avatar_url
.map(|url| {
- let dest = cache_dir_path(None, userid)?;
+ let dest = cache_dir_path(None, &user_id.to_string())?;
dw_media(
base,
url.as_str(),
@@ -382,10 +382,6 @@ pub fn cache_dir_path(dir: Option<&str>, name: &str) -> Result<String, Error> {
.ok_or(Error::CacheError)
}
-pub fn encode_uid(userid: &str) -> String {
- utf8_percent_encode(userid, USERINFO_ENCODE_SET).collect::<String>()
-}
-
pub trait ResultExpectLog {
fn expect_log(&self, log: &str);
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]