diff --git a/backend/data/follows.py b/backend/data/follows.py index a4b6314e..15e62c42 100644 --- a/backend/data/follows.py +++ b/backend/data/follows.py @@ -41,3 +41,13 @@ def get_inverse_followed_usernames(followee: User) -> List[str]: ) rows = cur.fetchall() return [row[0] for row in rows] + +def unfollow(follower: User, followee: User): + with db_cursor() as cur: + cur.execute( + "DELETE FROM follows WHERE follower = %(follower_id)s AND followee = %(followee_id)s", + dict( + follower_id=follower.id, + followee_id=followee.id, + ), + ) \ No newline at end of file diff --git a/backend/endpoints.py b/backend/endpoints.py index 0e177a07..bd9d39df 100644 --- a/backend/endpoints.py +++ b/backend/endpoints.py @@ -1,6 +1,6 @@ from typing import Dict, Union from data import blooms -from data.follows import follow, get_followed_usernames, get_inverse_followed_usernames +from data.follows import follow, unfollow, get_followed_usernames, get_inverse_followed_usernames from data.users import ( UserRegistrationError, get_suggested_follows, @@ -245,3 +245,21 @@ def verify_request_fields(names_to_types: Dict[str, type]) -> Union[Response, No ) ) return None + +@jwt_required() +def do_unfollow(profile_username): + current_user = get_current_user() + + follow_user = get_user(profile_username) + if follow_user is None: + return make_response( + (f"Cannot unfollow {profile_username} - user does not exist", 404) + ) + + unfollow(current_user, follow_user) + + return jsonify( + { + "success": True, + } + ) \ No newline at end of file diff --git a/backend/main.py b/backend/main.py index 7ba155fa..cdfefd09 100644 --- a/backend/main.py +++ b/backend/main.py @@ -4,6 +4,7 @@ from data.users import lookup_user from endpoints import ( do_follow, + do_unfollow, get_bloom, hashtag, home_timeline, @@ -60,6 +61,11 @@ def main(): app.add_url_rule("/bloom/", methods=["GET"], view_func=get_bloom) app.add_url_rule("/blooms/", view_func=user_blooms) app.add_url_rule("/hashtag/", view_func=hashtag) + app.add_url_rule( + "/unfollow/", + methods=["POST"], + view_func=do_unfollow, +) app.run(host="0.0.0.0", port="3000", debug=True) diff --git a/front-end/components/profile.mjs b/front-end/components/profile.mjs index ec4f2009..ca27f9d2 100644 --- a/front-end/components/profile.mjs +++ b/front-end/components/profile.mjs @@ -27,7 +27,10 @@ function createProfile(template, {profileData, whoToFollow, isLoggedIn}) { followerCountEl.textContent = profileData.followers?.length || 0; followingCountEl.textContent = profileData.follows?.length || 0; followButtonEl.setAttribute("data-username", profileData.username || ""); - followButtonEl.hidden = profileData.is_self || profileData.is_following; + followButtonEl.hidden = profileData.is_self; + followButtonEl.textContent = profileData.is_following + ? "Unfollow" + : "Follow"; followButtonEl.addEventListener("click", handleFollow); if (!isLoggedIn) { followButtonEl.style.display = "none"; @@ -62,7 +65,12 @@ async function handleFollow(event) { const username = button.getAttribute("data-username"); if (!username) return; - await apiService.followUser(username); + if (button.textContent === "Unfollow") { + await apiService.unfollowUser(username); + } else { + await apiService.followUser(username); + } + await apiService.getWhoToFollow(); }