diff --git a/engine/Cargo.lock b/engine/Cargo.lock index 6c85ede..662f488 100644 --- a/engine/Cargo.lock +++ b/engine/Cargo.lock @@ -1429,6 +1429,16 @@ version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" +[[package]] +name = "mime_guess" +version = "2.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4192263c238a5f0d0c6bfd21f336a313a4ce1c450542449ca191bb657b4642ef" +dependencies = [ + "mime", + "unicase", +] + [[package]] name = "minimal-lexical" version = "0.2.1" @@ -1809,9 +1819,11 @@ dependencies = [ "headers", "http", "http-body-util", + "httpdate", "hyper", "hyper-util", "mime", + "mime_guess", "multer", "nix", "parking_lot", @@ -3139,6 +3151,15 @@ dependencies = [ "version_check", ] +[[package]] +name = "unicase" +version = "2.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7d2d4dafb69621809a81864c9c1b864479e1235c0dd4e199924b9742439ed89" +dependencies = [ + "version_check", +] + [[package]] name = "unicode-bidi" version = "0.3.15" diff --git a/engine/Cargo.toml b/engine/Cargo.toml index 32827ea..ac50786 100644 --- a/engine/Cargo.toml +++ b/engine/Cargo.toml @@ -12,7 +12,7 @@ dotenv = "0.15.0" dotenvy = "0.15.7" openid = "0.14.0" poem = "3.0.4" -poem-openapi = { version = "5.0.3", features = ["email", "email_address", "swagger-ui"] } +poem-openapi = { version = "5.0.3", features = ["email", "email_address", "redoc", "static-files"] } reqwest = "0.12.5" serde = "1.0.204" serde_json = "1.0.120" diff --git a/engine/migrations/0001_init.sql b/engine/migrations/0001_init.sql index 69569e5..3bdf457 100644 --- a/engine/migrations/0001_init.sql +++ b/engine/migrations/0001_init.sql @@ -3,5 +3,5 @@ CREATE TABLE IF NOT EXISTS users id SERIAL PRIMARY KEY, oauth_sub VARCHAR(255) NOT NULL, oauth_data JSONB NOT NULL, - nickname VARCHAR(255) NOT NULL + nickname VARCHAR(255) ); diff --git a/engine/src/database/mod.rs b/engine/src/database/mod.rs index fe1f5da..64b10eb 100644 --- a/engine/src/database/mod.rs +++ b/engine/src/database/mod.rs @@ -1,8 +1,12 @@ +use std::{ops::Deref, str::FromStr}; + use async_std::stream::StreamExt; use openid::Userinfo; +use serde_json::Value; use sqlx::{ postgres::PgPoolOptions, query::{self, Query}, + types::Json, Execute, Executor, PgPool, }; use tracing::info; @@ -32,21 +36,49 @@ impl Database { Ok(()) } - pub async fn upsert_get_user(&self, oauth_userinfo: &Userinfo) -> Result { - // Check if the user exists, return its info, otherwise create a new user, and return its info. - - let sub = oauth_userinfo.sub.as_ref().unwrap().to_string(); - - let mut userdata = - sqlx::query_as::<_, UserData>("SELECT * FROM users WHERE oauth_sub = ? LIMIT 1") - .bind(sub) - .fetch(&self.pool); - - let x = userdata.next().await.unwrap().unwrap(); - - info!("upsert_get_user: {:?}", x); - - Ok(x) + /// Check if the user exists, return its info, otherwise create a new user, and return its info. + pub async fn upsert_get_user( + &self, + oauth_userinfo: &Userinfo, + ) -> Result { + let sub = oauth_userinfo.sub.as_deref().unwrap(); + + info!("upsert_get_user: sub: {}", sub); + + match sqlx::query_as::<_, UserData>("SELECT * FROM users WHERE oauth_sub = $1") + .bind(sub) + .fetch_one(&self.pool) + .await + { + Ok(x) => { + info!("upsert_get_user_found: {:?}", x); + Ok(x) + } + Err(e) => { + info!("upsert_get_user: not found {}", e); + + let mut local_userdata = UserData { + id: 0, + oauth_sub: sub.to_string(), + oauth_data: Json(oauth_userinfo.clone()), + nickname: None, + }; + + let insert_query = sqlx::query!( + "INSERT INTO users (oauth_sub, oauth_data) VALUES ($1, $2) RETURNING id", + local_userdata.oauth_sub, + Json(&oauth_userinfo) as _ + ) + .fetch_one(&self.pool) + .await?; + + info!("upsert_get_user: {:?}", insert_query); + + local_userdata.id = insert_query.id; + + Ok(local_userdata) + } + } } // pub async fn insert_user(&self, user: &Userinfo) -> Result { diff --git a/engine/src/models/user_data.rs b/engine/src/models/user_data.rs index 261482a..4a8c264 100644 --- a/engine/src/models/user_data.rs +++ b/engine/src/models/user_data.rs @@ -1,10 +1,12 @@ +use openid::Userinfo; use serde::{Deserialize, Serialize}; +use sqlx::types::Json; #[derive(sqlx::FromRow, Debug, Clone, Serialize, Deserialize)] pub struct UserData { - pub id: i64, + pub id: i32, pub oauth_sub: String, - pub oauth_data: Option, + pub oauth_data: Json, pub nickname: Option, } diff --git a/engine/src/routes/auth.rs b/engine/src/routes/auth.rs index 56dbe00..92d82fa 100644 --- a/engine/src/routes/auth.rs +++ b/engine/src/routes/auth.rs @@ -1,10 +1,11 @@ use crate::state::AppState; use openid::{Options, Token}; -use poem::{web::{Data, Query, Redirect}, IntoResponse}; +use poem::{handler, web::{headers::Header, Data, Query, Redirect}, IntoResponse}; use serde::Deserialize; use std::sync::Arc; -pub async fn login(state: Data>) -> impl IntoResponse { +#[handler] +pub async fn login(state: Data<&Arc>) -> impl IntoResponse { // let discovery_url = "http://localhost:8080/realms/master/.well-known/openid-configuration"; // let http_client = reqwest::Client::new(); @@ -40,7 +41,8 @@ pub struct MyQuery { pub prompt: Option, } -pub async fn callback(query: Query, state: Data>) -> impl IntoResponse { +#[handler] +pub async fn callback(query: Query, state: Data<&Arc>) -> impl IntoResponse { let mut token = state.openid.request_token(&query.code).await.unwrap(); let mut token = Token::from(token); @@ -61,9 +63,9 @@ pub async fn callback(query: Query, state: Data>) -> impl .await .unwrap(); - format!("Hello {:?}", user.nickname); - // TODO: return a token - serde_json::to_string(&user).unwrap() + let token = "hello".to_string(); + + Redirect::temporary("http://localhost:3000/hello").with_header("Set-Cookie", format!("property.v3x.token={}", token)) } diff --git a/engine/src/routes/index.html b/engine/src/routes/index.html new file mode 100644 index 0000000..5d95433 --- /dev/null +++ b/engine/src/routes/index.html @@ -0,0 +1,25 @@ + + + + enstate.rs - Lightweight ENS API + + + + + + + + + + + diff --git a/engine/src/routes/mod.rs b/engine/src/routes/mod.rs index 7ba97c4..25a2881 100644 --- a/engine/src/routes/mod.rs +++ b/engine/src/routes/mod.rs @@ -1,6 +1,6 @@ use std::sync::Arc; -use poem::{get, handler, listener::TcpListener, post, web::Path, EndpointExt, Route, Server}; +use poem::{get, handler, listener::TcpListener, post, web::{Html, Path}, Endpoint, EndpointExt, Route, Server}; use poem_openapi::{param::Query, payload::PlainText, OpenApi, OpenApiService}; use crate::state::AppState; @@ -11,6 +11,7 @@ struct Api; #[OpenApi] impl Api { + /// Testing one two three #[oai(path = "/hello", method = "get")] async fn index(&self, name: Query>) -> PlainText { match name.0 { @@ -20,15 +21,27 @@ impl Api { } } +// returns the html from the index.html file +#[handler] +async fn ui() -> Html<&'static str> { + Html(include_str!("./index.html")) +} + pub async fn serve(state: AppState) -> Result<(), poem::Error> { let api_service = OpenApiService::new(Api, "Hello World", "1.0").server("http://localhost:3000/api"); - let ui = api_service.swagger_ui(); + let spec = api_service.spec_endpoint(); let state = Arc::new(state); - let app = Route::new().nest("/api", api_service).nest("/", ui).data(state); + let app = Route::new() + .at("/login", get(auth::login)) + .at("/callback", get(auth::callback)) + .nest("/api", api_service) + .nest("/openapi.json", spec) + .at("/", get(ui)) + .data(state); // .at("/", get(root)) // .route("/login", get(auth::login)) // // OAuth Callback route