From cb61f4a86bc96250a44fe9bf5da02c99f69c42d7 Mon Sep 17 00:00:00 2001 From: Rafael Caricio Date: Thu, 27 Apr 2023 13:38:49 +0200 Subject: [PATCH] Allow mute accounts --- .../src/relationships/queries.rs | 38 +++++++++++++++++++ fedimovies-models/src/relationships/types.rs | 3 ++ src/mastodon_api/accounts/helpers.rs | 5 +++ src/mastodon_api/accounts/types.rs | 2 + src/mastodon_api/accounts/views.rs | 38 +++++++++++++++++++ src/mastodon_api/instance/types.rs | 4 +- 6 files changed, 89 insertions(+), 1 deletion(-) diff --git a/fedimovies-models/src/relationships/queries.rs b/fedimovies-models/src/relationships/queries.rs index 484afa3..37cae8b 100644 --- a/fedimovies-models/src/relationships/queries.rs +++ b/fedimovies-models/src/relationships/queries.rs @@ -614,6 +614,44 @@ pub async fn show_replies( Ok(()) } +pub async fn mute_posts( + db_client: &impl DatabaseClient, + source_id: &Uuid, + target_id: &Uuid, +) -> Result<(), DatabaseError> { + db_client + .execute( + " + INSERT INTO relationship (source_id, target_id, relationship_type) + VALUES ($1, $2, $3) + ON CONFLICT (source_id, target_id, relationship_type) DO NOTHING + ", + &[&source_id, &target_id, &RelationshipType::Mute], + ) + .await?; + Ok(()) +} + +pub async fn unmute_posts( + db_client: &impl DatabaseClient, + source_id: &Uuid, + target_id: &Uuid, +) -> Result<(), DatabaseError> { + // Does not return NotFound error + db_client + .execute( + " + DELETE FROM relationship + WHERE + source_id = $1 AND target_id = $2 + AND relationship_type = $3 + ", + &[&source_id, &target_id, &RelationshipType::Mute], + ) + .await?; + Ok(()) +} + #[cfg(test)] mod tests { use super::*; diff --git a/fedimovies-models/src/relationships/types.rs b/fedimovies-models/src/relationships/types.rs index 15317c6..0452a67 100644 --- a/fedimovies-models/src/relationships/types.rs +++ b/fedimovies-models/src/relationships/types.rs @@ -17,6 +17,7 @@ pub enum RelationshipType { Subscription, HideReposts, HideReplies, + Mute, } impl From<&RelationshipType> for i16 { @@ -27,6 +28,7 @@ impl From<&RelationshipType> for i16 { RelationshipType::Subscription => 3, RelationshipType::HideReposts => 4, RelationshipType::HideReplies => 5, + RelationshipType::Mute => 6, } } } @@ -41,6 +43,7 @@ impl TryFrom for RelationshipType { 3 => Self::Subscription, 4 => Self::HideReposts, 5 => Self::HideReplies, + 6 => Self::Mute, _ => return Err(DatabaseTypeError), }; Ok(relationship_type) diff --git a/src/mastodon_api/accounts/helpers.rs b/src/mastodon_api/accounts/helpers.rs index e6958b5..412137f 100644 --- a/src/mastodon_api/accounts/helpers.rs +++ b/src/mastodon_api/accounts/helpers.rs @@ -52,6 +52,11 @@ pub async fn get_relationship( relationship_map.showing_replies = false; }; } + RelationshipType::Mute => { + if relationship.is_direct(source_id, target_id)? { + relationship_map.muting = true; + }; + } }; } Ok(relationship_map) diff --git a/src/mastodon_api/accounts/types.rs b/src/mastodon_api/accounts/types.rs index 765970f..8786724 100644 --- a/src/mastodon_api/accounts/types.rs +++ b/src/mastodon_api/accounts/types.rs @@ -402,6 +402,7 @@ pub struct RelationshipMap { pub subscription_from: bool, pub showing_reblogs: bool, pub showing_replies: bool, + pub muting: bool, } fn default_showing_reblogs() -> bool { @@ -423,6 +424,7 @@ impl Default for RelationshipMap { subscription_from: false, showing_reblogs: default_showing_reblogs(), showing_replies: default_showing_replies(), + muting: false, } } } diff --git a/src/mastodon_api/accounts/views.rs b/src/mastodon_api/accounts/views.rs index 6448426..70c8a89 100644 --- a/src/mastodon_api/accounts/views.rs +++ b/src/mastodon_api/accounts/views.rs @@ -3,6 +3,7 @@ use actix_web_httpauth::extractors::bearer::BearerAuth; use uuid::Uuid; use fedimovies_config::{Config, DefaultRole, RegistrationType}; +use fedimovies_models::relationships::queries::{mute_posts, unmute_posts}; use fedimovies_models::{ database::{get_database_client, DatabaseError, DbPool}, posts::queries::get_posts_by_author, @@ -367,6 +368,41 @@ async fn unfollow_account( Ok(HttpResponse::Ok().json(relationship)) } +#[post("/{account_id}/mute")] +async fn mute_account( + auth: BearerAuth, + db_pool: web::Data, + account_id: web::Path, +) -> Result { + let db_client = &mut **get_database_client(&db_pool).await?; + let current_user = get_current_user(db_client, auth.token()).await?; + let target = get_profile_by_id(db_client, &account_id).await?; + + mute_posts(db_client, ¤t_user.id, &target.id).await?; + + let relationship = get_relationship(db_client, ¤t_user.id, &target.id).await?; + Ok(HttpResponse::Ok().json(relationship)) +} + +#[post("/{account_id}/unmute")] +async fn unmute_account( + auth: BearerAuth, + db_pool: web::Data, + account_id: web::Path, +) -> Result { + let db_client = &mut **get_database_client(&db_pool).await?; + let current_user = get_current_user(db_client, auth.token()).await?; + let target = get_profile_by_id(db_client, &account_id).await?; + match unmute_posts(db_client, ¤t_user.id, &target.id).await { + Ok(()) => (), + Err(DatabaseError::NotFound(_)) => (), // not following + Err(other_error) => return Err(other_error.into()), + }; + + let relationship = get_relationship(db_client, ¤t_user.id, &target.id).await?; + Ok(HttpResponse::Ok().json(relationship)) +} + #[get("/{account_id}/statuses")] async fn get_account_statuses( auth: Option, @@ -566,6 +602,8 @@ pub fn account_api_scope() -> Scope { .service(get_account) .service(follow_account) .service(unfollow_account) + .service(mute_account) + .service(unmute_account) .service(get_account_statuses) .service(get_account_followers) .service(get_account_following) diff --git a/src/mastodon_api/instance/types.rs b/src/mastodon_api/instance/types.rs index b96ba71..5e18c49 100644 --- a/src/mastodon_api/instance/types.rs +++ b/src/mastodon_api/instance/types.rs @@ -18,6 +18,7 @@ struct InstanceStats { struct InstanceStatusLimits { max_characters: usize, max_media_attachments: usize, + characters_reserved_per_url: usize, } #[derive(Serialize)] @@ -105,6 +106,7 @@ impl InstanceInfo { statuses: InstanceStatusLimits { max_characters: config.limits.posts.character_limit, max_media_attachments: ATTACHMENT_LIMIT, + characters_reserved_per_url: 32, // not real, but for compatibility }, media_attachments: InstanceMediaLimits { supported_mime_types: SUPPORTED_MEDIA_TYPES @@ -117,7 +119,7 @@ impl InstanceInfo { }, thumbnail: None, email: "".to_string(), - languages: vec![], + languages: vec!["en".to_string()], rules: vec![], urls: None, login_message: config.login_message.clone(),