diff --git a/src/db/mod.rs b/src/db/mod.rs index d1dcdcf..35e4995 100644 --- a/src/db/mod.rs +++ b/src/db/mod.rs @@ -1,3 +1,6 @@ +//! The db module contains all Diesel-related logic. This is to prevent the various Diesel imports +//! from poluting other modules' namespaces. + pub mod posts; pub mod sections; pub mod tokens; diff --git a/src/db/posts.rs b/src/db/posts.rs index 8014f3f..2486c08 100644 --- a/src/db/posts.rs +++ b/src/db/posts.rs @@ -1,3 +1,5 @@ +//! Handles all posts-related database operations. + use chrono::NaiveDate; use diesel::{insert_into, prelude::*, Insertable, PgConnection, Queryable}; use uuid::Uuid; @@ -7,6 +9,7 @@ use crate::{ schema::{posts, posts::dsl::*}, }; +/// Represents a post contained within the database. #[derive(Queryable)] pub struct Post { @@ -17,6 +20,7 @@ pub struct Post pub content: String, } +/// Represents a new post to be added to the database. #[derive(Insertable)] #[table_name = "posts"] pub struct NewPost @@ -26,6 +30,12 @@ pub struct NewPost pub publish_date: NaiveDate, } +/// Returns all posts in the database; should be used with care as this method could quickly return +/// a large amount of data. +/// +/// # Arguments +/// +/// * `conn` - a reference to a database connection pub fn all(conn: &PgConnection) -> RbResult> { posts @@ -33,6 +43,12 @@ pub fn all(conn: &PgConnection) -> RbResult> .map_err(|_| RbError::DbError("Couldn't get all posts.")) } +/// Insert a new post into the database. +/// +/// # Arguments +/// +/// * `conn` - reference to a database connection +/// * `new_post` - the new post object to insert pub fn create(conn: &PgConnection, new_post: &NewPost) -> RbResult<()> { insert_into(posts) diff --git a/src/db/sections.rs b/src/db/sections.rs index 19721fb..ca8956b 100644 --- a/src/db/sections.rs +++ b/src/db/sections.rs @@ -1,3 +1,5 @@ +//! Handles all section-related database operations. + use diesel::{insert_into, prelude::*, Insertable, PgConnection, Queryable}; use serde::Deserialize; use uuid::Uuid; @@ -7,6 +9,7 @@ use crate::{ schema::{sections, sections::dsl::*}, }; +/// Represents a section contained in the database. #[derive(Queryable)] pub struct Section { @@ -17,6 +20,7 @@ pub struct Section pub has_titles: bool, } +/// A new section to be added into the database. #[derive(Deserialize, Insertable)] #[table_name = "sections"] // #[serde(rename_all = "camelCase")] @@ -28,6 +32,11 @@ pub struct NewSection has_titles: Option, } +/// Returns all sections in the database. +/// +/// # Arguments +/// +/// * `conn` - reference to a database connection pub fn all(conn: &PgConnection) -> RbResult> { sections @@ -35,6 +44,12 @@ pub fn all(conn: &PgConnection) -> RbResult> .map_err(|_| RbError::DbError("Couldn't get all sections")) } +/// Inserts a new section into the database. +/// +/// # Arguments +/// +/// * `conn` - reference to a database connection +/// * `new_section` - the new section to be added pub fn create(conn: &PgConnection, new_section: &NewSection) -> RbResult<()> { insert_into(sections) diff --git a/src/db/tokens.rs b/src/db/tokens.rs index 97dd02d..cbb8898 100644 --- a/src/db/tokens.rs +++ b/src/db/tokens.rs @@ -1,3 +1,5 @@ +//! Handles refresh token-related database operations. + use diesel::{insert_into, prelude::*, Insertable, PgConnection, Queryable}; use uuid::Uuid; @@ -6,6 +8,7 @@ use crate::{ schema::{refresh_tokens, refresh_tokens::dsl::*}, }; +/// A refresh token as stored in the database #[derive(Queryable)] pub struct RefreshToken { @@ -15,6 +18,7 @@ pub struct RefreshToken pub last_used_at: Option, } +/// A new refresh token to be added into the database #[derive(Insertable)] #[table_name = "refresh_tokens"] pub struct NewRefreshToken @@ -24,6 +28,12 @@ pub struct NewRefreshToken pub expires_at: chrono::NaiveDateTime, } +// TODO add pagination as this could grow very quickly +/// Returns all refresh tokens contained in the database. +/// +/// # Arguments +/// +/// * `conn` - database connection to use pub fn all(conn: &PgConnection) -> RbResult> { refresh_tokens @@ -31,6 +41,12 @@ pub fn all(conn: &PgConnection) -> RbResult> .map_err(|_| RbError::DbError("Couldn't get all refresh tokens.")) } +/// Insert a new refresh token into the database. +/// +/// # Arguments +/// +/// * `conn` - database connection to use +/// * `new_refresh_token` - token to insert pub fn create(conn: &PgConnection, new_refresh_token: &NewRefreshToken) -> RbResult<()> { insert_into(refresh_tokens) @@ -43,6 +59,12 @@ pub fn create(conn: &PgConnection, new_refresh_token: &NewRefreshToken) -> RbRes Ok(()) } +/// Returns the token & user data associated with the given refresh token value. +/// +/// # Arguments +/// +/// * `conn` - database connection to use +/// * `token_val` - token value to search for pub fn find_with_user( conn: &PgConnection, token_val: &[u8], @@ -57,6 +79,16 @@ pub fn find_with_user( .ok() } +/// Updates a token's `last_used_at` column value. +/// +/// # Arguments +/// +/// * `conn` - database connection to use +/// * `token_` - value of the refresh token to update +/// * `last_used_at_` - date value to update column with +/// +/// **NOTE**: argument names use trailing underscores as to not conflict with Diesel's imported dsl +/// names. pub fn update_last_used_at( conn: &PgConnection, token_: &[u8], diff --git a/src/db/users.rs b/src/db/users.rs index efc74db..37ef9c2 100644 --- a/src/db/users.rs +++ b/src/db/users.rs @@ -1,3 +1,5 @@ +//! Handles user-related database operations. + use diesel::{prelude::*, AsChangeset, Insertable, Queryable}; use serde::{Deserialize, Serialize}; use uuid::Uuid; @@ -7,6 +9,7 @@ use crate::{ schema::{users, users::dsl::*}, }; +/// A user as stored in the database. #[derive(Queryable, Serialize)] pub struct User { @@ -18,6 +21,7 @@ pub struct User pub admin: bool, } +/// A new user to add to the database. #[derive(Insertable, AsChangeset, Deserialize)] #[table_name = "users"] pub struct NewUser @@ -27,6 +31,11 @@ pub struct NewUser pub admin: bool, } +/// Returns all users in the database. +/// +/// # Arguments +/// +/// * `conn` - database connection to use pub fn all(conn: &PgConnection) -> RbResult> { users @@ -34,11 +43,23 @@ pub fn all(conn: &PgConnection) -> RbResult> .map_err(|_| RbError::DbError("Couldn't get all users.")) } +/// Find a user with a given ID. +/// +/// # Arguments +/// +/// * `conn` - database connection to use +/// * `user_id` - ID to search for pub fn find(conn: &PgConnection, user_id: Uuid) -> Option { users.find(user_id).first::(conn).ok() } +/// Find a user with a given username. +/// +/// # Arguments +/// +/// * `conn` - database connection to use +/// * `username_` - username to search for pub fn find_by_username(conn: &PgConnection, username_: &str) -> RbResult { Ok(users @@ -47,6 +68,12 @@ pub fn find_by_username(conn: &PgConnection, username_: &str) -> RbResult .map_err(|_| RbError::DbError("Couldn't find users by username."))?) } +/// Insert a new user into the database +/// +/// # Arguments +/// +/// * `conn` - database connection to use +/// * `new_user` - user to insert pub fn create(conn: &PgConnection, new_user: &NewUser) -> RbResult<()> { let count = diesel::insert_into(users) @@ -61,6 +88,12 @@ pub fn create(conn: &PgConnection, new_user: &NewUser) -> RbResult<()> Ok(()) } +/// Either create a new user or update an existing one on conflict. +/// +/// # Arguments +/// +/// * `conn` - database connection to use +/// * `new_user` - user to insert/update pub fn create_or_update(conn: &PgConnection, new_user: &NewUser) -> RbResult<()> { diesel::insert_into(users) @@ -74,6 +107,12 @@ pub fn create_or_update(conn: &PgConnection, new_user: &NewUser) -> RbResult<()> Ok(()) } +/// Delete the user with the given ID. +/// +/// # Arguments +/// +/// `conn` - database connection to use +/// `user_id` - ID of user to delete pub fn delete(conn: &PgConnection, user_id: Uuid) -> RbResult<()> { diesel::delete(users.filter(id.eq(user_id))) @@ -83,6 +122,14 @@ pub fn delete(conn: &PgConnection, user_id: Uuid) -> RbResult<()> Ok(()) } +/// Block a user given an ID. +/// In practice, this means updating the user's entry so that the `blocked` column is set to +/// `true`. +/// +/// # Arguments +/// +/// `conn` - database connection to use +/// `user_id` - ID of user to block pub fn block(conn: &PgConnection, user_id: Uuid) -> RbResult<()> { diesel::update(users.filter(id.eq(user_id))) diff --git a/src/sections.rs b/src/sections.rs index c5e2f27..e4def24 100644 --- a/src/sections.rs +++ b/src/sections.rs @@ -1,8 +1,16 @@ +//! This module handles management of site sections (aka blogs). + use rocket::serde::json::Json; use crate::{db, errors::RbResult, guards::Admin, RbDbConn}; -/// Create a new section. +/// Route for creating a new section. +/// +/// # Arguments +/// +/// * `_admin` - guard ensuring user is admin +/// * `conn` - guard providing a connection to the database +/// * `new_section` - Json-encoded NewSection object #[post("/", data = "")] pub async fn create_section( _admin: Admin,