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