forked from jmug/stoatchat
131 lines
3.8 KiB
Rust
131 lines
3.8 KiB
Rust
use revolt_database::FieldsUser;
|
|
use revolt_database::{util::reference::Reference, Database, File, PartialUser, User};
|
|
use revolt_models::v0;
|
|
use revolt_result::{create_error, Result};
|
|
use rocket::serde::json::Json;
|
|
use rocket::State;
|
|
use validator::Validate;
|
|
|
|
/// # Edit User
|
|
///
|
|
/// Edit currently authenticated user.
|
|
#[openapi(tag = "User Information")]
|
|
#[patch("/<target>", data = "<data>")]
|
|
pub async fn edit(
|
|
db: &State<Database>,
|
|
mut user: User,
|
|
target: Reference,
|
|
data: Json<v0::DataEditUser>,
|
|
) -> Result<Json<v0::User>> {
|
|
let data = data.into_inner();
|
|
data.validate().map_err(|error| {
|
|
create_error!(FailedValidation {
|
|
error: error.to_string()
|
|
})
|
|
})?;
|
|
|
|
// If we want to edit a different user than self, ensure we have
|
|
// permissions and subsequently replace the user in question
|
|
if target.id != "@me" && target.id != user.id {
|
|
let target_user = target.as_user(db).await?;
|
|
let is_bot_owner = target_user
|
|
.bot
|
|
.map(|bot| bot.owner == user.id)
|
|
.unwrap_or_default();
|
|
|
|
if !is_bot_owner && !user.privileged {
|
|
return Err(create_error!(NotPrivileged));
|
|
}
|
|
}
|
|
|
|
// Otherwise, filter out invalid edit fields
|
|
if !user.privileged && (data.badges.is_some() || data.flags.is_some()) {
|
|
return Err(create_error!(NotPrivileged));
|
|
}
|
|
|
|
// Exit out early if nothing is changed
|
|
if data.display_name.is_none()
|
|
&& data.status.is_none()
|
|
&& data.profile.is_none()
|
|
&& data.avatar.is_none()
|
|
&& data.badges.is_none()
|
|
&& data.flags.is_none()
|
|
&& data.remove.is_none()
|
|
{
|
|
return Ok(Json(user.into_self(false).await));
|
|
}
|
|
|
|
// 1. Remove fields from object
|
|
if let Some(fields) = &data.remove {
|
|
if fields.contains(&v0::FieldsUser::Avatar) {
|
|
if let Some(avatar) = &user.avatar {
|
|
db.mark_attachment_as_deleted(&avatar.id).await?;
|
|
}
|
|
}
|
|
|
|
if fields.contains(&v0::FieldsUser::ProfileBackground) {
|
|
if let Some(profile) = &user.profile {
|
|
if let Some(background) = &profile.background {
|
|
db.mark_attachment_as_deleted(&background.id).await?;
|
|
}
|
|
}
|
|
}
|
|
|
|
for field in fields {
|
|
let field: FieldsUser = field.clone().into();
|
|
user.remove_field(&field);
|
|
}
|
|
}
|
|
|
|
let mut partial: PartialUser = PartialUser {
|
|
display_name: data.display_name,
|
|
badges: data.badges,
|
|
flags: data.flags,
|
|
..Default::default()
|
|
};
|
|
|
|
// 2. Apply new avatar
|
|
if let Some(avatar) = data.avatar {
|
|
partial.avatar = Some(File::use_avatar(db, &avatar, &user.id).await?);
|
|
}
|
|
|
|
// 3. Apply new status
|
|
if let Some(status) = data.status {
|
|
let mut new_status = user.status.take().unwrap_or_default();
|
|
if let Some(text) = status.text {
|
|
new_status.text = Some(text);
|
|
}
|
|
|
|
if let Some(presence) = status.presence {
|
|
new_status.presence = Some(presence.into());
|
|
}
|
|
|
|
partial.status = Some(new_status);
|
|
}
|
|
|
|
// 4. Apply new profile
|
|
if let Some(profile) = data.profile {
|
|
let mut new_profile = user.profile.take().unwrap_or_default();
|
|
if let Some(content) = profile.content {
|
|
new_profile.content = Some(content);
|
|
}
|
|
|
|
if let Some(background) = profile.background {
|
|
new_profile.background = Some(File::use_background(db, &background, &user.id).await?);
|
|
}
|
|
|
|
partial.profile = Some(new_profile);
|
|
}
|
|
|
|
user.update(
|
|
db,
|
|
partial,
|
|
data.remove
|
|
.map(|v| v.into_iter().map(Into::into).collect())
|
|
.unwrap_or_default(),
|
|
)
|
|
.await?;
|
|
|
|
Ok(Json(user.into_self(false).await))
|
|
}
|