feat: add visibility feature to thoughts, including new enum, database migration, and update related endpoints and tests
This commit is contained in:
@@ -1,8 +1,10 @@
|
||||
mod auth;
|
||||
mod json;
|
||||
mod optional_auth;
|
||||
mod valid;
|
||||
|
||||
pub use auth::AuthUser;
|
||||
pub use auth::Claims;
|
||||
pub use json::Json;
|
||||
pub use optional_auth::OptionalAuthUser;
|
||||
pub use valid::Valid;
|
||||
|
21
thoughts-backend/api/src/extractor/optional_auth.rs
Normal file
21
thoughts-backend/api/src/extractor/optional_auth.rs
Normal file
@@ -0,0 +1,21 @@
|
||||
use super::AuthUser;
|
||||
use crate::error::ApiError;
|
||||
use app::state::AppState;
|
||||
use axum::{extract::FromRequestParts, http::request::Parts};
|
||||
|
||||
pub struct OptionalAuthUser(pub Option<AuthUser>);
|
||||
|
||||
impl FromRequestParts<AppState> for OptionalAuthUser {
|
||||
type Rejection = ApiError;
|
||||
|
||||
async fn from_request_parts(
|
||||
parts: &mut Parts,
|
||||
state: &AppState,
|
||||
) -> Result<Self, Self::Rejection> {
|
||||
match AuthUser::from_request_parts(parts, state).await {
|
||||
Ok(user) => Ok(OptionalAuthUser(Some(user))),
|
||||
// If the user is not authenticated for any reason, we just treat them as a guest.
|
||||
Err(_) => Ok(OptionalAuthUser(None)),
|
||||
}
|
||||
}
|
||||
}
|
@@ -24,9 +24,11 @@ async fn feed_get(
|
||||
auth_user: AuthUser,
|
||||
) -> Result<impl IntoResponse, ApiError> {
|
||||
let following_ids = get_following_ids(&state.conn, auth_user.id).await?;
|
||||
let mut thoughts_with_authors = get_feed_for_user(&state.conn, following_ids).await?;
|
||||
let mut thoughts_with_authors =
|
||||
get_feed_for_user(&state.conn, following_ids, Some(auth_user.id)).await?;
|
||||
|
||||
let own_thoughts = get_feed_for_user(&state.conn, vec![auth_user.id]).await?;
|
||||
let own_thoughts =
|
||||
get_feed_for_user(&state.conn, vec![auth_user.id], Some(auth_user.id)).await?;
|
||||
thoughts_with_authors.extend(own_thoughts);
|
||||
|
||||
let thoughts_schema: Vec<ThoughtSchema> = thoughts_with_authors
|
||||
|
@@ -1,4 +1,4 @@
|
||||
use crate::error::ApiError;
|
||||
use crate::{error::ApiError, extractor::OptionalAuthUser};
|
||||
use app::{
|
||||
persistence::{tag, thought::get_thoughts_by_tag_name},
|
||||
state::AppState,
|
||||
@@ -20,8 +20,10 @@ use models::schemas::thought::{ThoughtListSchema, ThoughtSchema};
|
||||
async fn get_thoughts_by_tag(
|
||||
State(state): State<AppState>,
|
||||
Path(tag_name): Path<String>,
|
||||
viewer: OptionalAuthUser,
|
||||
) -> Result<impl IntoResponse, ApiError> {
|
||||
let thoughts_with_authors = get_thoughts_by_tag_name(&state.conn, &tag_name).await;
|
||||
let thoughts_with_authors =
|
||||
get_thoughts_by_tag_name(&state.conn, &tag_name, viewer.0.map(|u| u.id)).await;
|
||||
let thoughts_with_authors = thoughts_with_authors?;
|
||||
let thoughts_schema: Vec<ThoughtSchema> = thoughts_with_authors
|
||||
.into_iter()
|
||||
|
@@ -19,8 +19,8 @@ use models::schemas::user::{UserListSchema, UserSchema};
|
||||
use models::{params::user::UpdateUserParams, schemas::thought::ThoughtListSchema};
|
||||
use models::{queries::user::UserQuery, schemas::thought::ThoughtSchema};
|
||||
|
||||
use crate::models::ApiErrorResponse;
|
||||
use crate::{error::ApiError, extractor::AuthUser};
|
||||
use crate::{extractor::OptionalAuthUser, models::ApiErrorResponse};
|
||||
use crate::{
|
||||
extractor::{Json, Valid},
|
||||
routers::api_key::create_api_key_router,
|
||||
@@ -63,12 +63,14 @@ async fn users_get(
|
||||
async fn user_thoughts_get(
|
||||
State(state): State<AppState>,
|
||||
Path(username): Path<String>,
|
||||
viewer: OptionalAuthUser,
|
||||
) -> Result<impl IntoResponse, ApiError> {
|
||||
let user = get_user_by_username(&state.conn, &username)
|
||||
.await?
|
||||
.ok_or(UserError::NotFound)?;
|
||||
|
||||
let thoughts_with_authors = get_thoughts_by_user(&state.conn, user.id).await?;
|
||||
let thoughts_with_authors =
|
||||
get_thoughts_by_user(&state.conn, user.id, viewer.0.map(|u| u.id)).await?;
|
||||
|
||||
let thoughts_schema: Vec<ThoughtSchema> = thoughts_with_authors
|
||||
.into_iter()
|
||||
@@ -272,12 +274,13 @@ async fn get_user_by_param(
|
||||
async fn user_outbox_get(
|
||||
State(state): State<AppState>,
|
||||
Path(username): Path<String>,
|
||||
viewer: OptionalAuthUser,
|
||||
) -> Result<impl IntoResponse, ApiError> {
|
||||
let user = get_user_by_username(&state.conn, &username)
|
||||
.await?
|
||||
.ok_or(UserError::NotFound)?;
|
||||
|
||||
let thoughts = get_thoughts_by_user(&state.conn, user.id).await?;
|
||||
let thoughts = get_thoughts_by_user(&state.conn, user.id, viewer.0.map(|u| u.id)).await?;
|
||||
|
||||
// Format the outbox as an ActivityPub OrderedCollection
|
||||
let outbox_url = format!("{}/users/{}/outbox", &state.base_url, username);
|
||||
|
Reference in New Issue
Block a user