chatgpt
This commit is contained in:
commit
a9d22e8312
18 changed files with 2308 additions and 0 deletions
210
src/db.rs
Normal file
210
src/db.rs
Normal file
|
|
@ -0,0 +1,210 @@
|
|||
use anyhow::Result;
|
||||
use chrono::{DateTime, Utc};
|
||||
use serde_json::Value;
|
||||
use sha2::{Digest, Sha256};
|
||||
use sqlx::{PgPool, Postgres, Transaction};
|
||||
|
||||
use crate::model::DetectedCrossing;
|
||||
|
||||
pub fn hash_token(token: &str) -> Vec<u8> {
|
||||
let mut hasher = Sha256::new();
|
||||
hasher.update(token.as_bytes());
|
||||
hasher.finalize().to_vec()
|
||||
}
|
||||
|
||||
pub async fn create_session(
|
||||
db: &PgPool,
|
||||
athlete_id: i64,
|
||||
token: &str,
|
||||
) -> Result<()> {
|
||||
let hash = hash_token(token);
|
||||
|
||||
sqlx::query(
|
||||
r#"
|
||||
INSERT INTO sessions (
|
||||
token_hash,
|
||||
athlete_id
|
||||
)
|
||||
VALUES ($1, $2)
|
||||
"#,
|
||||
)
|
||||
.bind(hash)
|
||||
.bind(athlete_id)
|
||||
.execute(db)
|
||||
.await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn athlete_for_session(
|
||||
db: &PgPool,
|
||||
token: &str,
|
||||
) -> Result<Option<(i64, String)>> {
|
||||
let hash = hash_token(token);
|
||||
|
||||
let row = sqlx::query(
|
||||
r#"
|
||||
SELECT
|
||||
a.id,
|
||||
a.display_name
|
||||
FROM sessions s
|
||||
JOIN athletes a
|
||||
ON a.id = s.athlete_id
|
||||
WHERE s.token_hash = $1
|
||||
"#,
|
||||
)
|
||||
.bind(hash)
|
||||
.fetch_optional(db)
|
||||
.await?;
|
||||
|
||||
use sqlx::Row;
|
||||
|
||||
if let Some(row) = row {
|
||||
let id: i64 = row.try_get("id")?;
|
||||
let name: String = row.try_get("display_name")?;
|
||||
|
||||
sqlx::query(
|
||||
"UPDATE sessions SET last_seen_at = now() WHERE token_hash = $1",
|
||||
)
|
||||
.bind(hash)
|
||||
.execute(db)
|
||||
.await?;
|
||||
|
||||
Ok(Some((id, name)))
|
||||
} else {
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn delete_old_oauth_states(
|
||||
db: &PgPool,
|
||||
) -> Result<()> {
|
||||
sqlx::query(
|
||||
"DELETE FROM oauth_states WHERE created_at < now() - interval '10 minutes'",
|
||||
)
|
||||
.execute(db)
|
||||
.await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn ensure_activity(
|
||||
tx: &mut Transaction<'_, Postgres>,
|
||||
athlete_id: i64,
|
||||
intervals_activity_id: &str,
|
||||
start_time: DateTime<Utc>,
|
||||
activity_json: &Value,
|
||||
) -> Result<i64> {
|
||||
let row = sqlx::query(
|
||||
r#"
|
||||
INSERT INTO activities (
|
||||
athlete_id,
|
||||
intervals_activity_id,
|
||||
start_time,
|
||||
activity_json,
|
||||
processed_at
|
||||
)
|
||||
VALUES ($1, $2, $3, $4, NULL)
|
||||
|
||||
ON CONFLICT (
|
||||
athlete_id,
|
||||
intervals_activity_id
|
||||
)
|
||||
DO UPDATE SET
|
||||
start_time = EXCLUDED.start_time,
|
||||
activity_json = EXCLUDED.activity_json,
|
||||
processed_at = NULL
|
||||
|
||||
RETURNING id
|
||||
"#,
|
||||
)
|
||||
.bind(athlete_id)
|
||||
.bind(intervals_activity_id)
|
||||
.bind(start_time)
|
||||
.bind(activity_json)
|
||||
.fetch_one(&mut **tx)
|
||||
.await?;
|
||||
|
||||
use sqlx::Row;
|
||||
|
||||
Ok(row.try_get("id")?)
|
||||
}
|
||||
|
||||
pub async fn delete_activity_crossings(
|
||||
tx: &mut Transaction<'_, Postgres>,
|
||||
activity_id: i64,
|
||||
) -> Result<()> {
|
||||
sqlx::query(
|
||||
"DELETE FROM county_crossings WHERE activity_id = $1",
|
||||
)
|
||||
.bind(activity_id)
|
||||
.execute(&mut **tx)
|
||||
.await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn save_crossing(
|
||||
tx: &mut Transaction<'_, Postgres>,
|
||||
activity_id: i64,
|
||||
crossing: &DetectedCrossing,
|
||||
interval: Option<&Value>,
|
||||
) -> Result<()> {
|
||||
sqlx::query(
|
||||
r#"
|
||||
INSERT INTO county_crossings (
|
||||
activity_id,
|
||||
track_index,
|
||||
crossing_time,
|
||||
location,
|
||||
from_county_id,
|
||||
to_county_id,
|
||||
intervals_interval
|
||||
)
|
||||
VALUES (
|
||||
$1,
|
||||
$2,
|
||||
$3,
|
||||
|
||||
ST_SetSRID(
|
||||
ST_MakePoint($4, $5),
|
||||
4326
|
||||
),
|
||||
|
||||
$6,
|
||||
$7,
|
||||
$8
|
||||
)
|
||||
"#,
|
||||
)
|
||||
.bind(activity_id)
|
||||
.bind(crossing.track_index as i64)
|
||||
.bind(crossing.crossing_time)
|
||||
.bind(crossing.lon)
|
||||
.bind(crossing.lat)
|
||||
.bind(crossing.from_county_id)
|
||||
.bind(crossing.to_county_id)
|
||||
.bind(interval)
|
||||
.execute(&mut **tx)
|
||||
.await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn mark_activity_processed(
|
||||
tx: &mut Transaction<'_, Postgres>,
|
||||
activity_id: i64,
|
||||
) -> Result<()> {
|
||||
sqlx::query(
|
||||
r#"
|
||||
UPDATE activities
|
||||
SET processed_at = now()
|
||||
WHERE id = $1
|
||||
"#,
|
||||
)
|
||||
.bind(activity_id)
|
||||
.execute(&mut **tx)
|
||||
.await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
Loading…
Reference in a new issue