From b0cf9817d786c9ce8caf4f07853341ba9d8bc32a Mon Sep 17 00:00:00 2001 From: MythEclipse Date: Sat, 27 Sep 2025 13:06:55 +0700 Subject: [PATCH] feat: Implement submission retrieval and timeline validation in hackathon service --- .../src/v1/hackathon/hackathon_repository.rs | 35 +++++++++++++ .../src/v1/hackathon/hackathon_service.rs | 51 +++++++++++++++++++ 2 files changed, 86 insertions(+) diff --git a/imphnen-hackathon/src/v1/hackathon/hackathon_repository.rs b/imphnen-hackathon/src/v1/hackathon/hackathon_repository.rs index d97d0f4..be42183 100644 --- a/imphnen-hackathon/src/v1/hackathon/hackathon_repository.rs +++ b/imphnen-hackathon/src/v1/hackathon/hackathon_repository.rs @@ -548,6 +548,28 @@ impl<'a> HackathonRepository<'a> { } } + #[instrument(skip(self, id), err)] + pub async fn get_hackathon_submission_by_id(&self, id: String) -> Result { + let table = ResourceEnum::HackathonSubmissions.to_string(); + info!(query = %format!("SELECT * FROM {} WHERE id = '{}'", table, id), "Executing SurrealDB query"); + + let record: Option = self + .state + .surrealdb_ws + .select((table, id)) + .await?; + + match record { + Some(s) => { + if s.is_deleted { + bail!("Submission not found"); + } + Ok(s) + } + None => bail!("Submission not found"), + } + } + #[instrument(skip(self, id), err)] pub async fn submit_hackathon_submission(&self, id: String) -> Result { let table = ResourceEnum::HackathonSubmissions.to_string(); @@ -597,4 +619,17 @@ impl<'a> HackathonRepository<'a> { None => bail!("Failed to delete submission"), } } + #[instrument(skip(self, hackathon_id), err)] + pub async fn get_submission_timeline_phase(&self, hackathon_id: String) -> Result> { + let table = ResourceEnum::HackathonTimeline.to_string(); + + info!(query = %format!("SELECT * FROM {} WHERE hackathon_id = 'app_hackathons:{}' AND phase = 'Submission' AND is_deleted = false LIMIT 1", table, hackathon_id), "Executing SurrealDB query"); + + let mut response = self.state.surrealdb_ws + .query(format!("SELECT * FROM {} WHERE hackathon_id = 'app_hackathons:{}' AND phase = 'Submission' AND is_deleted = false LIMIT 1", table, hackathon_id)) + .await?; + + let timeline: Option = response.take(0)?; + Ok(timeline) + } } \ No newline at end of file diff --git a/imphnen-hackathon/src/v1/hackathon/hackathon_service.rs b/imphnen-hackathon/src/v1/hackathon/hackathon_service.rs index e17f14d..b90aad8 100644 --- a/imphnen-hackathon/src/v1/hackathon/hackathon_service.rs +++ b/imphnen-hackathon/src/v1/hackathon/hackathon_service.rs @@ -770,6 +770,57 @@ impl HackathonServiceTrait for HackathonService { Box::pin(async move { let repo = HackathonRepository::new(&state); + // Get submission to extract hackathon_id for timeline validation + let submission = match repo.get_hackathon_submission_by_id(id.clone()).await { + Ok(sub) => sub, + Err(e) => { + let error_msg = e.to_string(); + if error_msg.contains("not found") { + return Err(ErrorDto { + status: StatusCode::NOT_FOUND.as_u16(), + message: "Submission not found".to_string(), + details: None, + }); + } else { + error!("Failed to get submission for validation: {}", e); + return Err(ErrorDto { + status: StatusCode::INTERNAL_SERVER_ERROR.as_u16(), + message: "Failed to validate submission".to_string(), + details: None, + }); + } + } + }; + + // Check submission timeline phase + match repo.get_submission_timeline_phase(submission.hackathon_id.id.to_raw()).await { + Ok(Some(timeline_phase)) => { + let current_time = chrono::Utc::now(); + if current_time < timeline_phase.start_date || current_time > timeline_phase.end_date { + return Err(ErrorDto { + status: StatusCode::BAD_REQUEST.as_u16(), + message: "Submission is not allowed outside the designated submission period".to_string(), + details: Some(serde_json::json!({ + "start_date": timeline_phase.start_date, + "end_date": timeline_phase.end_date, + "current_time": current_time + })), + }); + } + } + Ok(None) => { + // If no timeline phase defined, allow submission (backward compatibility) + } + Err(e) => { + error!("Failed to get submission timeline phase: {}", e); + return Err(ErrorDto { + status: StatusCode::INTERNAL_SERVER_ERROR.as_u16(), + message: "Failed to validate submission period".to_string(), + details: None, + }); + } + } + match repo.submit_hackathon_submission(id).await { Ok(submission) => { let dto = HackathonSubmissionDto::from(submission);