Tidying up routes, query parameters for posts, better database api

This commit is contained in:
Imbus 2023-10-21 01:55:27 +02:00
parent 204ed8ec41
commit 4fc00eaf23
5 changed files with 39 additions and 20 deletions

View file

@ -2,9 +2,14 @@ use crate::routes::{NewPost, Post};
use log::warn;
use sqlx::SqlitePool;
// Gets all posts from the database
pub async fn db_get_posts(pool: &SqlitePool) -> Vec<Post> {
sqlx::query_as!(Post, "SELECT * FROM posts")
// Gets the latest posts from the database, ordered by created_at
pub async fn db_get_latest_posts(pool: &SqlitePool, limit: i64, offset: i64) -> Vec<Post> {
sqlx::query_as!(
Post,
"SELECT * FROM posts ORDER BY created_at DESC LIMIT ? OFFSET ?",
limit,
offset
)
.fetch_all(pool)
.await
.unwrap()

View file

@ -1,7 +1,3 @@
// use crate::{
// config::{DAYS_VALID, JWT_SECRET},
// Claims,
// };
use jsonwebtoken::{
decode, encode, errors::Result as JwtResult, DecodingKey, EncodingKey, Header, Validation,
};

View file

@ -1,7 +1,7 @@
use crate::db::{db_get_posts, db_new_post};
use crate::db::{db_get_latest_posts, db_new_post};
use crate::ServerState;
use actix_web::web::Data;
use actix_web::web::{Data, Query};
use actix_web::{get, post, web::Json, HttpResponse, Responder, Result};
use log::info;
use serde::{Deserialize, Serialize};
@ -27,6 +27,7 @@ pub struct Post {
pub updated_at: chrono::NaiveDateTime,
}
/// The user as it is stored in the database, with all the related metadata
#[derive(Debug, Serialize, Deserialize, Clone, FromRow)]
pub struct User {
pub id: i64,
@ -36,11 +37,30 @@ pub struct User {
pub updated_at: chrono::NaiveDateTime,
}
#[get("/posts")]
pub async fn get_posts(state: Data<ServerState>) -> Result<impl Responder> {
Ok(HttpResponse::Ok().json(db_get_posts(&state.pool).await))
// These look like /posts?limit=10&offset=20 in the URL
// Note that these are optional
/// Query parameters for the /posts endpoint
#[derive(Debug, Serialize, Deserialize)]
struct QueryParams {
limit: Option<i64>,
offset: Option<i64>,
}
/// Gets all posts from the database, query parameters are optional
/// If limit is not specified, it defaults to a sane value
#[get("/posts")]
pub async fn get_posts(
query: Query<QueryParams>,
state: Data<ServerState>,
) -> Result<impl Responder> {
if let (Some(lim), Some(ofs)) = (query.limit, query.offset) {
return Ok(HttpResponse::Ok()
.json(db_get_latest_posts(&state.pool, std::cmp::min(lim, 30), ofs).await));
}
Ok(HttpResponse::Ok().json(db_get_latest_posts(&state.pool, 30, 0).await))
}
/// Creates a new post, requires a token in release mode
#[post("/posts")]
pub async fn new_post(new_post: Json<NewPost>, state: Data<ServerState>) -> Result<impl Responder> {
return match db_new_post(new_post.into_inner(), &state.pool).await {

View file

@ -74,10 +74,6 @@ pub async fn register(
#[post("/login")]
pub async fn login(data: Json<LoginData>, state: Data<ServerState>) -> Result<impl Responder> {
// let q = "SELECT password FROM users WHERE username = ?";
// let query = sqlx::query(q).bind(&data.username);
// let result = query.fetch_one(&state.pool).await.ok();
let uname = data.username.clone();
let q = sqlx::query!("SELECT password FROM users WHERE username = ?", uname)
.fetch_one(&state.pool)

View file

@ -35,10 +35,12 @@ impl ServerState {
async fn debug_setup(pool: &SqlitePool) -> Result<(), sqlx::Error> {
use sqlx::query;
query!("INSERT INTO users (username, password) VALUES ('testuser', 'testpassword')",)
// Or ignore is just to silence the error if the user already exists
query!("INSERT OR IGNORE INTO users (username, password) VALUES ('testuser', 'testpassword')",)
.execute(pool)
.await?;
// This requires that the user with id 1 exists in the user table
query!("INSERT INTO posts (user_id, content) VALUES (1, 'Hello world!')",)
.execute(pool)
.await?;