Skip to content

Commit

Permalink
Introduce Sessions endpoint
Browse files Browse the repository at this point in the history
  • Loading branch information
lucemans committed Jul 27, 2024
1 parent 86782d5 commit 06c04ba
Show file tree
Hide file tree
Showing 5 changed files with 68 additions and 62 deletions.
11 changes: 11 additions & 0 deletions engine/src/auth/session.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,4 +41,15 @@ impl SessionState {

Ok(session)
}

pub async fn get_by_user_id(user_id: i32, database: &Database) -> Result<Vec<Self>, sqlx::Error> {
let sessions = sqlx::query_as::<_, SessionState>(
"SELECT * FROM sessions WHERE user_id = $1 AND valid = TRUE",
)
.bind(user_id)
.fetch_all(&database.pool)
.await?;

Ok(sessions)
}
}
42 changes: 1 addition & 41 deletions engine/src/database/mod.rs
Original file line number Diff line number Diff line change
@@ -1,18 +1,4 @@
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;
use uuid::Uuid;

use crate::{auth::session::SessionState, models::user_data::UserData};
use sqlx::{postgres::PgPoolOptions, PgPool};

#[derive(Debug)]
pub struct Database {
Expand All @@ -36,30 +22,4 @@ impl Database {

Ok(())
}

/// 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<UserData, sqlx::Error> {
let sub = oauth_userinfo.sub.as_deref().unwrap();

info!("upsert_get_user: sub: {}", sub);

sqlx::query_as::<_, UserData>(
"INSERT INTO users (oauth_sub, oauth_data) VALUES ($1, $2) ON CONFLICT (oauth_sub) DO UPDATE SET oauth_data = $2 RETURNING *"
)
.bind(sub)
.bind(Json(oauth_userinfo))
.fetch_one(&self.pool).await
}

pub async fn get_user_from_id(&self, id: i32) -> Result<UserData, sqlx::Error> {
let user = sqlx::query_as::<_, UserData>("SELECT * FROM users WHERE id = $1")
.bind(id)
.fetch_one(&self.pool)
.await?;

Ok(user)
}
}
27 changes: 27 additions & 0 deletions engine/src/models/user_data.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
use openid::Userinfo;
use serde::{Deserialize, Serialize};
use sqlx::types::Json;
use tracing::info;

use crate::database::Database;

#[derive(sqlx::FromRow, Debug, Clone, Serialize, Deserialize)]
pub struct UserData {
Expand All @@ -9,3 +12,27 @@ pub struct UserData {
pub oauth_data: Json<Userinfo>,
pub nickname: Option<String>,
}

impl UserData {
pub async fn new(oauth_userinfo: &Userinfo, database: &Database) -> Result<Self, sqlx::Error> {
let sub = oauth_userinfo.sub.as_deref().unwrap();

info!("Initializing new User {:?}", oauth_userinfo);

sqlx::query_as::<_, Self>(
"INSERT INTO users (oauth_sub, oauth_data) VALUES ($1, $2) ON CONFLICT (oauth_sub) DO UPDATE SET oauth_data = $2 RETURNING *"
)
.bind(sub)
.bind(Json(oauth_userinfo))
.fetch_one(&database.pool).await
}

pub async fn get_by_id(id: i32, database: &Database) -> Result<Self, sqlx::Error> {
let user = sqlx::query_as::<_, Self>("SELECT * FROM users WHERE id = $1")
.bind(id)
.fetch_one(&database.pool)
.await?;

Ok(user)
}
}
36 changes: 23 additions & 13 deletions engine/src/routes/auth.rs
Original file line number Diff line number Diff line change
@@ -1,17 +1,13 @@
use crate::{auth::session::SessionState, state::AppState};
use crate::{auth::session::SessionState, models::user_data::UserData, state::AppState};
use openid::{Options, Token};
use poem::{
handler,
http::HeaderMap,
web::{
cookie::{Cookie, CookieJar},
Data, Json, Query, RealIp, Redirect, RemoteAddr,
},
web::{cookie::CookieJar, Data, Json, Query, RealIp, Redirect},
IntoResponse,
};
use serde::Deserialize;
use std::sync::Arc;
use tracing::info;
use uuid::Uuid;

#[handler]
Expand Down Expand Up @@ -72,9 +68,7 @@ pub async fn callback(
format!("Hello {:?}", oauth_userinfo);

// Now we must verify the user information, decide wether they deserve access, and if so return a token.
let user = state
.database
.upsert_get_user(&oauth_userinfo)
let user = UserData::new(&oauth_userinfo, &state.database)
.await
.unwrap();

Expand All @@ -96,13 +90,29 @@ pub async fn me(state: Data<&Arc<AppState>>, cookies: &CookieJar) -> impl IntoRe
let token = cookies.get("property.v3x.token").unwrap();
let token = Uuid::parse_str(token.value_str()).unwrap();

let session = SessionState::get_by_id(token, &state.database).await.unwrap();
let session = SessionState::get_by_id(token, &state.database)
.await
.unwrap();

let user = state
.database
.get_user_from_id(session.user_id)
let user = UserData::get_by_id(session.user_id, &state.database)
.await
.unwrap();

Json(user)
}

#[handler]
pub async fn get_sessions(state: Data<&Arc<AppState>>, cookies: &CookieJar) -> impl IntoResponse {
let token = cookies.get("property.v3x.token").unwrap();
let token = Uuid::parse_str(token.value_str()).unwrap();

let session = SessionState::get_by_id(token, &state.database)
.await
.unwrap();

let sessions = SessionState::get_by_user_id(session.user_id, &state.database)
.await
.unwrap();

Json(sessions)
}
14 changes: 6 additions & 8 deletions engine/src/routes/mod.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
use std::sync::Arc;

use poem::{get, handler, listener::TcpListener, middleware::CookieJarManager, post, web::{Html, Path}, Endpoint, EndpointExt, Route, Server};
use poem::{
get, handler, listener::TcpListener, middleware::CookieJarManager, web::Html, EndpointExt,
Route, Server,
};
use poem_openapi::{param::Query, payload::PlainText, OpenApi, OpenApiService};

use crate::state::AppState;
Expand All @@ -23,7 +26,7 @@ impl Api {

// returns the html from the index.html file
#[handler]
async fn ui() -> Html<&'static str> {
async fn ui() -> Html<&'static str> {
Html(include_str!("./index.html"))
}

Expand All @@ -38,18 +41,13 @@ pub async fn serve(state: AppState) -> Result<(), poem::Error> {
let app = Route::new()
.at("/login", get(auth::login))
.at("/me", get(auth::me))
.at("/sessions", get(auth::get_sessions))
.at("/callback", get(auth::callback))
.nest("/api", api_service)
.nest("/openapi.json", spec)
.at("/", get(ui))
.with(CookieJarManager::new())
.data(state);
// .at("/", get(root))
// .route("/login", get(auth::login))
// // OAuth Callback route
// .route("/callback", get(auth::callback))
// // .route("/devices", get(routes::devices::get))
// .with_state(Arc::new(state));

let listener = TcpListener::bind("0.0.0.0:3000");

Expand Down

0 comments on commit 06c04ba

Please sign in to comment.