diff --git a/crates/app/src/public/html/post/post.lisp b/crates/app/src/public/html/post/post.lisp index b43fc82..81a16a9 100644 --- a/crates/app/src/public/html/post/post.lisp +++ b/crates/app/src/public/html/post/post.lisp @@ -71,7 +71,6 @@ ("name" "content") ("id" "content") ("placeholder" "content") - ("required" "") ("minlength" "2") ("maxlength" "4096"))) (div diff --git a/crates/app/src/public/html/profile/base.lisp b/crates/app/src/public/html/profile/base.lisp index c482033..51f8489 100644 --- a/crates/app/src/public/html/profile/base.lisp +++ b/crates/app/src/public/html/profile/base.lisp @@ -290,7 +290,7 @@ ]); fetch( - \"/api/v1/auth/user/{{ profile.id }}/follow\", + \"/api/v1/auth/user/{{ profile.id }}/follow/toggle\", { method: \"POST\", }, diff --git a/crates/app/src/public/html/profile/private.lisp b/crates/app/src/public/html/profile/private.lisp index 8bd94e9..4654298 100644 --- a/crates/app/src/public/html/profile/private.lisp +++ b/crates/app/src/public/html/profile/private.lisp @@ -81,7 +81,7 @@ (script (text "globalThis.toggle_follow_user = async (e) => { await trigger(\"atto::debounce\", [\"users::follow\"]); - fetch(\"/api/v1/auth/user/{{ profile.id }}/follow\", { + fetch(\"/api/v1/auth/user/{{ profile.id }}/follow/toggle\", { method: \"POST\", }) .then((res) => res.json()) diff --git a/crates/app/src/public/js/me.js b/crates/app/src/public/js/me.js index e7fa2d6..99fda4e 100644 --- a/crates/app/src/public/js/me.js +++ b/crates/app/src/public/js/me.js @@ -193,9 +193,13 @@ like.classList.add("green"); like.querySelector("svg").classList.add("filled"); - dislike.classList.remove("red"); + if (dislike) { + dislike.classList.remove("red"); + } } else { - dislike.classList.add("red"); + if (dislike) { + dislike.classList.add("red"); + } like.classList.remove("green"); like.querySelector("svg").classList.remove("filled"); diff --git a/crates/app/src/routes/api/v1/auth/social.rs b/crates/app/src/routes/api/v1/auth/social.rs index 17ca6cf..86a601d 100644 --- a/crates/app/src/routes/api/v1/auth/social.rs +++ b/crates/app/src/routes/api/v1/auth/social.rs @@ -17,7 +17,7 @@ use tetratto_core::model::{ }; /// Toggle following on the given user. -pub async fn follow_request( +pub async fn toggle_follow_request( jar: CookieJar, Path(id): Path, Extension(data): Extension, @@ -154,6 +154,71 @@ pub async fn accept_follow_request( } } +pub async fn follow_request( + jar: CookieJar, + Path(id): Path, + Extension(data): Extension, +) -> impl IntoResponse { + let data = &(data.read().await).0; + let mut user = match get_user_from_token!(jar, data, oauth::AppScope::UserManageFollowing) { + Some(ua) => ua, + None => return Json(Error::NotAllowed.into()), + }; + + if data + .get_userfollow_by_initiator_receiver(user.id, id) + .await + .is_ok() + { + return Json(Error::MiscError("Already following user".to_string()).into()); + } else { + match data + .create_userfollow(UserFollow::new(user.id, id), &user, false) + .await + { + Ok(r) => { + if r == FollowResult::Followed { + if let Err(e) = data + .create_notification(Notification::new( + "Somebody has followed you!".to_string(), + format!( + "You have been followed by [@{}](/api/v1/auth/user/find/{}).", + user.username, user.id + ), + id, + )) + .await + { + return Json(e.into()); + }; + + // award achievement + if let Err(e) = data + .add_achievement(&mut user, AchievementName::FollowUser.into(), true) + .await + { + return Json(e.into()); + } + + // ... + Json(ApiReturn { + ok: true, + message: "User followed".to_string(), + payload: (), + }) + } else { + Json(ApiReturn { + ok: true, + message: "Asked to follow user".to_string(), + payload: (), + }) + } + } + Err(e) => Json(e.into()), + } + } +} + pub async fn force_unfollow_me_request( jar: CookieJar, Path(id): Path, diff --git a/crates/app/src/routes/api/v1/mod.rs b/crates/app/src/routes/api/v1/mod.rs index 0fbfc40..d59fe26 100644 --- a/crates/app/src/routes/api/v1/mod.rs +++ b/crates/app/src/routes/api/v1/mod.rs @@ -285,6 +285,10 @@ pub fn routes() -> Router { .route("/auth/user/{id}/avatar", get(auth::images::avatar_request)) .route("/auth/user/{id}/banner", get(auth::images::banner_request)) .route("/auth/user/{id}/follow", post(auth::social::follow_request)) + .route( + "/auth/user/{id}/follow/toggle", + post(auth::social::toggle_follow_request), + ) .route( "/auth/user/{id}/follow/cancel", post(auth::social::cancel_follow_request), diff --git a/justfile b/justfile index 56aa26b..a83d0c4 100644 --- a/justfile +++ b/justfile @@ -10,6 +10,5 @@ doc: cargo doc --document-private-items --no-deps test: - sudo pkill -e tetratto cd example && LITTLEWEB=true PORT=4119 cargo run & cd example && cargo run