Skip to content

Commit

Permalink
Skip request stage on mutual follow
Browse files Browse the repository at this point in the history
If George follows you, and you want to follow George, you no longer have to get George's permission.

Closes #13
  • Loading branch information
dcramer committed May 18, 2023
1 parent 032289a commit c55d5a9
Show file tree
Hide file tree
Showing 2 changed files with 68 additions and 8 deletions.
43 changes: 43 additions & 0 deletions apps/api/src/routes/addUserFollow.test.ts
Expand Up @@ -96,3 +96,46 @@ test("can follow existing link", async () => {
expect(newFollow).toBeDefined();
expect(newFollow.status).toBe(follow.status);
});

test("automatically approves follow when mutual", async () => {
const otherUser = await Fixtures.User();
await Fixtures.Follow({
fromUserId: otherUser.id,
toUserId: DefaultFixtures.user.id,
status: "following",
});

const response = await app.inject({
method: "POST",
url: `/users/${otherUser.id}/follow`,
headers: DefaultFixtures.authHeaders,
});

expect(response).toRespondWith(200);
const data = JSON.parse(response.payload);
expect(data.status).toBe("following");

const [follow] = await db
.select()
.from(follows)
.where(
and(
eq(follows.fromUserId, DefaultFixtures.user.id),
eq(follows.toUserId, otherUser.id),
),
);
expect(follow).toBeDefined();
expect(follow.status).toBe("following");

const [notif] = await db
.select()
.from(notifications)
.where(
and(
eq(notifications.objectId, follow.id),
eq(notifications.objectType, objectTypeFromSchema(follows)),
),
);

expect(notif).toBeUndefined();
});
33 changes: 25 additions & 8 deletions apps/api/src/routes/addUserFollow.ts
Expand Up @@ -33,6 +33,21 @@ export default {
return res.status(404).send({ error: "Not found" });
}

// XXX: could make this a subquery to avoid a small race
const isFollowedBy =
(
await db
.select()
.from(follows)
.where(
and(
eq(follows.fromUserId, user.id),
eq(follows.toUserId, req.user.id),
eq(follows.status, "following"),
),
)
).length === 1;

const follow = await db.transaction(async (tx) => {
const follow =
first<Follow>(
Expand All @@ -41,6 +56,7 @@ export default {
.values({
fromUserId: req.user.id,
toUserId: user.id,
status: isFollowedBy ? "following" : "pending",
})
.onConflictDoNothing()
.returning(),
Expand All @@ -49,7 +65,7 @@ export default {
await tx
.update(follows)
.set({
status: "pending",
status: isFollowedBy ? "following" : "pending",
})
.where(
and(
Expand All @@ -72,13 +88,14 @@ export default {
)
)[0];

createNotification(tx, {
fromUserId: follow.fromUserId,
objectType: objectTypeFromSchema(follows),
objectId: follow.id,
createdAt: follow.createdAt,
userId: follow.toUserId,
});
if (follow.status === "pending")
createNotification(tx, {
fromUserId: follow.fromUserId,
objectType: objectTypeFromSchema(follows),
objectId: follow.id,
createdAt: follow.createdAt,
userId: follow.toUserId,
});

return follow;
});
Expand Down

0 comments on commit c55d5a9

Please sign in to comment.