feat: implement user follow/unfollow functionality and thought retrieval by user
- Added follow and unfollow endpoints for users. - Implemented logic to retrieve thoughts by a specific user. - Updated user error handling to include cases for already following and not following. - Created persistence layer for follow relationships. - Enhanced user and thought schemas to support new features. - Added tests for follow/unfollow endpoints and thought retrieval. - Updated frontend to display thoughts and allow posting new thoughts.
This commit is contained in:
87
thoughts-backend/api/src/routers/thought.rs
Normal file
87
thoughts-backend/api/src/routers/thought.rs
Normal file
@@ -0,0 +1,87 @@
|
||||
use axum::{
|
||||
extract::{Path, State},
|
||||
http::StatusCode,
|
||||
response::IntoResponse,
|
||||
routing::{delete, post},
|
||||
Router,
|
||||
};
|
||||
|
||||
use app::{
|
||||
error::UserError,
|
||||
persistence::thought::{create_thought, delete_thought, get_thought},
|
||||
state::AppState,
|
||||
};
|
||||
use models::{params::thought::CreateThoughtParams, schemas::thought::ThoughtSchema};
|
||||
|
||||
use crate::{
|
||||
error::ApiError,
|
||||
extractor::{AuthUser, Json, Valid},
|
||||
models::{ApiErrorResponse, ParamsErrorResponse},
|
||||
};
|
||||
|
||||
#[utoipa::path(
|
||||
post,
|
||||
path = "/thoughts",
|
||||
request_body = CreateThoughtParams,
|
||||
responses(
|
||||
(status = 201, description = "Thought created", body = ThoughtSchema),
|
||||
(status = 400, description = "Bad request", body = ApiErrorResponse),
|
||||
(status = 422, description = "Validation error", body = ParamsErrorResponse)
|
||||
),
|
||||
security(
|
||||
("api_key" = []),
|
||||
("bearer_auth" = [])
|
||||
)
|
||||
)]
|
||||
async fn thoughts_post(
|
||||
State(state): State<AppState>,
|
||||
auth_user: AuthUser,
|
||||
Valid(Json(params)): Valid<Json<CreateThoughtParams>>,
|
||||
) -> Result<impl IntoResponse, ApiError> {
|
||||
let thought = create_thought(&state.conn, auth_user.id, params).await?;
|
||||
let author = app::persistence::user::get_user(&state.conn, auth_user.id)
|
||||
.await?
|
||||
.ok_or(UserError::NotFound)?; // Should not happen if auth is valid
|
||||
|
||||
let schema = ThoughtSchema::from_models(&thought, &author);
|
||||
Ok((StatusCode::CREATED, Json(schema)))
|
||||
}
|
||||
|
||||
#[utoipa::path(
|
||||
delete,
|
||||
path = "/thoughts/{id}",
|
||||
params(
|
||||
("id" = i32, Path, description = "Thought ID")
|
||||
),
|
||||
responses(
|
||||
(status = 204, description = "Thought deleted"),
|
||||
(status = 403, description = "Forbidden", body = ApiErrorResponse),
|
||||
(status = 404, description = "Not Found", body = ApiErrorResponse)
|
||||
),
|
||||
security(
|
||||
("api_key" = []),
|
||||
("bearer_auth" = [])
|
||||
)
|
||||
)]
|
||||
async fn thoughts_delete(
|
||||
State(state): State<AppState>,
|
||||
auth_user: AuthUser,
|
||||
Path(id): Path<i32>,
|
||||
) -> Result<impl IntoResponse, ApiError> {
|
||||
let thought = get_thought(&state.conn, id)
|
||||
.await?
|
||||
.ok_or(UserError::NotFound)?;
|
||||
|
||||
if thought.author_id != auth_user.id {
|
||||
return Err(UserError::Forbidden.into());
|
||||
}
|
||||
|
||||
delete_thought(&state.conn, id).await?;
|
||||
Ok(StatusCode::NO_CONTENT)
|
||||
}
|
||||
|
||||
pub fn create_thought_router() -> Router<AppState> {
|
||||
Router::new()
|
||||
.route("/", post(thoughts_post))
|
||||
.route("/{id}", delete(thoughts_delete))
|
||||
}
|
Reference in New Issue
Block a user