use ::session::AuthedUser; use api::http::{Extension, State}; use api::rest::{AppResponseData, NoData}; use serde::Serialize; use time::OffsetDateTime; use utoipa::ToSchema; use ::bootstrap::AppState; use auth::errors::{ApiError, AuthBusinessError}; #[derive(Debug, Clone, Serialize, ToSchema)] pub struct AccountDeletionDto { pub status: String, pub requested_at: OffsetDateTime, pub purge_after: OffsetDateTime, pub last_error: Option, } impl From for AccountDeletionDto { fn from(value: deletion::AccountDeletionStatus) -> Self { Self { status: value.status, requested_at: value.requested_at, purge_after: value.purge_after, last_error: value.last_error, } } } #[utoipa::path( get, path = "/me/deletion", tag = "account", description = "读取当前账号的删除计划;没有计划时 data 为 null。", responses( (status = 200, description = "deletion status", body = AppResponseData), (status = 401, description = "authentication required", body = AppResponseData) ) )] pub async fn account_deletion_status( State(state): State, AuthedUser(uid): AuthedUser, ) -> Result>, ApiError> { let status = deletion::account_deletion_status(&state, uid) .await .map_err(AuthBusinessError::from)?; Ok(AppResponseData::ok(status.map(AccountDeletionDto::from))) } #[utoipa::path( post, path = "/me/deletion", tag = "account", description = "申请删除当前账号:立即软删并撤销全部会话/令牌/SSH 公钥,宽限期后匿名化。仍有活跃组织 OWNER 身份时返回 409。", responses( (status = 200, description = "deletion scheduled", body = AppResponseData), (status = 409, description = "account still owns an active organization", body = AppResponseData), (status = 401, description = "authentication required", body = AppResponseData) ) )] pub async fn request_account_deletion( State(state): State, Extension(accounts): Extension, AuthedUser(uid): AuthedUser, ) -> Result, ApiError> { let status = deletion::request_account_deletion( &state, &accounts, uid, "user requested account deletion", ) .await .map_err(AuthBusinessError::from)?; Ok(AppResponseData::ok(status.into())) } #[utoipa::path( delete, path = "/me/deletion", tag = "account", description = "撤销尚未执行的账号删除计划;已撤销的会话与令牌不会恢复,需重新登录。", responses( (status = 200, description = "deletion cancelled", body = AppResponseData), (status = 404, description = "no deletion is pending", body = AppResponseData), (status = 409, description = "account deletion is currently being purged", body = AppResponseData), (status = 401, description = "authentication required", body = AppResponseData) ) )] pub async fn cancel_account_deletion( State(state): State, Extension(accounts): Extension, AuthedUser(uid): AuthedUser, ) -> Result, ApiError> { deletion::cancel_account_deletion(&state, &accounts, uid) .await .map_err(AuthBusinessError::from)?; Ok(AppResponseData::empty()) }