feat: Update hackathon event and submission routes to require admin permissions and adjust response descriptions

This commit is contained in:
MythEclipse
2025-10-27 17:26:53 +07:00
parent d5ccf4cf75
commit e77797d7bb
3 changed files with 66 additions and 38 deletions
@@ -176,16 +176,20 @@ pub async fn delete_hackathon(
// Hackathon Events routes // Hackathon Events routes
#[utoipa::path( #[utoipa::path(
post, post,
security(
("Bearer" = [])
),
path = "/v1/hackathons/{hackathon_id}/events", path = "/v1/hackathons/{hackathon_id}/events",
params( params(
("hackathon_id" = String, Path, description = "Hackathon ID") ("hackathon_id" = String, Path, description = "Hackathon ID")
), ),
request_body = HackathonEventCreateRequestDto, request_body = HackathonEventCreateRequestDto,
responses( responses(
(status = 201, description = "[PUBLIC] Event created successfully", body = ResponseSuccessDto<HackathonEventDto>), (status = 201, description = "[ADMIN] Event created successfully", body = ResponseSuccessDto<HackathonEventDto>),
(status = 400, description = "[PUBLIC] Bad request", body = ErrorDto), (status = 400, description = "[ADMIN] Bad request", body = ErrorDto),
(status = 404, description = "[PUBLIC] Hackathon not found", body = ErrorDto), (status = 403, description = "[ADMIN] Forbidden - Administrator permission required", body = ErrorDto),
(status = 500, description = "[PUBLIC] Internal server error", body = ErrorDto) (status = 404, description = "[ADMIN] Hackathon not found", body = ErrorDto),
(status = 500, description = "[ADMIN] Internal server error", body = ErrorDto)
), ),
tag = "Hackathon Events" tag = "Hackathon Events"
)] )]
@@ -232,16 +236,20 @@ pub async fn list_hackathon_events(
#[utoipa::path( #[utoipa::path(
put, put,
security(
("Bearer" = [])
),
path = "/v1/hackathons/events/{id}", path = "/v1/hackathons/events/{id}",
params( params(
("id" = String, Path, description = "Event ID") ("id" = String, Path, description = "Event ID")
), ),
request_body = HackathonEventUpdateRequestDto, request_body = HackathonEventUpdateRequestDto,
responses( responses(
(status = 200, description = "[PUBLIC] Event updated successfully", body = ResponseSuccessDto<HackathonEventDto>), (status = 200, description = "[ADMIN] Event updated successfully", body = ResponseSuccessDto<HackathonEventDto>),
(status = 400, description = "[PUBLIC] Bad request", body = ErrorDto), (status = 400, description = "[ADMIN] Bad request", body = ErrorDto),
(status = 404, description = "[PUBLIC] Event not found", body = ErrorDto), (status = 403, description = "[ADMIN] Forbidden - Administrator permission required", body = ErrorDto),
(status = 500, description = "[PUBLIC] Internal server error", body = ErrorDto) (status = 404, description = "[ADMIN] Event not found", body = ErrorDto),
(status = 500, description = "[ADMIN] Internal server error", body = ErrorDto)
), ),
tag = "Hackathon Events" tag = "Hackathon Events"
)] )]
@@ -258,14 +266,18 @@ pub async fn update_hackathon_event(
#[utoipa::path( #[utoipa::path(
delete, delete,
security(
("Bearer" = [])
),
path = "/v1/hackathons/events/{id}", path = "/v1/hackathons/events/{id}",
params( params(
("id" = String, Path, description = "Event ID") ("id" = String, Path, description = "Event ID")
), ),
responses( responses(
(status = 200, description = "[PUBLIC] Event deleted successfully", body = ResponseSuccessDto<String>), (status = 200, description = "[ADMIN] Event deleted successfully", body = ResponseSuccessDto<String>),
(status = 404, description = "[PUBLIC] Event not found", body = ErrorDto), (status = 403, description = "[ADMIN] Forbidden - Administrator permission required", body = ErrorDto),
(status = 500, description = "[PUBLIC] Internal server error", body = ErrorDto) (status = 404, description = "[ADMIN] Event not found", body = ErrorDto),
(status = 500, description = "[ADMIN] Internal server error", body = ErrorDto)
), ),
tag = "Hackathon Events" tag = "Hackathon Events"
)] )]
@@ -400,6 +412,9 @@ pub async fn delete_hackathon_timeline(
// Hackathon Submissions routes with timeline enforcement // Hackathon Submissions routes with timeline enforcement
#[utoipa::path( #[utoipa::path(
post, post,
security(
("Bearer" = [])
),
path = "/v1/hackathons/{hackathon_id}/teams/{team_id}/submissions", path = "/v1/hackathons/{hackathon_id}/teams/{team_id}/submissions",
params( params(
("hackathon_id" = String, Path, description = "Hackathon ID"), ("hackathon_id" = String, Path, description = "Hackathon ID"),
@@ -407,11 +422,12 @@ pub async fn delete_hackathon_timeline(
), ),
request_body = HackathonSubmissionCreateRequestDto, request_body = HackathonSubmissionCreateRequestDto,
responses( responses(
(status = 201, description = "[PUBLIC] Submission created successfully", body = ResponseSuccessDto<HackathonSubmissionDto>), (status = 201, description = "[AUTH] Submission created successfully", body = ResponseSuccessDto<HackathonSubmissionDto>),
(status = 400, description = "[PUBLIC] Bad request", body = ErrorDto), (status = 400, description = "[AUTH] Bad request", body = ErrorDto),
(status = 403, description = "[PUBLIC] Forbidden - Submissions only allowed during submission phase", body = ErrorDto), (status = 401, description = "[AUTH] Unauthorized", body = ErrorDto),
(status = 404, description = "[PUBLIC] Hackathon not found", body = ErrorDto), (status = 403, description = "[AUTH] Forbidden - Submissions only allowed during submission phase", body = ErrorDto),
(status = 500, description = "[PUBLIC] Internal server error", body = ErrorDto) (status = 404, description = "[AUTH] Hackathon not found", body = ErrorDto),
(status = 500, description = "[AUTH] Internal server error", body = ErrorDto)
), ),
tag = "Hackathon Submissions" tag = "Hackathon Submissions"
)] )]
@@ -529,16 +545,20 @@ pub async fn get_hackathon_submission(
#[utoipa::path( #[utoipa::path(
put, put,
security(
("Bearer" = [])
),
path = "/v1/hackathons/submissions/{id}", path = "/v1/hackathons/submissions/{id}",
params( params(
("id" = String, Path, description = "Submission ID") ("id" = String, Path, description = "Submission ID")
), ),
request_body = HackathonSubmissionUpdateRequestDto, request_body = HackathonSubmissionUpdateRequestDto,
responses( responses(
(status = 200, description = "[PUBLIC] Submission updated successfully", body = ResponseSuccessDto<HackathonSubmissionDto>), (status = 200, description = "[AUTH] Submission updated successfully", body = ResponseSuccessDto<HackathonSubmissionDto>),
(status = 400, description = "[PUBLIC] Bad request", body = ErrorDto), (status = 400, description = "[AUTH] Bad request", body = ErrorDto),
(status = 404, description = "[PUBLIC] Submission not found", body = ErrorDto), (status = 401, description = "[AUTH] Unauthorized", body = ErrorDto),
(status = 500, description = "[PUBLIC] Internal server error", body = ErrorDto) (status = 404, description = "[AUTH] Submission not found", body = ErrorDto),
(status = 500, description = "[AUTH] Internal server error", body = ErrorDto)
), ),
tag = "Hackathon Submissions" tag = "Hackathon Submissions"
)] )]
@@ -555,15 +575,19 @@ pub async fn update_hackathon_submission(
#[utoipa::path( #[utoipa::path(
post, post,
security(
("Bearer" = [])
),
path = "/v1/hackathons/submissions/{id}/submit", path = "/v1/hackathons/submissions/{id}/submit",
params( params(
("id" = String, Path, description = "Submission ID") ("id" = String, Path, description = "Submission ID")
), ),
responses( responses(
(status = 200, description = "[PUBLIC] Submission submitted successfully", body = ResponseSuccessDto<HackathonSubmissionDto>), (status = 200, description = "[AUTH] Submission submitted successfully", body = ResponseSuccessDto<HackathonSubmissionDto>),
(status = 403, description = "[PUBLIC] Forbidden - Submissions only allowed during submission phase", body = ErrorDto), (status = 401, description = "[AUTH] Unauthorized", body = ErrorDto),
(status = 404, description = "[PUBLIC] Submission not found", body = ErrorDto), (status = 403, description = "[AUTH] Forbidden - Submissions only allowed during submission phase", body = ErrorDto),
(status = 500, description = "[PUBLIC] Internal server error", body = ErrorDto) (status = 404, description = "[AUTH] Submission not found", body = ErrorDto),
(status = 500, description = "[AUTH] Internal server error", body = ErrorDto)
), ),
tag = "Hackathon Submissions" tag = "Hackathon Submissions"
)] )]
@@ -581,14 +605,18 @@ pub async fn submit_hackathon_submission(
#[utoipa::path( #[utoipa::path(
delete, delete,
security(
("Bearer" = [])
),
path = "/v1/hackathons/submissions/{id}", path = "/v1/hackathons/submissions/{id}",
params( params(
("id" = String, Path, description = "Submission ID") ("id" = String, Path, description = "Submission ID")
), ),
responses( responses(
(status = 200, description = "[PUBLIC] Submission deleted successfully", body = ResponseSuccessDto<String>), (status = 200, description = "[AUTH] Submission deleted successfully", body = ResponseSuccessDto<String>),
(status = 404, description = "[PUBLIC] Submission not found", body = ErrorDto), (status = 401, description = "[AUTH] Unauthorized", body = ErrorDto),
(status = 500, description = "[PUBLIC] Internal server error", body = ErrorDto) (status = 404, description = "[AUTH] Submission not found", body = ErrorDto),
(status = 500, description = "[AUTH] Internal server error", body = ErrorDto)
), ),
tag = "Hackathon Submissions" tag = "Hackathon Submissions"
)] )]
+1 -1
View File
@@ -50,7 +50,7 @@ test_invalid_token_access() {
test_api_endpoint "GET User Me with Invalid Token" "GET" "/v1/users/me" 401 "" true test_api_endpoint "GET User Me with Invalid Token" "GET" "/v1/users/me" 401 "" true
# Test with malformed token # Test with malformed token
AUTH_TOKEN="Bearer.malformed.token" AUTH_TOKEN="malformed.token"
test_api_endpoint "GET Users with Malformed Token" "GET" "/v1/users" 401 "" true test_api_endpoint "GET Users with Malformed Token" "GET" "/v1/users" 401 "" true
# Test with empty token # Test with empty token
+10 -10
View File
@@ -182,13 +182,13 @@ mod tests {
weight: 1.0, weight: 1.0,
quantity: 10, quantity: 10,
}; };
let _ = GachaRollService::create_gacha_roll(&app_state, roll_dto).await; let _ = GachaRollService::create_gacha_roll(&app_state, roll_dto).await;
// Create auth header // Create auth header
let mut headers = HeaderMap::new(); let mut headers = HeaderMap::new();
headers.insert("authorization", format!("Bearer {}", email).parse().unwrap()); headers.insert("Authorization", format!("Bearer {}", email).parse().unwrap());
// Execute roll once // Execute roll once
let response = GachaRollService::execute_roll_once(headers, &app_state).await; let response = GachaRollService::execute_roll_once(headers, &app_state).await;
// Verify response (status + body) // Verify response (status + body)
@@ -219,13 +219,13 @@ mod tests {
phone_number: Some("1234567890".to_string()), phone_number: Some("1234567890".to_string()),
role_id: get_role_id(&app_state, "user").await.unwrap(), role_id: get_role_id(&app_state, "user").await.unwrap(),
}; };
let _ = UsersService::create_user(&app_state, user_dto).await; let _ = UsersService::create_user(&app_state, user_dto).await;
// Create auth header // Create auth header
let mut headers = HeaderMap::new(); let mut headers = HeaderMap::new();
headers.insert("authorization", format!("Bearer {}", email).parse().unwrap()); headers.insert("Authorization", format!("Bearer {}", email).parse().unwrap());
// Execute roll once with no active rolls // Execute roll once with no active rolls
let response = GachaRollService::execute_roll_once(headers, &app_state).await; let response = GachaRollService::execute_roll_once(headers, &app_state).await;
// Verify response (status + body) // Verify response (status + body)