main
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<String>,
}
impl From<deletion::AccountDeletionStatus> 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<AccountDeletionDto>),
(status = 401, description = "authentication required", body = AppResponseData<NoData>)
)
)]
pub async fn account_deletion_status(
State(state): State<AppState>,
AuthedUser(uid): AuthedUser,
) -> Result<AppResponseData<Option<AccountDeletionDto>>, 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<AccountDeletionDto>),
(status = 409, description = "account still owns an active organization", body = AppResponseData<NoData>),
(status = 401, description = "authentication required", body = AppResponseData<NoData>)
)
)]
pub async fn request_account_deletion(
State(state): State<AppState>,
Extension(accounts): Extension<auth::Accounts>,
AuthedUser(uid): AuthedUser,
) -> Result<AppResponseData<AccountDeletionDto>, 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<NoData>),
(status = 404, description = "no deletion is pending", body = AppResponseData<NoData>),
(status = 409, description = "account deletion is currently being purged", body = AppResponseData<NoData>),
(status = 401, description = "authentication required", body = AppResponseData<NoData>)
)
)]
pub async fn cancel_account_deletion(
State(state): State<AppState>,
Extension(accounts): Extension<auth::Accounts>,
AuthedUser(uid): AuthedUser,
) -> Result<AppResponseData<NoData>, ApiError> {
deletion::cancel_account_deletion(&state, &accounts, uid)
.await
.map_err(AuthBusinessError::from)?;
Ok(AppResponseData::empty())
}