#[cfg(feature = "auth-provider")]
pub mod provider;
mod schema;
mod utils;
pub use ft_sys_shared::SESSION_KEY;
pub use schema::fastn_user;
pub use utils::{user_data_by_query, Counter};
#[derive(Clone, Debug)]
pub struct UserId(pub i64);
#[derive(serde::Serialize, serde::Deserialize, Clone, Debug, Default)]
#[serde(default)]
pub struct ProviderData {
pub identity: String,
pub username: Option<String>,
pub name: Option<String>,
pub emails: Vec<String>,
pub verified_emails: Vec<String>,
pub profile_picture: Option<String>,
pub custom: serde_json::Value,
}
impl ProviderData {
pub fn get_custom<T: serde::de::DeserializeOwned>(&self, key: &str) -> Option<T> {
self.custom
.get(key)
.and_then(|v| serde_json::from_value(v.clone()).ok())
}
pub fn first_email(&self) -> Option<String> {
self.verified_emails
.first()
.cloned()
.or_else(|| self.emails.first().cloned())
}
}
pub fn user_id() -> Option<UserId> {
todo!()
}
pub fn username(_provider: &str) -> Option<String> {
todo!()
}
pub fn get_user_data() -> std::collections::HashMap<String, ProviderData> {
todo!()
}
pub fn is_authenticated() -> bool {
todo!()
}
pub fn provider_ids(_provider: &str) -> Vec<String> {
todo!()
}
pub fn session_provider_ids(_provider: &str) -> Vec<String> {
todo!()
}
pub fn providers() -> Vec<String> {
todo!()
}
pub fn session_providers() -> Vec<String> {
todo!()
}
#[cfg(feature = "field-extractors")]
pub fn ud(
cookie: ft_sdk::Cookie<SESSION_KEY>,
conn: &mut ft_sdk::Connection,
) -> Result<Option<ft_sys::UserData>, UserDataError> {
if let Some(v) = ft_sys::env::var("DEBUG_LOGGED_IN".to_string()) {
let mut v = v.splitn(4, ' ');
return Ok(Some(ft_sys::UserData {
id: v.next().unwrap().parse().unwrap(),
identity: v.next().unwrap_or_default().to_string(),
name: v.next().map(|v| v.to_string()).unwrap_or_default(),
email: v.next().map(|v| v.to_string()).unwrap_or_default(),
verified_email: true,
}));
}
ft_sdk::println!("sid: {cookie}");
let sid = match cookie.0 {
Some(v) => v,
None => return Ok(None),
};
let (UserId(id), identity, data) = match utils::user_data_by_query(
conn,
r#"
SELECT
fastn_user.id as id, identity, fastn_user.data -> 'email' as data
FROM fastn_user
JOIN fastn_session
WHERE
fastn_session.id = $1
AND fastn_user.id = fastn_session.uid
"#,
sid.as_str(),
) {
Ok(v) => v,
Err(UserDataError::NoDataFound) => return Ok(None),
Err(e) => return Err(e),
};
let email = data
.first_email()
.expect("email provider must have an email");
Ok(Some(ft_sys::UserData {
id,
identity: identity.expect("user fetched from session cookie must have identity"),
name: data.name.unwrap_or_default(),
email,
verified_email: !data.verified_emails.is_empty(),
}))
}
#[derive(Debug, thiserror::Error)]
pub enum UserDataError {
#[error("no data found for the provider")]
NoDataFound,
#[error("multiple rows found")]
MultipleRowsFound,
#[error("db error: {0:?}")]
DatabaseError(#[from] diesel::result::Error),
#[error("failed to deserialize data from db: {0:?}")]
FailedToDeserializeData(#[from] serde_json::Error),
}