1#[cfg(feature = "auth-provider")]
2pub mod provider;
3mod schema;
4mod utils;
5
6pub use ft_sys_shared::SESSION_KEY;
7pub use schema::fastn_user;
8pub use utils::{user_data_by_query, Counter};
9
10#[derive(Clone, Debug)]
11pub struct UserId(pub i64);
12
13#[derive(serde::Serialize, serde::Deserialize, Clone, Debug, Default)]
14#[serde(default)]
15pub struct ProviderData {
16 pub identity: String,
17 pub username: Option<String>,
18 pub name: Option<String>,
19 pub emails: Vec<String>,
20 pub verified_emails: Vec<String>,
21 pub profile_picture: Option<String>,
22 pub custom: serde_json::Value,
23}
24
25impl ProviderData {
26 pub fn get_custom<T: serde::de::DeserializeOwned>(&self, key: &str) -> Option<T> {
27 self.custom
28 .get(key)
29 .and_then(|v| serde_json::from_value(v.clone()).ok())
30 }
31
32 pub fn first_email(&self) -> Option<String> {
34 self.verified_emails
35 .first()
36 .cloned()
37 .or_else(|| self.emails.first().cloned())
38 }
39}
40
41pub fn user_id() -> Option<UserId> {
43 todo!()
44}
45
46pub fn username(_provider: &str) -> Option<String> {
48 todo!()
49}
50
51pub fn get_user_data() -> std::collections::HashMap<String, ProviderData> {
54 todo!()
55}
56
57pub fn is_authenticated() -> bool {
58 todo!()
59}
60
61pub fn provider_ids(_provider: &str) -> Vec<String> {
63 todo!()
64}
65
66pub fn session_provider_ids(_provider: &str) -> Vec<String> {
68 todo!()
69}
70
71pub fn providers() -> Vec<String> {
74 todo!()
75}
76
77pub fn session_providers() -> Vec<String> {
79 todo!()
80}
81
82#[cfg(feature = "field-extractors")]
83pub fn ud(
84 cookie: ft_sdk::Cookie<SESSION_KEY>,
85 conn: &mut ft_sdk::Connection,
86) -> Result<Option<ft_sys::UserData>, UserDataError> {
87 if let Some(v) = ft_sys::env::var("DEBUG_LOGGED_IN".to_string()) {
88 let mut v = v.splitn(4, ' ');
89 return Ok(Some(ft_sys::UserData {
90 id: v.next().unwrap().parse().unwrap(),
91 identity: v.next().unwrap_or_default().to_string(),
92 name: v.next().map(|v| v.to_string()).unwrap_or_default(),
93 email: v.next().map(|v| v.to_string()).unwrap_or_default(),
94 verified_email: true,
95 }));
96 }
97
98 ft_sdk::println!("sid: {cookie}");
99
100 let sid = match cookie.0 {
101 Some(v) => v,
102 None => return Ok(None),
103 };
104
105 let (UserId(id), identity, data) = match utils::user_data_by_query(
106 conn,
107 r#"
108 SELECT
109 fastn_user.id as id, identity, fastn_user.data -> 'email' as data
110 FROM fastn_user
111 JOIN fastn_session
112 WHERE
113 fastn_session.id = $1
114 AND fastn_user.id = fastn_session.uid
115 "#,
116 sid.as_str(),
117 ) {
118 Ok(v) => v,
119 Err(UserDataError::NoDataFound) => return Ok(None),
120 Err(e) => return Err(e),
121 };
122
123 let email = data
124 .first_email()
125 .expect("email provider must have an email");
126
127 Ok(Some(ft_sys::UserData {
128 id,
129 identity: identity.expect("user fetched from session cookie must have identity"),
130 name: data.name.unwrap_or_default(),
131 email,
132 verified_email: !data.verified_emails.is_empty(),
133 }))
134}
135
136#[derive(Debug, thiserror::Error)]
137pub enum UserDataError {
138 #[error("no data found for the provider")]
139 NoDataFound,
140 #[error("multiple rows found")]
141 MultipleRowsFound,
142 #[error("db error: {0:?}")]
143 DatabaseError(#[from] diesel::result::Error),
144 #[error("failed to deserialize data from db: {0:?}")]
145 FailedToDeserializeData(#[from] serde_json::Error),
146}