From 48f5a2ee5e44f381e86b11f148f2e2a99ac94ef6 Mon Sep 17 00:00:00 2001
From: Dessalines <tyhou13@gmx.com>
Date: Fri, 6 May 2022 17:37:53 -0400
Subject: [PATCH] Add pending, and change use specific API response for
 FollowCommunity. Fixes #2246

---
 crates/api/src/community/follow.rs            | 25 +++++++---------
 crates/api_common/src/community.rs            | 12 +++++++-
 .../src/community_follower_view.rs            | 29 ++++++++++++++++++-
 crates/db_views_actor/src/structs.rs          |  1 +
 4 files changed, 50 insertions(+), 17 deletions(-)

diff --git a/crates/api/src/community/follow.rs b/crates/api/src/community/follow.rs
index aab21a9c..df9fae3c 100644
--- a/crates/api/src/community/follow.rs
+++ b/crates/api/src/community/follow.rs
@@ -1,7 +1,7 @@
 use crate::Perform;
 use actix_web::web::Data;
 use lemmy_api_common::{
-  community::{CommunityResponse, FollowCommunity},
+  community::{FollowCommunity, FollowCommunityResponse},
   utils::{
     blocking,
     check_community_ban,
@@ -20,20 +20,20 @@ use lemmy_db_schema::{
   source::community::{Community, CommunityFollower, CommunityFollowerForm},
   traits::{Crud, Followable},
 };
-use lemmy_db_views_actor::structs::CommunityView;
+use lemmy_db_views_actor::structs::CommunityFollowerView;
 use lemmy_utils::{ConnectionId, LemmyError};
 use lemmy_websocket::LemmyContext;
 
 #[async_trait::async_trait(?Send)]
 impl Perform for FollowCommunity {
-  type Response = CommunityResponse;
+  type Response = FollowCommunityResponse;
 
   #[tracing::instrument(skip(context, _websocket_id))]
   async fn perform(
     &self,
     context: &Data<LemmyContext>,
     _websocket_id: Option<ConnectionId>,
-  ) -> Result<CommunityResponse, LemmyError> {
+  ) -> Result<Self::Response, LemmyError> {
     let data: &FollowCommunity = self;
     let local_user_view =
       get_local_user_view_from_jwt(&data.auth, context.pool(), context.secret()).await?;
@@ -47,7 +47,7 @@ impl Perform for FollowCommunity {
     let community_follower_form = CommunityFollowerForm {
       community_id: data.community_id,
       person_id: local_user_view.person.id,
-      pending: false,
+      pending: false, // Don't worry, this form isn't used for remote follows
     };
 
     if community.local {
@@ -82,18 +82,13 @@ impl Perform for FollowCommunity {
 
     let community_id = data.community_id;
     let person_id = local_user_view.person.id;
-    let mut community_view = blocking(context.pool(), move |conn| {
-      CommunityView::read(conn, community_id, Some(person_id))
+    let community_follower_view = blocking(context.pool(), move |conn| {
+      CommunityFollowerView::read(conn, community_id, person_id)
     })
     .await??;
 
-    // TODO: this needs to return a "pending" state, until Accept is received from the remote server
-    // For now, just assume that remote follows are accepted.
-    // Otherwise, the subscribed will be null
-    if !community.local {
-      community_view.subscribed = data.follow;
-    }
-
-    Ok(CommunityResponse { community_view })
+    Ok(Self::Response {
+      community_follower_view,
+    })
   }
 }
diff --git a/crates/api_common/src/community.rs b/crates/api_common/src/community.rs
index 90c86f1c..a4b5e2e6 100644
--- a/crates/api_common/src/community.rs
+++ b/crates/api_common/src/community.rs
@@ -5,7 +5,12 @@ use lemmy_db_schema::{
   ListingType,
   SortType,
 };
-use lemmy_db_views_actor::structs::{CommunityModeratorView, CommunityView, PersonViewSafe};
+use lemmy_db_views_actor::structs::{
+  CommunityFollowerView,
+  CommunityModeratorView,
+  CommunityView,
+  PersonViewSafe,
+};
 use serde::{Deserialize, Serialize};
 
 #[derive(Debug, Serialize, Deserialize, Clone, Default)]
@@ -41,6 +46,11 @@ pub struct CommunityResponse {
   pub community_view: CommunityView,
 }
 
+#[derive(Debug, Serialize, Deserialize, Clone)]
+pub struct FollowCommunityResponse {
+  pub community_follower_view: CommunityFollowerView,
+}
+
 #[derive(Debug, Serialize, Deserialize, Clone, Default)]
 pub struct ListCommunities {
   pub type_: Option<ListingType>,
diff --git a/crates/db_views_actor/src/community_follower_view.rs b/crates/db_views_actor/src/community_follower_view.rs
index 6d5d94a5..7e37e446 100644
--- a/crates/db_views_actor/src/community_follower_view.rs
+++ b/crates/db_views_actor/src/community_follower_view.rs
@@ -10,7 +10,7 @@ use lemmy_db_schema::{
   traits::{ToSafe, ViewToVec},
 };
 
-type CommunityFollowerViewTuple = (CommunitySafe, PersonSafe);
+type CommunityFollowerViewTuple = (CommunitySafe, PersonSafe, Option<bool>);
 
 impl CommunityFollowerView {
   pub fn for_community(conn: &PgConnection, community_id: CommunityId) -> Result<Vec<Self>, Error> {
@@ -20,6 +20,7 @@ impl CommunityFollowerView {
       .select((
         Community::safe_columns_tuple(),
         Person::safe_columns_tuple(),
+        community_follower::pending,
       ))
       .filter(community_follower::community_id.eq(community_id))
       .order_by(community::title)
@@ -35,6 +36,7 @@ impl CommunityFollowerView {
       .select((
         Community::safe_columns_tuple(),
         Person::safe_columns_tuple(),
+        community_follower::pending,
       ))
       .filter(community_follower::person_id.eq(person_id))
       .order_by(community::title)
@@ -42,6 +44,30 @@ impl CommunityFollowerView {
 
     Ok(Self::from_tuple_to_vec(res))
   }
+
+  pub fn read(
+    conn: &PgConnection,
+    community_id: CommunityId,
+    person_id: PersonId,
+  ) -> Result<Self, Error> {
+    let (community, follower, pending) = community_follower::table
+      .inner_join(community::table)
+      .inner_join(person::table)
+      .select((
+        Community::safe_columns_tuple(),
+        Person::safe_columns_tuple(),
+        community_follower::pending,
+      ))
+      .filter(community_follower::person_id.eq(person_id))
+      .filter(community_follower::community_id.eq(community_id))
+      .first::<CommunityFollowerViewTuple>(conn)?;
+
+    Ok(Self {
+      community,
+      follower,
+      pending,
+    })
+  }
 }
 
 impl ViewToVec for CommunityFollowerView {
@@ -52,6 +78,7 @@ impl ViewToVec for CommunityFollowerView {
       .map(|a| Self {
         community: a.0.to_owned(),
         follower: a.1.to_owned(),
+        pending: a.2.to_owned(),
       })
       .collect::<Vec<Self>>()
   }
diff --git a/crates/db_views_actor/src/structs.rs b/crates/db_views_actor/src/structs.rs
index a6ec9710..25d2c178 100644
--- a/crates/db_views_actor/src/structs.rs
+++ b/crates/db_views_actor/src/structs.rs
@@ -20,6 +20,7 @@ pub struct CommunityBlockView {
 pub struct CommunityFollowerView {
   pub community: CommunitySafe,
   pub follower: PersonSafe,
+  pub pending: Option<bool>,
 }
 
 #[derive(Debug, Serialize, Deserialize, Clone)]
-- 
2.44.1