From 3e7612a9a8b278a21a561295464aae31f30e5202 Mon Sep 17 00:00:00 2001 From: Jef Roosens Date: Mon, 13 Sep 2021 22:15:38 +0200 Subject: [PATCH] Added create section endpoint --- Rb.yaml | 21 +++++++++++++++++++++ rustfmt.toml | 2 +- src/db/mod.rs | 6 +++--- src/db/posts.rs | 6 ++++-- src/db/sections.rs | 12 ++++++++---- src/errors.rs | 2 +- src/guards.rs | 18 ++++++++---------- src/main.rs | 2 ++ src/schema.rs | 7 +------ src/sections.rs | 16 ++++++++++++++++ tests/admin.py | 13 ++++++++++--- 11 files changed, 75 insertions(+), 30 deletions(-) create mode 100644 src/sections.rs diff --git a/Rb.yaml b/Rb.yaml index c944758..29a37f8 100644 --- a/Rb.yaml +++ b/Rb.yaml @@ -21,3 +21,24 @@ debug: databases: postgres_rb: url: "postgres://rb:rb@localhost:5432/rb" + +# This config is just used for testing, you should change it when deploying +release: + keep_alive: 5 + read_timeout: 5 + write_timeout: 5 + log_level: "normal" + limits: + forms: 32768 + + admin_user: "admin" + admin_pass: "password" + jwt: + key: "secret" + refresh_token_size: 64 + # Just 5 seconds for debugging + refresh_token_expire: 60 + + databases: + postgres_rb: + url: "postgres://rb:rb@localhost:5432/rb" diff --git a/rustfmt.toml b/rustfmt.toml index 5e52857..8e8627b 100644 --- a/rustfmt.toml +++ b/rustfmt.toml @@ -36,7 +36,7 @@ license_template_path = "" make_backup = false match_arm_blocks = true match_arm_leading_pipes = "Never" -match_block_trailing_comma = false +match_block_trailing_comma = true max_width = 100 merge_derives = true newline_style = "Auto" diff --git a/src/db/mod.rs b/src/db/mod.rs index 19cb419..d1dcdcf 100644 --- a/src/db/mod.rs +++ b/src/db/mod.rs @@ -1,8 +1,8 @@ +pub mod posts; +pub mod sections; pub mod tokens; pub mod users; -pub mod sections; -pub mod posts; +pub use sections::{NewSection, Section}; pub use tokens::{NewRefreshToken, RefreshToken}; pub use users::{NewUser, User}; -pub use sections::{Section, NewSection}; diff --git a/src/db/posts.rs b/src/db/posts.rs index 0493405..8014f3f 100644 --- a/src/db/posts.rs +++ b/src/db/posts.rs @@ -1,6 +1,6 @@ +use chrono::NaiveDate; use diesel::{insert_into, prelude::*, Insertable, PgConnection, Queryable}; use uuid::Uuid; -use chrono::NaiveDate; use crate::{ errors::{RbError, RbResult}, @@ -28,7 +28,9 @@ pub struct NewPost pub fn all(conn: &PgConnection) -> RbResult> { - posts.load::(conn).map_err(|_| RbError::DbError("Couldn't get all posts.")) + posts + .load::(conn) + .map_err(|_| RbError::DbError("Couldn't get all posts.")) } pub fn create(conn: &PgConnection, new_post: &NewPost) -> RbResult<()> diff --git a/src/db/sections.rs b/src/db/sections.rs index cff2736..19721fb 100644 --- a/src/db/sections.rs +++ b/src/db/sections.rs @@ -1,4 +1,5 @@ use diesel::{insert_into, prelude::*, Insertable, PgConnection, Queryable}; +use serde::Deserialize; use uuid::Uuid; use crate::{ @@ -16,19 +17,22 @@ pub struct Section pub has_titles: bool, } -#[derive(Insertable)] +#[derive(Deserialize, Insertable)] #[table_name = "sections"] +// #[serde(rename_all = "camelCase")] pub struct NewSection { title: String, description: Option, - is_default: bool, - has_titles: bool, + is_default: Option, + has_titles: Option, } pub fn all(conn: &PgConnection) -> RbResult> { - sections.load::
(conn).map_err(|_| RbError::DbError("Couldn't get all sections")) + sections + .load::
(conn) + .map_err(|_| RbError::DbError("Couldn't get all sections")) } pub fn create(conn: &PgConnection, new_section: &NewSection) -> RbResult<()> diff --git a/src/errors.rs b/src/errors.rs index bb7856a..1f9aff3 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -61,7 +61,7 @@ impl RbError RbError::AuthInvalidRefreshToken => "This refresh token is not valid.", RbError::AuthDuplicateRefreshToken => { "This refresh token has already been used. The user has been blocked." - } + }, RbError::AuthMissingHeader => "Missing Authorization header.", RbError::UMDuplicateUser => "This user already exists.", diff --git a/src/guards.rs b/src/guards.rs index 7b40bdd..3510163 100644 --- a/src/guards.rs +++ b/src/guards.rs @@ -10,7 +10,7 @@ use sha2::Sha256; use crate::{auth::jwt::Claims, errors::RbError, RbConfig}; -/// Extracts a "Authorization: Bearer" string from the headers. +/// Extracts an "Authorization: Bearer" string from the headers. pub struct Bearer<'a>(&'a str); #[rocket::async_trait] @@ -22,7 +22,7 @@ impl<'r> FromRequest<'r> for Bearer<'r> { // If the header isn't present, just forward to the next route let header = match req.headers().get_one("Authorization") { - None => return Outcome::Failure((Status::BadRequest, Self::Error::AuthMissingHeader)), + None => return Outcome::Forward(()), Some(val) => val, }; @@ -31,12 +31,10 @@ impl<'r> FromRequest<'r> for Bearer<'r> } // Extract the jwt token from the header - let auth_string = match header.get(7..) { - Some(s) => s, - None => return Outcome::Failure((Status::Unauthorized, Self::Error::AuthUnauthorized)), - }; - - Outcome::Success(Self(auth_string)) + match header.get(7..) { + Some(s) => Outcome::Success(Self(s)), + None => Outcome::Failure((Status::Unauthorized, Self::Error::AuthUnauthorized)), + } } } @@ -63,14 +61,14 @@ impl<'r> FromRequest<'r> for Jwt Status::InternalServerError, Self::Error::Custom("Failed to do Hmac thing."), )) - } + }, }; // Verify token using key let claims: Claims = match bearer.verify_with_key(&key) { Ok(claims) => claims, Err(_) => { return Outcome::Failure((Status::Unauthorized, Self::Error::AuthUnauthorized)) - } + }, }; Outcome::Success(Self(claims)) diff --git a/src/main.rs b/src/main.rs index 2819e79..adb2f26 100644 --- a/src/main.rs +++ b/src/main.rs @@ -27,6 +27,7 @@ pub mod db; pub mod errors; pub mod guards; pub(crate) mod schema; +pub mod sections; #[global_allocator] static GLOBAL: mimalloc::MiMalloc = mimalloc::MiMalloc; @@ -111,4 +112,5 @@ fn rocket() -> _ "/api/admin", routes![admin::get_users, admin::create_user, admin::get_user_info], ) + .mount("/api/sections", routes![sections::create_section]) } diff --git a/src/schema.rs b/src/schema.rs index a38f572..45b9813 100644 --- a/src/schema.rs +++ b/src/schema.rs @@ -40,9 +40,4 @@ table! { joinable!(posts -> sections (section_id)); joinable!(refresh_tokens -> users (user_id)); -allow_tables_to_appear_in_same_query!( - posts, - refresh_tokens, - sections, - users, -); +allow_tables_to_appear_in_same_query!(posts, refresh_tokens, sections, users,); diff --git a/src/sections.rs b/src/sections.rs new file mode 100644 index 0000000..c5e2f27 --- /dev/null +++ b/src/sections.rs @@ -0,0 +1,16 @@ +use rocket::serde::json::Json; + +use crate::{db, errors::RbResult, guards::Admin, RbDbConn}; + +/// Create a new section. +#[post("/", data = "")] +pub async fn create_section( + _admin: Admin, + conn: RbDbConn, + new_section: Json, +) -> RbResult<()> +{ + Ok(conn + .run(move |c| db::sections::create(c, &new_section.into_inner())) + .await?) +} diff --git a/tests/admin.py b/tests/admin.py index 19a1c5b..069c2dd 100644 --- a/tests/admin.py +++ b/tests/admin.py @@ -2,7 +2,7 @@ import requests class RbClient: - def __init__(self, username, password, base_url = "http://localhost:8000/api"): + def __init__(self, username = "admin", password = "password", base_url = "http://localhost:8000/api"): self.username = username self.password = password self.base_url = base_url @@ -17,6 +17,7 @@ class RbClient: }) if r.status_code != 200: + print(r.text) raise Exception("Couldn't login") res = r.json() @@ -56,9 +57,15 @@ class RbClient: def get(self, url, *args, **kwargs): return self._request("GET", f"{self.base_url}{url}", *args, **kwargs) + def post(self, url, *args, **kwargs): + return self._request("POST", f"{self.base_url}{url}", *args, **kwargs) + if __name__ == "__main__": - client = RbClient("admin", "password") + client = RbClient() - print(client.get("/admin/users").json()) + # print(client.get("/admin/users").json()) + client.post("/sections", json={ + "title": "this is a title" + })