feat(data): SyncProvider::delete_account + SolitaireServerClient impl
Adds delete_account() as a default no-op on the SyncProvider trait. SolitaireServerClient sends DELETE /api/account with JWT (retry on 401). The server handler already existed (DELETE /api/account, ON DELETE CASCADE). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -51,6 +51,11 @@ pub trait SyncProvider: Send + Sync {
|
|||||||
async fn opt_out_leaderboard(&self) -> Result<(), SyncError> {
|
async fn opt_out_leaderboard(&self) -> Result<(), SyncError> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
/// Permanently delete the authenticated player's account and all server
|
||||||
|
/// data. No-op for backends that don't support account management.
|
||||||
|
async fn delete_account(&self) -> Result<(), SyncError> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Blanket impl so `Box<dyn SyncProvider + Send + Sync>` (returned by
|
/// Blanket impl so `Box<dyn SyncProvider + Send + Sync>` (returned by
|
||||||
@@ -84,6 +89,9 @@ impl SyncProvider for Box<dyn SyncProvider + Send + Sync> {
|
|||||||
async fn opt_out_leaderboard(&self) -> Result<(), SyncError> {
|
async fn opt_out_leaderboard(&self) -> Result<(), SyncError> {
|
||||||
(**self).opt_out_leaderboard().await
|
(**self).opt_out_leaderboard().await
|
||||||
}
|
}
|
||||||
|
async fn delete_account(&self) -> Result<(), SyncError> {
|
||||||
|
(**self).delete_account().await
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub mod stats;
|
pub mod stats;
|
||||||
|
|||||||
@@ -295,6 +295,40 @@ impl SyncProvider for SolitaireServerClient {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn delete_account(&self) -> Result<(), SyncError> {
|
||||||
|
let token = self.access_token()?;
|
||||||
|
let url = format!("{}/api/account", self.base_url);
|
||||||
|
|
||||||
|
let resp = self
|
||||||
|
.client
|
||||||
|
.delete(&url)
|
||||||
|
.bearer_auth(&token)
|
||||||
|
.send()
|
||||||
|
.await
|
||||||
|
.map_err(|e| SyncError::Network(e.to_string()))?;
|
||||||
|
|
||||||
|
if resp.status() == reqwest::StatusCode::UNAUTHORIZED {
|
||||||
|
self.refresh_token().await?;
|
||||||
|
let new_token = self.access_token()?;
|
||||||
|
let resp = self
|
||||||
|
.client
|
||||||
|
.delete(&url)
|
||||||
|
.bearer_auth(new_token)
|
||||||
|
.send()
|
||||||
|
.await
|
||||||
|
.map_err(|e| SyncError::Network(e.to_string()))?;
|
||||||
|
if !resp.status().is_success() {
|
||||||
|
return Err(SyncError::Auth(format!("delete account failed: {}", resp.status())));
|
||||||
|
}
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
if !resp.status().is_success() {
|
||||||
|
return Err(SyncError::Auth(format!("delete account failed: {}", resp.status())));
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
async fn fetch_leaderboard(&self) -> Result<Vec<LeaderboardEntry>, SyncError> {
|
async fn fetch_leaderboard(&self) -> Result<Vec<LeaderboardEntry>, SyncError> {
|
||||||
let token = self.access_token()?;
|
let token = self.access_token()?;
|
||||||
let url = format!("{}/api/leaderboard", self.base_url);
|
let url = format!("{}/api/leaderboard", self.base_url);
|
||||||
|
|||||||
Reference in New Issue
Block a user