Replace profile_* with userid_*

Add a missing dot in the errormessage
Require mxc:// to be present at the start of an avatar_url
Update mxc check TODO
Show displayname or avatar_url if either is available when getting the profile Endpoint
Return the correct data in case of a empty displayname or an empty avatar_url

Took 50 minutes

Took 34 seconds
This commit is contained in:
Marcel 2020-04-09 20:47:03 +02:00
parent 062c5521f0
commit b1284fd509
3 changed files with 91 additions and 52 deletions

View File

@ -60,10 +60,15 @@ impl Data {
.map(|bytes| utils::string_from_bytes(&bytes)) .map(|bytes| utils::string_from_bytes(&bytes))
} }
/// Removes a displayname.
pub fn displayname_remove(&self, user_id: &UserId) {
self.db.userid_displayname.remove(user_id).unwrap();
}
/// Set a new displayname. /// Set a new displayname.
pub fn displayname_set(&self, user_id: &UserId, displayname: Option<String>) { pub fn displayname_set(&self, user_id: &UserId, displayname: Option<String>) {
self.db self.db
.profile_displayname .userid_displayname
.insert(user_id.to_string(), &*displayname.unwrap_or_default()) .insert(user_id.to_string(), &*displayname.unwrap_or_default())
.unwrap(); .unwrap();
} }
@ -71,16 +76,21 @@ impl Data {
/// Get a the displayname of a user. /// Get a the displayname of a user.
pub fn displayname_get(&self, user_id: &UserId) -> Option<String> { pub fn displayname_get(&self, user_id: &UserId) -> Option<String> {
self.db self.db
.profile_displayname .userid_displayname
.get(user_id.to_string()) .get(user_id.to_string())
.unwrap() .unwrap()
.map(|bytes| utils::string_from_bytes(&bytes)) .map(|bytes| utils::string_from_bytes(&bytes))
} }
/// Removes a avatar_url.
pub fn avatar_url_remove(&self, user_id: &UserId) {
self.db.userid_avatar_url.remove(user_id).unwrap();
}
/// Set a new avatar_url. /// Set a new avatar_url.
pub fn avatar_url_set(&self, user_id: &UserId, avatar_url: String) { pub fn avatar_url_set(&self, user_id: &UserId, avatar_url: String) {
self.db self.db
.profile_avatar_url .userid_avatar_url
.insert(user_id.to_string(), &*avatar_url) .insert(user_id.to_string(), &*avatar_url)
.unwrap(); .unwrap();
} }
@ -88,7 +98,7 @@ impl Data {
/// Get a the avatar_url of a user. /// Get a the avatar_url of a user.
pub fn avatar_url_get(&self, user_id: &UserId) -> Option<String> { pub fn avatar_url_get(&self, user_id: &UserId) -> Option<String> {
self.db self.db
.profile_avatar_url .userid_avatar_url
.get(user_id.to_string()) .get(user_id.to_string())
.unwrap() .unwrap()
.map(|bytes| utils::string_from_bytes(&bytes)) .map(|bytes| utils::string_from_bytes(&bytes))

View File

@ -52,8 +52,8 @@ impl MultiValue {
pub struct Database { pub struct Database {
pub userid_password: sled::Tree, pub userid_password: sled::Tree,
pub userid_deviceids: MultiValue, pub userid_deviceids: MultiValue,
pub profile_displayname: sled::Tree, pub userid_displayname: sled::Tree,
pub profile_avatar_url: sled::Tree, pub userid_avatar_url: sled::Tree,
pub deviceid_token: sled::Tree, pub deviceid_token: sled::Tree,
pub token_userid: sled::Tree, pub token_userid: sled::Tree,
pub pduid_pdus: sled::Tree, pub pduid_pdus: sled::Tree,
@ -77,8 +77,8 @@ impl Database {
Self { Self {
userid_password: db.open_tree("userid_password").unwrap(), userid_password: db.open_tree("userid_password").unwrap(),
userid_deviceids: MultiValue(db.open_tree("userid_deviceids").unwrap()), userid_deviceids: MultiValue(db.open_tree("userid_deviceids").unwrap()),
profile_displayname: db.open_tree("profile_displayname").unwrap(), userid_displayname: db.open_tree("userid_displayname").unwrap(),
profile_avatar_url: db.open_tree("profile_avatar_url").unwrap(), userid_avatar_url: db.open_tree("userid_avatar_url").unwrap(),
deviceid_token: db.open_tree("deviceid_token").unwrap(), deviceid_token: db.open_tree("deviceid_token").unwrap(),
token_userid: db.open_tree("token_userid").unwrap(), token_userid: db.open_tree("token_userid").unwrap(),
pduid_pdus: db.open_tree("pduid_pdus").unwrap(), pduid_pdus: db.open_tree("pduid_pdus").unwrap(),
@ -108,7 +108,7 @@ impl Database {
); );
} }
println!("# AccountData -> Displayname:"); println!("# AccountData -> Displayname:");
for (k, v) in self.profile_displayname.iter().map(|r| r.unwrap()) { for (k, v) in self.userid_displayname.iter().map(|r| r.unwrap()) {
println!( println!(
"{:?} -> {:?}", "{:?} -> {:?}",
String::from_utf8_lossy(&k), String::from_utf8_lossy(&k),
@ -116,7 +116,7 @@ impl Database {
); );
} }
println!("# AccountData -> AvatarURL:"); println!("# AccountData -> AvatarURL:");
for (k, v) in self.profile_avatar_url.iter().map(|r| r.unwrap()) { for (k, v) in self.userid_avatar_url.iter().map(|r| r.unwrap()) {
println!( println!(
"{:?} -> {:?}", "{:?} -> {:?}",
String::from_utf8_lossy(&k), String::from_utf8_lossy(&k),

View File

@ -1,4 +1,5 @@
#![feature(proc_macro_hygiene, decl_macro)] #![feature(proc_macro_hygiene, decl_macro)]
mod data; mod data;
mod database; mod database;
mod pdu; mod pdu;
@ -229,8 +230,8 @@ fn get_pushrules_all_route() -> MatrixResult<get_pushrules_all::Response> {
} }
#[get( #[get(
"/_matrix/client/r0/user/<_user_id>/filter/<_filter_id>", "/_matrix/client/r0/user/<_user_id>/filter/<_filter_id>",
data = "<body>" data = "<body>"
)] )]
fn get_filter_route( fn get_filter_route(
body: Ruma<get_filter::Request>, body: Ruma<get_filter::Request>,
@ -261,8 +262,8 @@ fn create_filter_route(
} }
#[put( #[put(
"/_matrix/client/r0/user/<_user_id>/account_data/<_type>", "/_matrix/client/r0/user/<_user_id>/account_data/<_type>",
data = "<body>" data = "<body>"
)] )]
fn set_global_account_data_route( fn set_global_account_data_route(
body: Ruma<set_global_account_data::Request>, body: Ruma<set_global_account_data::Request>,
@ -274,8 +275,8 @@ fn set_global_account_data_route(
} }
#[get( #[get(
"/_matrix/client/r0/user/<_user_id>/account_data/<_type>", "/_matrix/client/r0/user/<_user_id>/account_data/<_type>",
data = "<body>" data = "<body>"
)] )]
fn get_global_account_data_route( fn get_global_account_data_route(
body: Ruma<get_global_account_data::Request>, body: Ruma<get_global_account_data::Request>,
@ -297,25 +298,35 @@ fn set_displayname_route(
_user_id: String, _user_id: String,
) -> MatrixResult<set_display_name::Response> { ) -> MatrixResult<set_display_name::Response> {
let user_id = body.user_id.clone().expect("user is authenticated"); let user_id = body.user_id.clone().expect("user is authenticated");
// Send error on None and accept Some("") as valid username
// Synapse returns a parsing error but the spec doesn't require this
if body.displayname.is_none() { if body.displayname.is_none() {
debug!("Request was missing the displayname payload."); debug!("Request was missing the displayname payload.");
return MatrixResult(Err(Error { return MatrixResult(Err(Error {
kind: ErrorKind::MissingParam, kind: ErrorKind::MissingParam,
message: "Missing displayname".to_owned(), message: "Missing displayname.".to_owned(),
status_code: http::StatusCode::BAD_REQUEST, status_code: http::StatusCode::BAD_REQUEST,
})); }));
} }
if let Some(displayname) = body.displayname {
if displayname == "" {
data.displayname_remove(&user_id);
} else {
data.displayname_set(&user_id, body.displayname.clone()); data.displayname_set(&user_id, body.displayname.clone());
// TODO send a new m.room.member join event with the updated displayname // TODO send a new m.room.member join event with the updated displayname
// TODO send a new m.presence event with the updated displayname // TODO send a new m.presence event with the updated displayname
}
}
MatrixResult(Ok(set_display_name::Response)) MatrixResult(Ok(set_display_name::Response))
} }
#[get( #[get(
"/_matrix/client/r0/profile/<user_id_raw>/displayname", "/_matrix/client/r0/profile/<user_id_raw>/displayname",
data = "<body>" data = "<body>"
)] )]
fn get_displayname_route( fn get_displayname_route(
data: State<Data>, data: State<Data>,
@ -323,20 +334,26 @@ fn get_displayname_route(
user_id_raw: String, user_id_raw: String,
) -> MatrixResult<get_display_name::Response> { ) -> MatrixResult<get_display_name::Response> {
let user_id = (*body).user_id.clone(); let user_id = (*body).user_id.clone();
if let Some(displayname) = data.displayname_get(&user_id) { if !data.user_exists(&user_id) {
return MatrixResult(Ok(get_display_name::Response { // Return 404 if we don't have a profile for this id
displayname: Some(displayname),
}));
}
// Return 404 if we don't have any
debug!("Profile was not found."); debug!("Profile was not found.");
MatrixResult(Err(Error { MatrixResult(Err(Error {
kind: ErrorKind::NotFound, kind: ErrorKind::NotFound,
message: "Profile was not found".to_owned(), message: "Profile was not found".to_owned(),
status_code: http::StatusCode::NOT_FOUND, status_code: http::StatusCode::NOT_FOUND,
})) }))
}
if let Some(displayname) = data.displayname_get(&user_id) {
return MatrixResult(Ok(get_display_name::Response {
displayname: Some(displayname),
}));
}
MatrixResult(Ok(get_display_name::Response {
displayname: None,
}))
} }
#[put("/_matrix/client/r0/profile/<_user_id>/avatar_url", data = "<body>")] #[put("/_matrix/client/r0/profile/<_user_id>/avatar_url", data = "<body>")]
fn set_avatar_url_route( fn set_avatar_url_route(
data: State<Data>, data: State<Data>,
@ -344,22 +361,29 @@ fn set_avatar_url_route(
_user_id: String, _user_id: String,
) -> MatrixResult<set_avatar_url::Response> { ) -> MatrixResult<set_avatar_url::Response> {
let user_id = body.user_id.clone().expect("user is authenticated"); let user_id = body.user_id.clone().expect("user is authenticated");
if body.avatar_url == "" {
debug!("Request was missing the avatar_url payload."); if !body.avatar_url.starts_with("mxc://") {
debug!("Request contains an invalid avatar_url.");
return MatrixResult(Err(Error { return MatrixResult(Err(Error {
kind: ErrorKind::MissingParam, kind: ErrorKind::InvalidParam,
message: "Missing avatar_url".to_owned(), message: "Missing avatar_url".to_owned(),
status_code: http::StatusCode::BAD_REQUEST, status_code: http::StatusCode::BAD_REQUEST,
})); }));
} }
// TODO in the future when we can handle media uploads make sure that this url is our own server // TODO in the future when we can handle media uploads make sure that this url is our own server
// TODO also make sure this is mxc:// format // TODO also make sure this is valid mxc:// format (not only starting with it)
data.avatar_url_set(&user_id, body.avatar_url.clone());
if body.avatar_url == "" {
data.avatar_url_remove(&user_id);
} else {
data.avatar_url_set(&user_id, body.displayname.clone());
// TODO send a new m.room.member join event with the updated avatar_url // TODO send a new m.room.member join event with the updated avatar_url
// TODO send a new m.presence event with the updated avatar_url // TODO send a new m.presence event with the updated avatar_url
}
MatrixResult(Ok(set_avatar_url::Response)) MatrixResult(Ok(set_avatar_url::Response))
} }
@ -370,12 +394,7 @@ fn get_avatar_url_route(
user_id_raw: String, user_id_raw: String,
) -> MatrixResult<get_avatar_url::Response> { ) -> MatrixResult<get_avatar_url::Response> {
let user_id = (*body).user_id.clone(); let user_id = (*body).user_id.clone();
if let Some(avatar_url) = data.avatar_url_get(&user_id) { if !data.user_exists(&user_id) {
return MatrixResult(Ok(get_avatar_url::Response {
avatar_url: Some(avatar_url),
}));
}
// Return 404 if we don't have a profile for this id // Return 404 if we don't have a profile for this id
debug!("Profile was not found."); debug!("Profile was not found.");
MatrixResult(Err(Error { MatrixResult(Err(Error {
@ -383,6 +402,16 @@ fn get_avatar_url_route(
message: "Profile was not found".to_owned(), message: "Profile was not found".to_owned(),
status_code: http::StatusCode::NOT_FOUND, status_code: http::StatusCode::NOT_FOUND,
})) }))
}
if let Some(avatar_url) = data.avatar_url_get(&user_id) {
return MatrixResult(Ok(get_avatar_url::Response {
avatar_url: Some(avatar_url),
}));
}
MatrixResult(Ok(get_avatar_url::Response {
avatar_url: None,
}))
} }
#[get("/_matrix/client/r0/profile/<user_id_raw>", data = "<body>")] #[get("/_matrix/client/r0/profile/<user_id_raw>", data = "<body>")]
@ -395,7 +424,7 @@ fn get_profile_route(
let avatar_url = data.avatar_url_get(&user_id); let avatar_url = data.avatar_url_get(&user_id);
let displayname = data.displayname_get(&user_id); let displayname = data.displayname_get(&user_id);
if avatar_url.is_some() && displayname.is_some() { if avatar_url.is_some() || displayname.is_some() {
return MatrixResult(Ok(get_profile::Response { return MatrixResult(Ok(get_profile::Response {
avatar_url, avatar_url,
displayname, displayname,
@ -606,8 +635,8 @@ fn get_protocols_route(
} }
#[put( #[put(
"/_matrix/client/r0/rooms/<_room_id>/send/<_event_type>/<_txn_id>", "/_matrix/client/r0/rooms/<_room_id>/send/<_event_type>/<_txn_id>",
data = "<body>" data = "<body>"
)] )]
fn create_message_event_route( fn create_message_event_route(
data: State<Data>, data: State<Data>,
@ -631,8 +660,8 @@ fn create_message_event_route(
} }
#[put( #[put(
"/_matrix/client/r0/rooms/<_room_id>/state/<_event_type>/<_state_key>", "/_matrix/client/r0/rooms/<_room_id>/state/<_event_type>/<_state_key>",
data = "<body>" data = "<body>"
)] )]
fn create_state_event_for_key_route( fn create_state_event_for_key_route(
data: State<Data>, data: State<Data>,
@ -654,8 +683,8 @@ fn create_state_event_for_key_route(
} }
#[put( #[put(
"/_matrix/client/r0/rooms/<_room_id>/state/<_event_type>", "/_matrix/client/r0/rooms/<_room_id>/state/<_event_type>",
data = "<body>" data = "<body>"
)] )]
fn create_state_event_for_empty_key_route( fn create_state_event_for_empty_key_route(
data: State<Data>, data: State<Data>,