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