use axum::{extract::State, http::HeaderMap, Json};
use std::sync::Arc;
use crate::callback::AuthCallback;
use crate::errors::AppError;
use crate::models::{
ApiKeyResponse, RegenerateApiKeyResponse, ValidateApiKeyRequest, ValidateApiKeyResponse,
};
use crate::repositories::{generate_api_key, ApiKeyEntity};
use crate::services::EmailService;
use crate::utils::authenticate;
use crate::AppState;
pub async fn get_api_key<C: AuthCallback, E: EmailService>(
State(state): State<Arc<AppState<C, E>>>,
headers: HeaderMap,
) -> Result<Json<ApiKeyResponse>, AppError> {
let auth = authenticate(&state, &headers).await?;
let api_key = state
.api_key_repo
.find_by_user_id(auth.user_id)
.await?
.ok_or_else(|| AppError::NotFound("No API key found for user".to_string()))?;
Ok(Json(ApiKeyResponse::from(&api_key)))
}
pub async fn regenerate_api_key<C: AuthCallback, E: EmailService>(
State(state): State<Arc<AppState<C, E>>>,
headers: HeaderMap,
) -> Result<Json<RegenerateApiKeyResponse>, AppError> {
let auth = authenticate(&state, &headers).await?;
state.api_key_repo.delete_for_user(auth.user_id).await?;
let raw_key = generate_api_key();
let entity = ApiKeyEntity::new(auth.user_id, &raw_key);
let created = state.api_key_repo.create(entity).await?;
Ok(Json(RegenerateApiKeyResponse {
api_key: raw_key,
key_prefix: created.key_prefix,
created_at: created.created_at,
message: "Store this key securely. It cannot be retrieved again.".to_string(),
}))
}
pub async fn validate_api_key<C: AuthCallback, E: EmailService>(
State(state): State<Arc<AppState<C, E>>>,
Json(request): Json<ValidateApiKeyRequest>,
) -> Result<Json<ValidateApiKeyResponse>, AppError> {
let api_key = match state.api_key_repo.find_by_key(&request.api_key).await? {
Some(key) => key,
None => {
return Ok(Json(ValidateApiKeyResponse {
valid: false,
user_id: None,
user_email: None,
message: Some("Invalid API key".to_string()),
}));
}
};
state.api_key_repo.update_last_used(api_key.id).await?;
let user = state
.user_repo
.find_by_id(api_key.user_id)
.await?
.ok_or_else(|| AppError::NotFound("User not found".to_string()))?;
Ok(Json(ValidateApiKeyResponse {
valid: true,
user_id: Some(user.id),
user_email: user.email,
message: None,
}))
}