- Enforce axum best practices across all 13 workspace crates (max 200 LOC/file, no comments, no unwrap, clean architecture) - Fix domain→infrastructure dependency inversions in imphnen-iam and imphnen-dimentorin - Extract imphnen-storage (MinIO) and imphnen-email (Lettre) as standalone crates - Centralize all config in ENV struct: CDN_URL, CORS_ALLOWED_ORIGINS - Centralize SMTP through imphnen-email; remove dead HackathonConfig - Centralize database: QR crate now shares main DB pool (single DATABASE_URL) - Rename QR users table to qr_users to avoid collision with main users table - Merge imphnen-qr into imphnen-cms/src/qr (13 crates, down from 14) - Restructure imphnen-hackathon flat modules into clean architecture - Remove all stale env vars from .env.example (SurrealDB, QR_JWT, Hackathon infra) - Fix Dockerfile to include all current workspace crates - Bump all crate versions 0.2.0 → 0.3.0 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
95 lines
2.9 KiB
Rust
95 lines
2.9 KiB
Rust
use super::super::dto::{MentorAvailabilityDto, SessionListResponseDto};
|
|
use crate::sessions::domain::SessionService;
|
|
use axum::{
|
|
extract::{Extension, Path, Query},
|
|
http::HeaderMap,
|
|
response::IntoResponse,
|
|
};
|
|
use imphnen_utils::AppError;
|
|
use imphnen_utils::{ApiSuccess, extract_email};
|
|
use serde::Deserialize;
|
|
use std::sync::Arc;
|
|
|
|
#[derive(Deserialize)]
|
|
pub struct SessionStatusFilter {
|
|
pub status: Option<String>,
|
|
}
|
|
|
|
#[utoipa::path(
|
|
get,
|
|
path = "/v1/mentors/{id}/sessions",
|
|
tag = "sessions",
|
|
security(("Bearer" = [])),
|
|
params(
|
|
("id" = String, Path, description = "Mentor ID"),
|
|
("status" = Option<String>, Query, description = "Filter by status"),
|
|
),
|
|
responses(
|
|
(status = 200, description = "Sessions retrieved successfully", body = SessionListResponseDto),
|
|
(status = 401, description = "Unauthorized"),
|
|
(status = 404, description = "Mentor not found"),
|
|
)
|
|
)]
|
|
pub async fn get_mentor_sessions(
|
|
headers: HeaderMap,
|
|
Extension(service): Extension<Arc<dyn SessionService>>,
|
|
Path(mentor_id): Path<String>,
|
|
Query(filter): Query<SessionStatusFilter>,
|
|
) -> Result<impl IntoResponse, AppError> {
|
|
let _user_email = extract_email(&headers)
|
|
.ok_or_else(|| AppError::AuthenticationError("Token tidak valid".to_string()))?;
|
|
let resp = SessionListResponseDto::from(
|
|
service
|
|
.get_mentor_sessions(mentor_id, filter.status)
|
|
.await?,
|
|
);
|
|
Ok(ApiSuccess(resp))
|
|
}
|
|
|
|
#[utoipa::path(
|
|
get,
|
|
path = "/v1/mentors/{id}/availability",
|
|
tag = "sessions",
|
|
params(
|
|
("id" = String, Path, description = "Mentor ID"),
|
|
),
|
|
responses(
|
|
(status = 200, description = "Availability retrieved successfully", body = MentorAvailabilityDto),
|
|
(status = 404, description = "Mentor not found"),
|
|
)
|
|
)]
|
|
pub async fn get_mentor_availability(
|
|
Extension(service): Extension<Arc<dyn SessionService>>,
|
|
Path(mentor_id): Path<String>,
|
|
) -> Result<impl IntoResponse, AppError> {
|
|
let resp =
|
|
MentorAvailabilityDto::from(service.get_mentor_availability(mentor_id).await?);
|
|
Ok(ApiSuccess(resp))
|
|
}
|
|
|
|
#[utoipa::path(
|
|
get,
|
|
path = "/v1/users/me/sessions",
|
|
tag = "sessions",
|
|
security(("Bearer" = [])),
|
|
params(
|
|
("status" = Option<String>, Query, description = "Filter by status"),
|
|
),
|
|
responses(
|
|
(status = 200, description = "Sessions retrieved successfully", body = SessionListResponseDto),
|
|
(status = 401, description = "Unauthorized"),
|
|
)
|
|
)]
|
|
pub async fn get_my_sessions(
|
|
headers: HeaderMap,
|
|
Extension(service): Extension<Arc<dyn SessionService>>,
|
|
Query(filter): Query<SessionStatusFilter>,
|
|
) -> Result<impl IntoResponse, AppError> {
|
|
let user_email = extract_email(&headers)
|
|
.ok_or_else(|| AppError::AuthenticationError("Token tidak valid".to_string()))?;
|
|
let resp = SessionListResponseDto::from(
|
|
service.get_user_sessions(user_email, filter.status).await?,
|
|
);
|
|
Ok(ApiSuccess(resp))
|
|
}
|