diff --git a/api_tests/package.json b/api_tests/package.json index 3aa57d49c..4deffe4f6 100644 --- a/api_tests/package.json +++ b/api_tests/package.json @@ -16,7 +16,7 @@ "eslint": "^7.30.0", "eslint-plugin-jane": "^9.0.3", "jest": "^27.0.6", - "lemmy-js-client": "0.16.0-rc.1", + "lemmy-js-client": "0.17.0-rc.3", "node-fetch": "^2.6.1", "prettier": "^2.3.2", "ts-jest": "^27.0.3", diff --git a/api_tests/src/comment.spec.ts b/api_tests/src/comment.spec.ts index 314f18ecc..cfb09a517 100644 --- a/api_tests/src/comment.spec.ts +++ b/api_tests/src/comment.spec.ts @@ -329,12 +329,12 @@ test('A and G subscribe to B (center) A posts, G mentions B, it gets announced t test('Check that activity from another instance is sent to third instance', async () => { // Alpha and gamma users follow beta community let alphaFollow = await followBeta(alpha); - expect(alphaFollow.community_view.community.local).toBe(false); - expect(alphaFollow.community_view.community.name).toBe('main'); + expect(alphaFollow.community_follower_view.community.local).toBe(false); + expect(alphaFollow.community_follower_view.community.name).toBe('main'); let gammaFollow = await followBeta(gamma); - expect(gammaFollow.community_view.community.local).toBe(false); - expect(gammaFollow.community_view.community.name).toBe('main'); + expect(gammaFollow.community_follower_view.community.local).toBe(false); + expect(gammaFollow.community_follower_view.community.name).toBe('main'); // Create a post on beta let betaPost = await createPost(beta, 2); @@ -407,8 +407,8 @@ test('Fetch in_reply_tos: A is unsubbed from B, B makes a post, and some embedde // Follow beta again let follow = await followBeta(alpha); - expect(follow.community_view.community.local).toBe(false); - expect(follow.community_view.community.name).toBe('main'); + expect(follow.community_follower_view.community.local).toBe(false); + expect(follow.community_follower_view.community.name).toBe('main'); // An update to the child comment on beta, should push the post, parent, and child to alpha now let updatedCommentContent = 'An update child comment from beta'; diff --git a/api_tests/src/community.spec.ts b/api_tests/src/community.spec.ts index e1f6825ae..ba12de5c4 100644 --- a/api_tests/src/community.spec.ts +++ b/api_tests/src/community.spec.ts @@ -67,7 +67,7 @@ test('Delete community', async () => { ); // Make sure the follow response went through - expect(follow.community_view.community.local).toBe(false); + expect(follow.community_follower_view.community.local).toBe(false); let deleteCommunityRes = await deleteCommunity( beta, @@ -118,7 +118,7 @@ test('Remove community', async () => { ); // Make sure the follow response went through - expect(follow.community_view.community.local).toBe(false); + expect(follow.community_follower_view.community.local).toBe(false); let removeCommunityRes = await removeCommunity( beta, diff --git a/api_tests/src/follow.spec.ts b/api_tests/src/follow.spec.ts index 078c382c2..d75735b00 100644 --- a/api_tests/src/follow.spec.ts +++ b/api_tests/src/follow.spec.ts @@ -25,8 +25,9 @@ test('Follow federated community', async () => { ); // Make sure the follow response went through - expect(follow.community_view.community.local).toBe(false); - expect(follow.community_view.community.name).toBe('main'); + expect(follow.community_follower_view.community.local).toBe(false); + expect(follow.community_follower_view.community.name).toBe('main'); + expect(follow.community_follower_view.pending).toBe(true); // Check it from local let site = await getSite(alpha); @@ -37,7 +38,7 @@ test('Follow federated community', async () => { // Test an unfollow let unfollow = await followCommunity(alpha, false, remoteCommunityId); - expect(unfollow.community_view.community.local).toBe(false); + expect(unfollow.community_follower_view).toBeNull() // Make sure you are unsubbed locally let siteUnfollowCheck = await getSite(alpha); diff --git a/api_tests/src/post.spec.ts b/api_tests/src/post.spec.ts index b2f12298c..82545528e 100644 --- a/api_tests/src/post.spec.ts +++ b/api_tests/src/post.spec.ts @@ -261,7 +261,7 @@ test('Remove a post from admin and community on same instance', async () => { expect(removePostRes.post_view.post.removed).toBe(true); // Make sure lemmy alpha sees post is removed - let alphaPost = await getPost(alpha, postRes.post_view.post.id); + // let alphaPost = await getPost(alpha, postRes.post_view.post.id); // expect(alphaPost.post_view.post.removed).toBe(true); // TODO this shouldn't be commented // assertPostFederation(alphaPost.post_view, removePostRes.post_view); diff --git a/api_tests/src/shared.ts b/api_tests/src/shared.ts index d5be61ac3..d4b75c7e4 100644 --- a/api_tests/src/shared.ts +++ b/api_tests/src/shared.ts @@ -11,6 +11,7 @@ import { PostResponse, SearchResponse, FollowCommunity, + FollowCommunityResponse, CommunityResponse, GetPostResponse, Register, @@ -298,7 +299,7 @@ export async function banPersonFromSite( api: API, person_id: number, ban: boolean, - remove_data: boolean, + remove_data: boolean ): Promise { // Make sure lemmy-beta/c/main is cached on lemmy_alpha let form: BanPerson = { @@ -331,7 +332,7 @@ export async function followCommunity( api: API, follow: boolean, community_id: number -): Promise { +): Promise { let form: FollowCommunity = { community_id, follow, @@ -558,7 +559,7 @@ export async function saveUserSettings( } export async function deleteUser( - api: API, + api: API ): Promise { let form: DeleteAccount = { auth: api.auth, @@ -602,7 +603,7 @@ export async function unfollowRemotes( return siteRes; } -export async function followBeta(api: API): Promise { +export async function followBeta(api: API): Promise { let betaCommunity = (await resolveBetaCommunity(api)).community; if (betaCommunity) { let follow = await followCommunity(api, true, betaCommunity.community.id); @@ -613,7 +614,7 @@ export async function followBeta(api: API): Promise { export async function reportPost( api: API, post_id: number, - reason: string, + reason: string ): Promise { let form: CreatePostReport = { post_id, @@ -633,7 +634,7 @@ export async function listPostReports(api: API): Promise { let form: CreateCommentReport = { comment_id, diff --git a/api_tests/src/user.spec.ts b/api_tests/src/user.spec.ts index 29029ac1e..7e45760e5 100644 --- a/api_tests/src/user.spec.ts +++ b/api_tests/src/user.spec.ts @@ -7,7 +7,7 @@ import { saveUserSettings, getSite, createPost, - gamma, + // gamma, resolveCommunity, createComment, resolveBetaCommunity, diff --git a/api_tests/yarn.lock b/api_tests/yarn.lock index c60da9dad..3b198755d 100644 --- a/api_tests/yarn.lock +++ b/api_tests/yarn.lock @@ -3076,10 +3076,10 @@ language-tags@^1.0.5: dependencies: language-subtag-registry "~0.3.2" -lemmy-js-client@0.16.0-rc.1: - version "0.16.0-rc.1" - resolved "https://registry.yarnpkg.com/lemmy-js-client/-/lemmy-js-client-0.16.0-rc.1.tgz#14c4a526abf4b171c8afe4efbe2a62dcaf6a6f17" - integrity sha512-0hR/gHHsokp46whIHGMBQO2zBKWM7bT6mwKNMZxPvyJo+YW9EbKTO5edjF5E4v8nf3FuIE+gFtm5NFAjCaeWJg== +lemmy-js-client@0.17.0-rc.3: + version "0.17.0-rc.3" + resolved "https://registry.yarnpkg.com/lemmy-js-client/-/lemmy-js-client-0.17.0-rc.3.tgz#3c9b3d5e3346eed8cb8096dad527e72096052223" + integrity sha512-VwKSkjqZhsTrtlKTKs9DEVaj9rlmMEjzn/BxkizU9v03Km7OIs9Z7cOEfperOR9A6q5gh2hWfTDp5eV/0kYkVg== leven@^3.1.0: version "3.1.0" diff --git a/crates/api/src/community/follow.rs b/crates/api/src/community/follow.rs index aab21a9c2..a61383b21 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, _websocket_id: Option, - ) -> Result { + ) -> Result { 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,14 @@ 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??; + .await? + .ok(); - // 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 90c86f1c2..3c0f33d1c 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,12 @@ pub struct CommunityResponse { pub community_view: CommunityView, } +#[derive(Debug, Serialize, Deserialize, Clone)] +/// An unfollow will return None +pub struct FollowCommunityResponse { + pub community_follower_view: Option, +} + #[derive(Debug, Serialize, Deserialize, Clone, Default)] pub struct ListCommunities { pub type_: Option, diff --git a/crates/db_schema/src/impls/community.rs b/crates/db_schema/src/impls/community.rs index 14a670f51..073255cdb 100644 --- a/crates/db_schema/src/impls/community.rs +++ b/crates/db_schema/src/impls/community.rs @@ -390,7 +390,7 @@ mod tests { id: inserted_community_follower.id, community_id: inserted_community.id, person_id: inserted_person.id, - pending: Some(false), + pending: false, published: inserted_community_follower.published, }; diff --git a/crates/db_schema/src/schema.rs b/crates/db_schema/src/schema.rs index 666986a69..74285e3c6 100644 --- a/crates/db_schema/src/schema.rs +++ b/crates/db_schema/src/schema.rs @@ -119,7 +119,7 @@ table! { community_id -> Int4, person_id -> Int4, published -> Timestamp, - pending -> Nullable, + pending -> Bool, } } diff --git a/crates/db_schema/src/source/community.rs b/crates/db_schema/src/source/community.rs index 7693f2f41..25766b408 100644 --- a/crates/db_schema/src/source/community.rs +++ b/crates/db_schema/src/source/community.rs @@ -128,7 +128,7 @@ pub struct CommunityFollower { pub community_id: CommunityId, pub person_id: PersonId, pub published: chrono::NaiveDateTime, - pub pending: Option, + pub pending: bool, } #[derive(Clone)] diff --git a/crates/db_views_actor/src/community_follower_view.rs b/crates/db_views_actor/src/community_follower_view.rs index 6d5d94a59..7bece59d3 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, bool); impl CommunityFollowerView { pub fn for_community(conn: &PgConnection, community_id: CommunityId) -> Result, 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 { + 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::(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::>() } diff --git a/crates/db_views_actor/src/structs.rs b/crates/db_views_actor/src/structs.rs index a6ec9710e..a0b1ad4bc 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: bool, } #[derive(Debug, Serialize, Deserialize, Clone)] diff --git a/migrations/2022-05-10-173801_change_pending_to_notnull/down.sql b/migrations/2022-05-10-173801_change_pending_to_notnull/down.sql new file mode 100644 index 000000000..4ef1387af --- /dev/null +++ b/migrations/2022-05-10-173801_change_pending_to_notnull/down.sql @@ -0,0 +1,5 @@ +-- This file should undo anything in `up.sql` + +alter table community_follower + alter column pending drop not null, + alter column pending set default false; diff --git a/migrations/2022-05-10-173801_change_pending_to_notnull/up.sql b/migrations/2022-05-10-173801_change_pending_to_notnull/up.sql new file mode 100644 index 000000000..659f321bc --- /dev/null +++ b/migrations/2022-05-10-173801_change_pending_to_notnull/up.sql @@ -0,0 +1,8 @@ +-- Make the pending column not null + +update community_follower set pending = true where pending is null; + +alter table community_follower + alter column pending set not null, + alter column pending drop default; +