use super::super::dto::{ BookSessionRequestDto, BookSessionResponseDto, SessionFeedbackRequestDto, SessionFeedbackResponseDto, UpdateSessionStatusRequestDto, UpdateSessionStatusResponseDto, }; use crate::sessions::domain::SessionService; use axum::{ extract::{Extension, Path}, http::{HeaderMap, header::AUTHORIZATION}, response::IntoResponse, }; use imphnen_libs::{ValidatedJson, decode_access_token}; use imphnen_utils::AppError; use imphnen_utils::ApiSuccess; use imphnen_entities::seaorm::auth::mentors::{ Column as MentorColumn, Entity as MentorsEntity, }; use imphnen_libs::AppState; use sea_orm::{ColumnTrait, EntityTrait, QueryFilter}; use std::sync::Arc; use uuid::Uuid; fn extract_user_id(headers: &HeaderMap) -> Result { let token = headers .get(AUTHORIZATION) .and_then(|h| h.to_str().ok()) .and_then(|s| s.strip_prefix("Bearer ")) .ok_or_else(|| AppError::AuthenticationError("Token tidak valid".to_string()))?; let claims = decode_access_token(token) .map_err(|_| AppError::AuthenticationError("Token tidak valid".to_string()))?; Ok(claims.claims.user_id) } #[utoipa::path( post, path = "/v1/dimentorin/mentors/{id}/sessions/create", tag = "sessions", security(("Bearer" = [])), params( ("id" = String, Path, description = "Mentor ID"), ), request_body = BookSessionRequestDto, responses( (status = 201, description = "Session booked successfully", body = BookSessionResponseDto), (status = 400, description = "Invalid request"), (status = 401, description = "Unauthorized"), (status = 404, description = "Mentor not found"), ) )] pub async fn post_book_session( headers: HeaderMap, Extension(state): Extension, Extension(service): Extension>, Path(mentor_id): Path, ValidatedJson(dto): ValidatedJson, ) -> Result { let user_id = extract_user_id(&headers)?; let mentor_uuid = Uuid::parse_str(&mentor_id).map_err(|_| { AppError::BadRequestError("Invalid mentor ID format".to_string()) })?; // Resolve mentor profile id -> user id (sessions.mentor_id FK ke app_users) let mentor = MentorsEntity::find_by_id(mentor_uuid) .one(&state.postgres_connection.conn) .await? .ok_or_else(|| AppError::NotFoundError("Mentor not found".to_string()))?; let resp = BookSessionResponseDto::from( service .book_session(mentor.user_id.to_string(), user_id, dto.into()) .await?, ); Ok(ApiSuccess(resp)) } #[utoipa::path( put, path = "/v1/dimentorin/sessions/update/{id}/status", tag = "sessions", security(("Bearer" = [])), params( ("id" = String, Path, description = "Session ID"), ), request_body = UpdateSessionStatusRequestDto, responses( (status = 200, description = "Status updated successfully", body = UpdateSessionStatusResponseDto), (status = 400, description = "Invalid request"), (status = 401, description = "Unauthorized"), (status = 404, description = "Session not found"), ) )] pub async fn put_update_session_status( headers: HeaderMap, Extension(service): Extension>, Path(session_id): Path, ValidatedJson(dto): ValidatedJson, ) -> Result { let user_id = extract_user_id(&headers)?; let resp = UpdateSessionStatusResponseDto::from( service .update_session_status(session_id, user_id, dto.into()) .await?, ); Ok(ApiSuccess(resp)) } #[utoipa::path( post, path = "/v1/dimentorin/sessions/{id}/feedback/create", tag = "sessions", security(("Bearer" = [])), params( ("id" = String, Path, description = "Session ID"), ), request_body = SessionFeedbackRequestDto, responses( (status = 200, description = "Feedback submitted successfully", body = SessionFeedbackResponseDto), (status = 400, description = "Invalid request or session not completed"), (status = 401, description = "Unauthorized"), (status = 403, description = "Forbidden"), (status = 404, description = "Session not found"), ) )] pub async fn post_submit_feedback( headers: HeaderMap, Extension(service): Extension>, Path(session_id): Path, ValidatedJson(dto): ValidatedJson, ) -> Result { let user_id = extract_user_id(&headers)?; let resp = SessionFeedbackResponseDto::from( service .submit_feedback(session_id, user_id, dto.into()) .await?, ); Ok(ApiSuccess(resp)) }