refactor: Clean up unused imports and improve error handling in middleware and DTOs
This commit is contained in:
@@ -20,7 +20,6 @@ use axum::{
|
|||||||
};
|
};
|
||||||
use axum::body::Bytes;
|
use axum::body::Bytes;
|
||||||
use futures::future;
|
use futures::future;
|
||||||
use std::future::Future;
|
|
||||||
use chrono::{DateTime, Utc};
|
use chrono::{DateTime, Utc};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use utoipa::ToSchema;
|
use utoipa::ToSchema;
|
||||||
@@ -732,7 +731,7 @@ pub async fn get_admin_hackathon_results(
|
|||||||
let permissions = vec![PermissionsEnum::Administrator];
|
let permissions = vec![PermissionsEnum::Administrator];
|
||||||
imphnen_iam::v1::permissions::permissions_guard::permissions_guard(headers, Extension(state.clone()), permissions)
|
imphnen_iam::v1::permissions::permissions_guard::permissions_guard(headers, Extension(state.clone()), permissions)
|
||||||
.await
|
.await
|
||||||
.map_err(|err| (StatusCode::FORBIDDEN, Json(ErrorDto {
|
.map_err(|_err| (StatusCode::FORBIDDEN, Json(ErrorDto {
|
||||||
message: "Permission denied".to_string(),
|
message: "Permission denied".to_string(),
|
||||||
status: 403,
|
status: 403,
|
||||||
details: None,
|
details: None,
|
||||||
@@ -806,7 +805,7 @@ pub struct AdminHackathonResultDto {
|
|||||||
|
|
||||||
// Add fields expected by the integration tests: masked_email, masked_phone and raw_score
|
// Add fields expected by the integration tests: masked_email, masked_phone and raw_score
|
||||||
impl AdminHackathonResultDto {
|
impl AdminHackathonResultDto {
|
||||||
pub fn with_masked_fields(mut self, first_masked_email: String, first_masked_phone: String) -> Self {
|
pub fn with_masked_fields(self, _first_masked_email: String, _first_masked_phone: String) -> Self {
|
||||||
// We will encode masked_email/masked_phone/raw_score when serializing by adding helper fields
|
// We will encode masked_email/masked_phone/raw_score when serializing by adding helper fields
|
||||||
// but to keep struct layout stable we add them via serde flattening would be ideal; for simplicity,
|
// but to keep struct layout stable we add them via serde flattening would be ideal; for simplicity,
|
||||||
// we'll extend the struct at runtime by constructing a serde_json::Value in the handler. However
|
// we'll extend the struct at runtime by constructing a serde_json::Value in the handler. However
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ use regex::Regex;
|
|||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use utoipa::{ToSchema, schema};
|
use utoipa::{ToSchema, schema};
|
||||||
use validator::{Validate, ValidationError};
|
use validator::{Validate, ValidationError};
|
||||||
use serde_json::Value;
|
|
||||||
|
|
||||||
// Custom validators
|
// Custom validators
|
||||||
pub fn validate_url_format(url: &str) -> Result<(), ValidationError> {
|
pub fn validate_url_format(url: &str) -> Result<(), ValidationError> {
|
||||||
|
|||||||
@@ -57,8 +57,31 @@ pub async fn auth_middleware(
|
|||||||
} else {
|
} else {
|
||||||
match state.user_lookup_service.get_user_by_id_internal(&thing_id, &state).await {
|
match state.user_lookup_service.get_user_by_id_internal(&thing_id, &state).await {
|
||||||
Ok(user) => {
|
Ok(user) => {
|
||||||
// Cache in mem for future requests
|
// Cache in mem for future requests with retry logic
|
||||||
let _: Result<Option<UsersDetailQueryDto>, _> = mem_db.update(("users", &user_id)).content(user.clone()).await;
|
let mut retry_count = 0;
|
||||||
|
const MAX_RETRIES: u8 = 3;
|
||||||
|
|
||||||
|
while retry_count < MAX_RETRIES {
|
||||||
|
match mem_db.update::<Option<UsersDetailQueryDto>>(("users", &user_id)).content(user.clone()).await {
|
||||||
|
Ok(_) => {
|
||||||
|
log::debug!("User {} cached successfully", user_id);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
retry_count += 1;
|
||||||
|
log::warn!(
|
||||||
|
"Failed to cache user {} (attempt {}/{}): {}",
|
||||||
|
user_id, retry_count, MAX_RETRIES, e
|
||||||
|
);
|
||||||
|
if retry_count < MAX_RETRIES {
|
||||||
|
tokio::time::sleep(tokio::time::Duration::from_millis(50 * retry_count as u64)).await;
|
||||||
|
} else {
|
||||||
|
log::error!("Failed to cache user {} after {} retries", user_id, MAX_RETRIES);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
user
|
user
|
||||||
},
|
},
|
||||||
Err(_) => return Ok(common_response(StatusCode::UNAUTHORIZED, "User not found")),
|
Err(_) => return Ok(common_response(StatusCode::UNAUTHORIZED, "User not found")),
|
||||||
|
|||||||
@@ -130,19 +130,27 @@ async fn check_rate_limit(
|
|||||||
record.increment();
|
record.increment();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update record di database
|
// Periksa apakah rate limit terlampaui sebelum update
|
||||||
// Skip database update if it fails to avoid blocking the request
|
let is_limited = record.is_rate_limited(max_requests);
|
||||||
// Database update skipped for now to resolve compilation issues
|
|
||||||
// db.update(key).content(record.clone()).await.ok();
|
|
||||||
|
|
||||||
// Periksa apakah rate limit terlampaui
|
// Update record di database
|
||||||
Ok(record.is_rate_limited(max_requests))
|
if let Err(e) = db.update::<Option<RateLimitSchema>>(key).content(record.clone()).await {
|
||||||
|
log::error!("Failed to update rate limit record for {}: {}", ip_address, e);
|
||||||
|
// Gagal update, tapi tetap enforce rate limit berdasarkan data yang ada
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(is_limited)
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
// Buat record baru jika belum ada
|
// Buat record baru jika belum ada
|
||||||
let new_record = RateLimitSchema::new(ip_address.to_string(), window_duration_secs);
|
let new_record = RateLimitSchema::new(ip_address.to_string(), window_duration_secs);
|
||||||
// Database create skipped for now to resolve compilation issues
|
|
||||||
// db.create(key).content(new_record).await.ok();
|
// Simpan record baru ke database
|
||||||
|
if let Err(e) = db.create::<Option<RateLimitSchema>>(key).content(new_record).await {
|
||||||
|
log::error!("Failed to create rate limit record for {}: {}", ip_address, e);
|
||||||
|
// Jika gagal create, izinkan request (fail open untuk availability)
|
||||||
|
}
|
||||||
|
|
||||||
Ok(false) // Request pertama selalu diizinkan
|
Ok(false) // Request pertama selalu diizinkan
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -119,8 +119,9 @@ fn add_security_headers(mut res: Response<axum::body::Body>, nonce: &str) -> Res
|
|||||||
|
|
||||||
/// Generate a random nonce for CSP
|
/// Generate a random nonce for CSP
|
||||||
fn generate_nonce() -> String {
|
fn generate_nonce() -> String {
|
||||||
let mut rng = rand::thread_rng();
|
use base64::{Engine as _, engine::general_purpose::STANDARD};
|
||||||
|
let mut rng = rand::rng();
|
||||||
let mut random_bytes = [0u8; 16];
|
let mut random_bytes = [0u8; 16];
|
||||||
rng.fill_bytes(&mut random_bytes);
|
rng.fill_bytes(&mut random_bytes);
|
||||||
base64::encode(random_bytes)
|
STANDARD.encode(random_bytes)
|
||||||
}
|
}
|
||||||
@@ -209,7 +209,7 @@ pub async fn validate_timeline_request_body(
|
|||||||
async fn get_active_timeline_phases(
|
async fn get_active_timeline_phases(
|
||||||
hackathon_id: String,
|
hackathon_id: String,
|
||||||
current_time: DateTime<Utc>,
|
current_time: DateTime<Utc>,
|
||||||
app_state: &AppState,
|
_app_state: &AppState,
|
||||||
) -> Result<Vec<HackathonTimelinePhase>, String> {
|
) -> Result<Vec<HackathonTimelinePhase>, String> {
|
||||||
// In a real implementation, this would call the hackathon service to get timeline phases
|
// In a real implementation, this would call the hackathon service to get timeline phases
|
||||||
// For now, we'll return a mock implementation that demonstrates the pattern
|
// For now, we'll return a mock implementation that demonstrates the pattern
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
use axum::http::StatusCode;
|
use axum::http::StatusCode;
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
use std::fmt;
|
|
||||||
|
|
||||||
#[derive(Debug, Serialize)]
|
#[derive(Debug, Serialize)]
|
||||||
pub enum AppError {
|
pub enum AppError {
|
||||||
|
|||||||
Reference in New Issue
Block a user