diff --git a/.dockerignore b/.dockerignore index 5ad583d..04c13db 100644 --- a/.dockerignore +++ b/.dockerignore @@ -1,6 +1,5 @@ * -!.cargo/ !Cargo.lock !Cargo.toml !Makefile diff --git a/Dockerfile b/Dockerfile index 72638d3..7a7ee23 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,66 +1,19 @@ -# Build frontend files -FROM node:16 AS fbuilder +FROM rust:1.54 + +ENV PREFIX="/usr/src/out/prefix" \ + CC="musl-gcc -fPIC -pie -static" \ + LD_LIBRARY_PATH="$PREFIX" \ + PKG_CONFIG_PATH="/usr/local/lib/pkgconfig" \ + PATH="/usr/local/bin:/root/.cargo/bin:$PATH" + +RUN apt update && \ + apt install -y --no-install-recommends \ + musl-dev \ + musl-tools \ + libpq-dev \ + libssl-dev && \ + rustup target add x86_64-unknown-linux-musl && \ + mkdir "$PREFIX" && \ + echo "$PREFIX/lib" >> /etc/ld-musl-x86_64.path WORKDIR /usr/src/app - -COPY web/ ./ - -RUN yarn install && \ - yarn build - - -# Build backend & backend docs -FROM rust:1.55-alpine AS builder - -ARG DI_VER=1.2.5 - -# ENV OPENSSL_STATIC=1 \ -# PQ_LIB_STATIC=1 - -RUN apk update && \ - apk add --no-cache \ - postgresql \ - postgresql-dev \ - openssl-dev \ - build-base - -WORKDIR /usr/src/app - -# Build backend -COPY .cargo/ ./.cargo -COPY src/ ./src -COPY migrations/ ./migrations -COPY Cargo.toml Cargo.lock ./ - -RUN cargo build --release && \ - cargo doc --no-deps - -# Build dumb-init -RUN curl -sSL "https://github.com/Yelp/dumb-init/archive/refs/tags/v$DI_VER.tar.gz" | \ - tar -xzf - && \ - cd "dumb-init-$DI_VER" && \ - make build && \ - mv dumb-init .. - - -FROM alpine:3.14.2 - -RUN mkdir -p /var/www/html - -COPY --from=fbuilder /usr/src/app/dist /var/www/html/site -COPY --from=builder /usr/src/app/out/target/doc /var/www/html/doc -COPY --from=builder /usr/src/app/out/target/release/rbd /usr/bin/rbd -COPY --from=builder /usr/src/app/dumb-init /usr/bin/dumb-init - -ENTRYPOINT [ "dumb-init", "--" ] -CMD [ "/usr/bin/rbd" ] - -# RUN apt update && \ -# apt install -y --no-install-recommends \ -# musl-dev \ -# musl-tools \ -# libpq-dev \ -# libssl-dev && \ -# rustup target add x86_64-unknown-linux-musl && \ -# mkdir "$PREFIX" && \ -# echo "$PREFIX/lib" >> /etc/ld-musl-x86_64.path diff --git a/src/admin.rs b/src/admin.rs index 904e5c2..084bd9f 100644 --- a/src/admin.rs +++ b/src/admin.rs @@ -10,11 +10,11 @@ use crate::{ RbDbConn, }; -// #[get("/users")] -// pub async fn get_users(_admin: Admin, conn: RbDbConn) -> RbResult>> -// { -// Ok(Json(conn.run(|c| db::users::all(c)).await?)) -// } +#[get("/users")] +pub async fn get_users(_admin: Admin, conn: RbDbConn) -> RbResult>> +{ + Ok(Json(conn.run(|c| db::users::all(c)).await?)) +} #[post("/users", data = "")] pub async fn create_user(_admin: Admin, conn: RbDbConn, user: Json) -> RbResult<()> @@ -48,11 +48,8 @@ pub fn create_admin_user(conn: &PgConnection, username: &str, password: &str) -> admin: true, }; - if db::users::find_by_username(conn, username).is_ok() { - db::users::create(conn, &new_user); - } - // db::users::create_or_update(conn, &new_user) - // .map_err(|_| RbError::Custom("Couldn't create admin."))?; + db::users::create_or_update(conn, &new_user) + .map_err(|_| RbError::Custom("Couldn't create admin."))?; Ok(true) } diff --git a/src/db/posts.rs b/src/db/posts.rs index 109da6d..f435b9e 100644 --- a/src/db/posts.rs +++ b/src/db/posts.rs @@ -52,7 +52,7 @@ pub fn create(conn: &PgConnection, new_post: &NewPost) -> RbResult { Ok(insert_into(posts) .values(new_post) - .get_result(conn) + .get_result::(conn) .map_err(|_| RbError::DbError("Couldn't insert post."))?) // TODO check for conflict? @@ -62,7 +62,7 @@ pub fn update(conn: &PgConnection, post_id: &Uuid, patch_post: &PatchPost) -> Rb { Ok(diesel::update(posts.filter(id.eq(post_id))) .set(patch_post) - .get_result(conn) + .get_result::(conn) .map_err(|_| RbError::DbError("Couldn't update post."))?) } diff --git a/src/db/sections.rs b/src/db/sections.rs index 4adcc35..5c69352 100644 --- a/src/db/sections.rs +++ b/src/db/sections.rs @@ -44,7 +44,7 @@ pub fn get(conn: &PgConnection, offset_: u32, limit_: u32) -> RbResult(conn) .map_err(|_| RbError::DbError("Couldn't query sections."))?) } @@ -52,7 +52,7 @@ pub fn create(conn: &PgConnection, new_post: &NewSection) -> RbResult
{ Ok(insert_into(sections) .values(new_post) - .get_result(conn) + .get_result::
(conn) .map_err(|_| RbError::DbError("Couldn't insert section."))?) // TODO check for conflict? @@ -62,7 +62,7 @@ pub fn update(conn: &PgConnection, post_id: &Uuid, patch_post: &PatchSection) -> { Ok(diesel::update(sections.filter(id.eq(post_id))) .set(patch_post) - .get_result(conn) + .get_result::
(conn) .map_err(|_| RbError::DbError("Couldn't update section."))?) } diff --git a/src/db/tokens.rs b/src/db/tokens.rs index f2226c3..cbb8898 100644 --- a/src/db/tokens.rs +++ b/src/db/tokens.rs @@ -2,7 +2,6 @@ use diesel::{insert_into, prelude::*, Insertable, PgConnection, Queryable}; use uuid::Uuid; -use serde::{Serialize, Deserialize}; use crate::{ errors::{RbError, RbResult}, @@ -10,7 +9,7 @@ use crate::{ }; /// A refresh token as stored in the database -#[derive(Queryable, Serialize)] +#[derive(Queryable)] pub struct RefreshToken { pub token: Vec, @@ -20,7 +19,7 @@ pub struct RefreshToken } /// A new refresh token to be added into the database -#[derive(Deserialize, Insertable)] +#[derive(Insertable)] #[table_name = "refresh_tokens"] pub struct NewRefreshToken { @@ -29,46 +28,33 @@ pub struct NewRefreshToken pub expires_at: chrono::NaiveDateTime, } -#[derive(Deserialize, AsChangeset)] -#[table_name = "refresh_tokens"] -pub struct PatchRefreshToken +// 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> { - pub expires_at: Option, - pub last_used_at: Option, + refresh_tokens + .load::(conn) + .map_err(|_| RbError::DbError("Couldn't get all refresh tokens.")) } -pub fn get(conn: &PgConnection, offset_: u32, limit_: u32) -> RbResult> +/// 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<()> { - Ok(refresh_tokens - .offset(offset_.into()) - .limit(limit_.into()) - .load(conn) - .map_err(|_| RbError::DbError("Couldn't query tokens."))?) -} - -pub fn create(conn: &PgConnection, new_token: &NewRefreshToken) -> RbResult -{ - Ok(insert_into(refresh_tokens) - .values(new_token) - .get_result(conn) - .map_err(|_| RbError::DbError("Couldn't insert refresh token."))?) + insert_into(refresh_tokens) + .values(new_refresh_token) + .execute(conn) + .map_err(|_| RbError::DbError("Couldn't insert refresh token."))?; // TODO check for conflict? -} - -pub fn update(conn: &PgConnection, token_: &[u8], patch_token: &PatchRefreshToken) -> RbResult -{ - Ok(diesel::update(refresh_tokens.filter(token.eq(token_))) - .set(patch_token) - .get_result(conn) - .map_err(|_| RbError::DbError("Couldn't update token."))?) -} - -pub fn delete(conn: &PgConnection, token_: &[u8]) -> RbResult<()> -{ - diesel::delete(refresh_tokens.filter(token.eq(token_))) - .execute(conn) - .map_err(|_| RbError::DbError("Couldn't delete token."))?; Ok(()) } @@ -81,13 +67,13 @@ pub fn delete(conn: &PgConnection, token_: &[u8]) -> RbResult<()> /// * `token_val` - token value to search for pub fn find_with_user( conn: &PgConnection, - token_: &[u8], + token_val: &[u8], ) -> Option<(RefreshToken, super::users::User)> { // TODO actually check for errors here refresh_tokens .inner_join(crate::schema::users::dsl::users) - .filter(token.eq(token_)) + .filter(token.eq(token_val)) .first::<(RefreshToken, super::users::User)>(conn) .map_err(|_| RbError::DbError("Couldn't get refresh token & user.")) .ok() diff --git a/src/db/users.rs b/src/db/users.rs index 4929a15..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,7 +21,8 @@ pub struct User pub admin: bool, } -#[derive(Insertable, Deserialize)] +/// A new user to add to the database. +#[derive(Insertable, AsChangeset, Deserialize)] #[table_name = "users"] pub struct NewUser { @@ -27,29 +31,35 @@ pub struct NewUser pub admin: bool, } -#[derive(Deserialize, AsChangeset)] -#[table_name = "users"] -#[serde(rename_all = "camelCase")] -pub struct PatchSection +/// Returns all users in the database. +/// +/// # Arguments +/// +/// * `conn` - database connection to use +pub fn all(conn: &PgConnection) -> RbResult> { - username: Option, - admin: Option, -} - -pub fn get(conn: &PgConnection, offset_: u32, limit_: u32) -> RbResult> -{ - Ok(users - .offset(offset_.into()) - .limit(limit_.into()) - .load(conn) - .map_err(|_| RbError::DbError("Couldn't query users."))?) + users + .load::(conn) + .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 @@ -84,18 +94,18 @@ pub fn create(conn: &PgConnection, new_user: &NewUser) -> RbResult<()> /// /// * `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) -// .values(new_user) -// .on_conflict(username) -// .do_update() -// .set(new_user) -// .execute(conn) -// .map_err(|_| RbError::DbError("Couldn't create or update user."))?; +pub fn create_or_update(conn: &PgConnection, new_user: &NewUser) -> RbResult<()> +{ + diesel::insert_into(users) + .values(new_user) + .on_conflict(username) + .do_update() + .set(new_user) + .execute(conn) + .map_err(|_| RbError::DbError("Couldn't create or update user."))?; -// Ok(()) -// } + Ok(()) +} /// Delete the user with the given ID. /// diff --git a/src/main.rs b/src/main.rs index bd32e6c..f9e6217 100644 --- a/src/main.rs +++ b/src/main.rs @@ -109,7 +109,7 @@ fn rocket() -> _ ) .mount( "/api/admin", - routes![admin::create_user, admin::get_user_info], + routes![admin::get_users, admin::create_user, admin::get_user_info], ) .mount("/api/sections", routes![sections::create_section]) } diff --git a/src/sections.rs b/src/sections.rs index adc9a2d..013c0d3 100644 --- a/src/sections.rs +++ b/src/sections.rs @@ -16,9 +16,9 @@ pub async fn create_section( _admin: Admin, conn: RbDbConn, new_section: Json, -) -> RbResult> +) -> RbResult<()> { - Ok(Json(conn + Ok(conn .run(move |c| db::sections::create(c, &new_section.into_inner())) - .await?)) + .await?) }