this repo has no description
1use chrono::{DateTime, Utc};
2use sqlx::PgPool;
3
4use super::super::{DeviceData, OAuthError};
5
6pub struct DeviceAccountRow {
7 pub did: String,
8 pub handle: String,
9 pub email: Option<String>,
10 pub last_used_at: DateTime<Utc>,
11}
12
13pub async fn create_device(
14 pool: &PgPool,
15 device_id: &str,
16 data: &DeviceData,
17) -> Result<(), OAuthError> {
18 sqlx::query!(
19 r#"
20 INSERT INTO oauth_device (id, session_id, user_agent, ip_address, last_seen_at)
21 VALUES ($1, $2, $3, $4, $5)
22 "#,
23 device_id,
24 data.session_id,
25 data.user_agent,
26 data.ip_address,
27 data.last_seen_at,
28 )
29 .execute(pool)
30 .await?;
31
32 Ok(())
33}
34
35pub async fn get_device(pool: &PgPool, device_id: &str) -> Result<Option<DeviceData>, OAuthError> {
36 let row = sqlx::query!(
37 r#"
38 SELECT session_id, user_agent, ip_address, last_seen_at
39 FROM oauth_device
40 WHERE id = $1
41 "#,
42 device_id
43 )
44 .fetch_optional(pool)
45 .await?;
46
47 Ok(row.map(|r| DeviceData {
48 session_id: r.session_id,
49 user_agent: r.user_agent,
50 ip_address: r.ip_address,
51 last_seen_at: r.last_seen_at,
52 }))
53}
54
55pub async fn update_device_last_seen(
56 pool: &PgPool,
57 device_id: &str,
58) -> Result<(), OAuthError> {
59 sqlx::query!(
60 r#"
61 UPDATE oauth_device
62 SET last_seen_at = NOW()
63 WHERE id = $1
64 "#,
65 device_id
66 )
67 .execute(pool)
68 .await?;
69
70 Ok(())
71}
72
73pub async fn delete_device(pool: &PgPool, device_id: &str) -> Result<(), OAuthError> {
74 sqlx::query!(
75 r#"
76 DELETE FROM oauth_device WHERE id = $1
77 "#,
78 device_id
79 )
80 .execute(pool)
81 .await?;
82
83 Ok(())
84}
85
86pub async fn upsert_account_device(
87 pool: &PgPool,
88 did: &str,
89 device_id: &str,
90) -> Result<(), OAuthError> {
91 sqlx::query!(
92 r#"
93 INSERT INTO oauth_account_device (did, device_id, created_at, updated_at)
94 VALUES ($1, $2, NOW(), NOW())
95 ON CONFLICT (did, device_id) DO UPDATE SET updated_at = NOW()
96 "#,
97 did,
98 device_id
99 )
100 .execute(pool)
101 .await?;
102
103 Ok(())
104}
105
106pub async fn get_device_accounts(
107 pool: &PgPool,
108 device_id: &str,
109) -> Result<Vec<DeviceAccountRow>, OAuthError> {
110 let rows = sqlx::query!(
111 r#"
112 SELECT u.did, u.handle, u.email, ad.updated_at as last_used_at
113 FROM oauth_account_device ad
114 JOIN users u ON u.did = ad.did
115 WHERE ad.device_id = $1
116 AND u.deactivated_at IS NULL
117 AND u.takedown_ref IS NULL
118 ORDER BY ad.updated_at DESC
119 "#,
120 device_id
121 )
122 .fetch_all(pool)
123 .await?;
124
125 Ok(rows
126 .into_iter()
127 .map(|r| DeviceAccountRow {
128 did: r.did,
129 handle: r.handle,
130 email: r.email,
131 last_used_at: r.last_used_at,
132 })
133 .collect())
134}
135
136pub async fn verify_account_on_device(
137 pool: &PgPool,
138 device_id: &str,
139 did: &str,
140) -> Result<bool, OAuthError> {
141 let row = sqlx::query!(
142 r#"
143 SELECT 1 as exists
144 FROM oauth_account_device ad
145 JOIN users u ON u.did = ad.did
146 WHERE ad.device_id = $1
147 AND ad.did = $2
148 AND u.deactivated_at IS NULL
149 AND u.takedown_ref IS NULL
150 "#,
151 device_id,
152 did
153 )
154 .fetch_optional(pool)
155 .await?;
156
157 Ok(row.is_some())
158}