205 lines
4.3 KiB
Rust
205 lines
4.3 KiB
Rust
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(
|
|
r#"
|
|
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(
|
|
r#"
|
|
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(
|
|
r#"
|
|
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(())
|
|
}
|
|
|
|
pub async fn delete_session(db: &PgPool, token: &str) -> Result<()> {
|
|
let hash = hash_token(token);
|
|
|
|
sqlx::query("DELETE FROM sessions WHERE token_hash = $1")
|
|
.bind(&hash)
|
|
.execute(db)
|
|
.await?;
|
|
|
|
Ok(())
|
|
}
|