diff --git a/Cargo.lock b/Cargo.lock index 0ae6e43..6673bb4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -240,6 +240,7 @@ dependencies = [ "libc", "num-integer", "num-traits", + "serde", "time 0.1.44", "winapi 0.3.9", ] @@ -393,6 +394,7 @@ checksum = "3e2de9deab977a153492a1468d1b1c0662c1cf39e5ea87d0c060ecd59ef18d8c" dependencies = [ "bitflags", "byteorder", + "chrono", "diesel_derives", "pq-sys", "r2d2", @@ -2157,6 +2159,7 @@ checksum = "1d649a3145108d7d3fbcde896a468d1bd636791823c9921135218ad89be08307" name = "wasmcloud-api" version = "0.1.0" dependencies = [ + "chrono", "color-eyre", "diesel", "log 0.4.11", diff --git a/Cargo.toml b/Cargo.toml index ca42b9c..81d5c0c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,8 +7,9 @@ edition = "2018" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] +chrono = { version = "0.4", features = ["serde"] } color-eyre = "0.5" -diesel = { version = "1", features = ["postgres", "r2d2", "uuidv07"] } +diesel = { version = "1", features = ["postgres", "r2d2", "uuidv07", "chrono"] } log = "0" rocket = "0.4" rocket_oauth2 = "0.4" diff --git a/migrations/2020-10-26-160352_users/up.sql b/migrations/2020-10-26-160352_users/up.sql index 9f61570..ee46445 100644 --- a/migrations/2020-10-26-160352_users/up.sql +++ b/migrations/2020-10-26-160352_users/up.sql @@ -1,5 +1,13 @@ CREATE EXTENSION IF NOT EXISTS "uuid-ossp"; +CREATE OR REPLACE FUNCTION trigger_set_timestamp() + RETURNS TRIGGER AS $$ +BEGIN + NEW.updated_at = NOW(); + RETURN NEW; +END; +$$ LANGUAGE plpgsql; + CREATE TABLE IF NOT EXISTS users ( id UUID DEFAULT uuid_generate_v4() NOT NULL , email VARCHAR UNIQUE NOT NULL @@ -7,5 +15,12 @@ CREATE TABLE IF NOT EXISTS users , is_admin BOOLEAN DEFAULT false NOT NULL , is_locked BOOLEAN DEFAULT false NOT NULL , tier INTEGER DEFAULT 0 NOT NULL + , created_at TIMESTAMP NOT NULL DEFAULT NOW() + , updated_at TIMESTAMP NOT NULL DEFAULT NOW() , PRIMARY KEY (id) ); + +CREATE TRIGGER set_timestamp_users + BEFORE UPDATE ON users + FOR EACH ROW + EXECUTE PROCEDURE trigger_set_timestamp(); diff --git a/migrations/2020-10-26-202745_gitea_tokens/up.sql b/migrations/2020-10-26-202745_gitea_tokens/up.sql index 8825ced..319fc61 100644 --- a/migrations/2020-10-26-202745_gitea_tokens/up.sql +++ b/migrations/2020-10-26-202745_gitea_tokens/up.sql @@ -3,8 +3,15 @@ CREATE TABLE IF NOT EXISTS gitea_tokens , user_id UUID NOT NULL , access_token VARCHAR NOT NULL , refresh_token VARCHAR NOT NULL + , created_at TIMESTAMP NOT NULL DEFAULT NOW() + , updated_at TIMESTAMP NOT NULL DEFAULT NOW() , PRIMARY KEY (id) , CONSTRAINT fk_user_id FOREIGN KEY (user_id) REFERENCES users(id) ); + +CREATE TRIGGER set_timestamp_gitea_tokens + BEFORE UPDATE ON gitea_tokens + FOR EACH ROW + EXECUTE PROCEDURE trigger_set_timestamp(); diff --git a/migrations/2020-10-27-195721_api-tokens/down.sql b/migrations/2020-10-27-195721_api-tokens/down.sql new file mode 100644 index 0000000..291a97c --- /dev/null +++ b/migrations/2020-10-27-195721_api-tokens/down.sql @@ -0,0 +1 @@ +-- This file should undo anything in `up.sql` \ No newline at end of file diff --git a/migrations/2020-10-27-195721_api-tokens/up.sql b/migrations/2020-10-27-195721_api-tokens/up.sql new file mode 100644 index 0000000..523d17b --- /dev/null +++ b/migrations/2020-10-27-195721_api-tokens/up.sql @@ -0,0 +1,13 @@ +CREATE TABLE IF NOT EXISTS tokens + ( id UUID DEFAULT uuid_generate_v4() NOT NULL + , user_id UUID NOT NULL + , created_at TIMESTAMP NOT NULL DEFAULT NOW() + , updated_at TIMESTAMP NOT NULL DEFAULT NOW() + , deleted_at TIMESTAMP + , PRIMARY KEY (id) + ); + +CREATE TRIGGER set_timestamp_tokens + BEFORE UPDATE ON tokens + FOR EACH ROW + EXECUTE PROCEDURE trigger_set_timestamp(); diff --git a/src/api.rs b/src/api.rs new file mode 100644 index 0000000..f77aafb --- /dev/null +++ b/src/api.rs @@ -0,0 +1,15 @@ +use crate::{schema, models, MainDatabase}; +use diesel::prelude::*; +use rocket_contrib::{json::Json, uuid::Uuid}; + +#[tracing::instrument(skip(conn))] +#[get("/user/")] +pub fn get_user(conn: MainDatabase, uuid: Uuid) -> Json { + use schema::users::dsl::users; + let result = users + .find(uuid.into_inner()) + .get_result::(&*conn) + .expect("to find user"); + + Json(result) +} diff --git a/src/main.rs b/src/main.rs index 642057c..0bc09e2 100644 --- a/src/main.rs +++ b/src/main.rs @@ -14,30 +14,19 @@ use rocket::{ http::{Cookie, Cookies, SameSite}, response::Redirect, }; -use rocket_contrib::{helmet::SpaceHelmet, json::Json, uuid::Uuid}; +use rocket_contrib::{helmet::SpaceHelmet}; use rocket_oauth2::{OAuth2, TokenResponse}; +pub mod api; pub mod gitea; pub mod models; pub mod schema; #[database("main_data")] -struct MainDatabase(PgConnection); +pub struct MainDatabase(PgConnection); struct Gitea; -#[tracing::instrument(skip(conn))] -#[get("/user/")] -fn get_user(conn: MainDatabase, uuid: Uuid) -> Json { - use schema::users::dsl::users; - let result = users - .find(uuid.into_inner()) - .get_result::(&*conn) - .expect("to find user"); - - Json(result) -} - #[tracing::instrument(skip(oauth2, cookies))] #[get("/login/gitea")] fn gitea_login(oauth2: OAuth2, mut cookies: Cookies<'_>) -> Redirect { @@ -69,8 +58,7 @@ fn gitea_callback( .load::(&*conn) { Ok(u) => if u.len() == 0 { - let u = models::User { - id: uuid::Uuid::new_v4(), + let u = models::NewUser { salutation: gitea_user.full_name, email: gitea_user.email, is_admin: gitea_user.is_admin, @@ -83,8 +71,7 @@ fn gitea_callback( .get_result(&*conn) .expect("able to insert user"); - let tok = models::GiteaToken { - id: uuid::Uuid::new_v4(), + let tok = models::NewGiteaToken { user_id: u.id.clone(), access_token: tok, refresh_token: refresh, @@ -124,7 +111,7 @@ fn main() -> Result<()> { .attach(OAuth2::::fairing("gitea")) .attach(MainDatabase::fairing()) .attach(SpaceHelmet::default()) - .mount("/api", routes![get_user]) + .mount("/api", routes![api::get_user]) .mount("/", routes![gitea_login, gitea_callback]) .launch(); diff --git a/src/models.rs b/src/models.rs index 049ff44..1959191 100644 --- a/src/models.rs +++ b/src/models.rs @@ -1,11 +1,11 @@ +use crate::schema::{gitea_tokens, users}; +use chrono::NaiveDateTime; use serde::Serialize; use uuid::Uuid; -use crate::schema::{gitea_tokens, users}; -#[derive(Insertable, Queryable, Serialize, Debug, Clone)] -#[table_name="users"] -pub struct User { - pub id: Uuid, +#[derive(Insertable)] +#[table_name = "users"] +pub struct NewUser { pub email: String, pub salutation: String, pub is_admin: bool, @@ -13,11 +13,33 @@ pub struct User { pub tier: i32, } -#[derive(Insertable, Queryable, Debug, Clone)] +#[derive(Queryable, Serialize, Debug, Clone)] +pub struct User { + pub id: Uuid, + pub email: String, + pub salutation: String, + pub is_admin: bool, + pub is_locked: bool, + pub tier: i32, + pub created_at: NaiveDateTime, + pub updated_at: NaiveDateTime, +} + +#[derive(Insertable)] #[table_name="gitea_tokens"] +pub struct NewGiteaToken { + pub user_id: Uuid, + pub access_token: String, + pub refresh_token: String, +} + +#[derive(Insertable, Queryable, Debug, Clone)] +#[table_name = "gitea_tokens"] pub struct GiteaToken { pub id: Uuid, pub user_id: Uuid, pub access_token: String, pub refresh_token: String, + pub created_at: NaiveDateTime, + pub updated_at: NaiveDateTime, } diff --git a/src/schema.rs b/src/schema.rs index c099e04..4ac66b9 100644 --- a/src/schema.rs +++ b/src/schema.rs @@ -4,6 +4,18 @@ table! { user_id -> Uuid, access_token -> Varchar, refresh_token -> Varchar, + created_at -> Timestamp, + updated_at -> Timestamp, + } +} + +table! { + tokens (id) { + id -> Uuid, + user_id -> Uuid, + created_at -> Timestamp, + updated_at -> Timestamp, + deleted_at -> Nullable, } } @@ -15,6 +27,8 @@ table! { is_admin -> Bool, is_locked -> Bool, tier -> Int4, + created_at -> Timestamp, + updated_at -> Timestamp, } } @@ -22,5 +36,6 @@ joinable!(gitea_tokens -> users (user_id)); allow_tables_to_appear_in_same_query!( gitea_tokens, + tokens, users, );