use reqwest::Method;
use serde::{Deserialize, Serialize};
use crate::{
core::{
api_req::ApiRequest,
api_resp::{ApiResponseTrait, BaseResponse, ResponseFormat},
config::Config,
constants::AccessTokenType,
endpoints::hire::*,
endpoints::EndpointBuilder,
http::Transport,
req_option::RequestOption,
SDKResult,
},
service::hire::models::{CommonResponse, I18nText, PageResponse},
};
pub struct ExamService {
pub config: Config,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct ExamPaper {
pub id: String,
pub title: I18nText,
pub description: Option<I18nText>,
pub paper_type: String,
pub question_count: u32,
pub duration_minutes: u32,
pub pass_score: f32,
pub total_score: f32,
pub difficulty_level: String,
pub suitable_positions: Vec<String>,
pub skill_tags: Vec<String>,
pub enabled: bool,
pub creator_id: String,
pub created_time: Option<String>,
pub updated_time: Option<String>,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct ExamRecord {
pub id: String,
pub application_id: String,
pub talent_id: String,
pub paper_id: String,
pub status: String,
pub start_time: Option<String>,
pub end_time: Option<String>,
pub actual_duration: Option<u32>,
pub score: Option<f32>,
pub passed: Option<bool>,
pub answer_details: Vec<ExamAnswerDetail>,
pub proctoring_records: Vec<ExamProctoringRecord>,
pub remark: Option<String>,
pub created_time: Option<String>,
pub updated_time: Option<String>,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct ExamAnswerDetail {
pub question_id: String,
pub question_type: String,
pub candidate_answer: String,
pub correct_answer: Option<String>,
pub is_correct: Option<bool>,
pub score: Option<f32>,
pub answer_time: Option<String>,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct ExamProctoringRecord {
pub id: String,
pub record_type: String,
pub record_time: String,
pub details: Option<String>,
pub risk_level: Option<String>,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct ExamQuestion {
pub id: String,
pub question_type: String,
pub content: I18nText,
pub options: Option<Vec<ExamOption>>,
pub correct_answer: String,
pub score: f32,
pub difficulty: String,
pub skill_tags: Vec<String>,
pub explanation: Option<I18nText>,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct ExamOption {
pub key: String,
pub content: I18nText,
}
#[derive(Debug, Serialize, Deserialize, Default)]
pub struct ExamArrangementRequest {
pub application_id: String,
pub paper_id: String,
pub start_time: String,
pub end_time: String,
pub enable_proctoring: Option<bool>,
pub retry_count: Option<u32>,
pub notify_candidate: Option<bool>,
pub remark: Option<String>,
}
#[derive(Debug, Serialize, Deserialize, Default)]
pub struct ExamSubmissionRequest {
pub exam_record_id: String,
pub answers: Vec<ExamAnswerSubmission>,
pub submit_time: String,
}
#[derive(Debug, Serialize, Deserialize, Default)]
pub struct ExamAnswerSubmission {
pub question_id: String,
pub answer: String,
}
#[derive(Debug, Serialize, Deserialize, Default)]
pub struct ExamPaperListRequest {
pub page_size: Option<u32>,
pub page_token: Option<String>,
pub paper_type: Option<String>,
pub difficulty_level: Option<String>,
pub skill_tag: Option<String>,
pub enabled: Option<bool>,
}
#[derive(Debug, Serialize, Deserialize, Default)]
pub struct ExamRecordListRequest {
pub page_size: Option<u32>,
pub page_token: Option<String>,
pub talent_id: Option<String>,
pub paper_id: Option<String>,
pub status: Option<String>,
pub start_time_from: Option<String>,
pub start_time_to: Option<String>,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct ExamPaperListResponse {
#[serde(flatten)]
pub papers: PageResponse<ExamPaper>,
}
impl ApiResponseTrait for ExamPaperListResponse {
fn data_format() -> ResponseFormat {
ResponseFormat::Data
}
}
#[derive(Debug, Serialize, Deserialize)]
pub struct ExamRecordListResponse {
#[serde(flatten)]
pub records: PageResponse<ExamRecord>,
}
impl ApiResponseTrait for ExamRecordListResponse {
fn data_format() -> ResponseFormat {
ResponseFormat::Data
}
}
#[derive(Debug, Serialize, Deserialize)]
pub struct ExamRecordDetailResponse {
pub record: ExamRecord,
}
impl ApiResponseTrait for ExamRecordDetailResponse {
fn data_format() -> ResponseFormat {
ResponseFormat::Data
}
}
#[derive(Debug, Serialize, Deserialize)]
pub struct ExamOperationResponse {
#[serde(flatten)]
pub result: CommonResponse,
pub id: Option<String>,
}
impl ApiResponseTrait for ExamOperationResponse {
fn data_format() -> ResponseFormat {
ResponseFormat::Data
}
}
impl ExamService {
pub fn new(config: Config) -> Self {
Self { config }
}
pub async fn list_papers(
&self,
request: ExamPaperListRequest,
option: Option<RequestOption>,
) -> SDKResult<BaseResponse<ExamPaperListResponse>> {
let mut api_req = ApiRequest {
http_method: Method::GET,
api_path: HIRE_V1_EXAM_PAPERS.to_string(),
supported_access_token_types: vec![AccessTokenType::Tenant],
body: vec![],
..Default::default()
};
if let Some(page_size) = request.page_size {
api_req
.query_params
.insert("page_size", page_size.to_string());
}
if let Some(page_token) = request.page_token {
api_req.query_params.insert("page_token", page_token);
}
if let Some(paper_type) = request.paper_type {
api_req.query_params.insert("paper_type", paper_type);
}
if let Some(difficulty_level) = request.difficulty_level {
api_req
.query_params
.insert("difficulty_level", difficulty_level);
}
if let Some(skill_tag) = request.skill_tag {
api_req.query_params.insert("skill_tag", skill_tag);
}
if let Some(enabled) = request.enabled {
api_req.query_params.insert("enabled", enabled.to_string());
}
Transport::request(api_req, &self.config, option).await
}
pub async fn arrange_exam(
&self,
request: ExamArrangementRequest,
option: Option<RequestOption>,
) -> SDKResult<BaseResponse<ExamOperationResponse>> {
let api_req = ApiRequest {
http_method: Method::POST,
api_path: HIRE_V1_EXAM_ARRANGEMENTS.to_string(),
supported_access_token_types: vec![AccessTokenType::Tenant],
body: serde_json::to_vec(&request).unwrap_or_default(),
..Default::default()
};
Transport::request(api_req, &self.config, option).await
}
pub async fn get_record_detail(
&self,
record_id: &str,
option: Option<RequestOption>,
) -> SDKResult<BaseResponse<ExamRecordDetailResponse>> {
let api_req = ApiRequest {
http_method: Method::GET,
api_path: EndpointBuilder::replace_param(
HIRE_V1_EXAM_RECORD_GET,
"record_id",
record_id,
),
supported_access_token_types: vec![AccessTokenType::Tenant],
body: vec![],
..Default::default()
};
Transport::request(api_req, &self.config, option).await
}
pub async fn list_records(
&self,
request: ExamRecordListRequest,
option: Option<RequestOption>,
) -> SDKResult<BaseResponse<ExamRecordListResponse>> {
let mut api_req = ApiRequest {
http_method: Method::GET,
api_path: HIRE_V1_EXAM_RECORDS.to_string(),
supported_access_token_types: vec![AccessTokenType::Tenant],
body: vec![],
..Default::default()
};
if let Some(page_size) = request.page_size {
api_req
.query_params
.insert("page_size", page_size.to_string());
}
if let Some(page_token) = request.page_token {
api_req.query_params.insert("page_token", page_token);
}
if let Some(talent_id) = request.talent_id {
api_req.query_params.insert("talent_id", talent_id);
}
if let Some(paper_id) = request.paper_id {
api_req.query_params.insert("paper_id", paper_id);
}
if let Some(status) = request.status {
api_req.query_params.insert("status", status);
}
if let Some(start_time_from) = request.start_time_from {
api_req
.query_params
.insert("start_time_from", start_time_from);
}
if let Some(start_time_to) = request.start_time_to {
api_req.query_params.insert("start_time_to", start_time_to);
}
Transport::request(api_req, &self.config, option).await
}
pub async fn submit_exam(
&self,
request: ExamSubmissionRequest,
option: Option<RequestOption>,
) -> SDKResult<BaseResponse<ExamOperationResponse>> {
let api_req = ApiRequest {
http_method: Method::POST,
api_path: HIRE_V1_EXAM_SUBMISSIONS.to_string(),
supported_access_token_types: vec![AccessTokenType::Tenant],
body: serde_json::to_vec(&request).unwrap_or_default(),
..Default::default()
};
Transport::request(api_req, &self.config, option).await
}
pub async fn cancel_exam(
&self,
record_id: &str,
reason: &str,
option: Option<RequestOption>,
) -> SDKResult<BaseResponse<ExamOperationResponse>> {
#[derive(Serialize)]
struct CancelExamRequest {
reason: String,
}
let request = CancelExamRequest {
reason: reason.to_string(),
};
let api_req = ApiRequest {
http_method: Method::POST,
api_path: EndpointBuilder::replace_param(
HIRE_V1_EXAM_RECORD_CANCEL,
"record_id",
record_id,
),
supported_access_token_types: vec![AccessTokenType::Tenant],
body: serde_json::to_vec(&request).unwrap_or_default(),
..Default::default()
};
Transport::request(api_req, &self.config, option).await
}
pub async fn reschedule_exam(
&self,
record_id: &str,
new_start_time: &str,
new_end_time: &str,
option: Option<RequestOption>,
) -> SDKResult<BaseResponse<ExamOperationResponse>> {
#[derive(Serialize)]
struct RescheduleExamRequest {
new_start_time: String,
new_end_time: String,
}
let request = RescheduleExamRequest {
new_start_time: new_start_time.to_string(),
new_end_time: new_end_time.to_string(),
};
let api_req = ApiRequest {
http_method: Method::POST,
api_path: EndpointBuilder::replace_param(
HIRE_V1_EXAM_RECORD_RESCHEDULE,
"record_id",
record_id,
),
supported_access_token_types: vec![AccessTokenType::Tenant],
body: serde_json::to_vec(&request).unwrap_or_default(),
..Default::default()
};
Transport::request(api_req, &self.config, option).await
}
pub async fn get_exam_statistics(
&self,
paper_id: Option<String>,
start_date: Option<String>,
end_date: Option<String>,
option: Option<RequestOption>,
) -> SDKResult<BaseResponse<serde_json::Value>> {
let mut api_req = ApiRequest {
http_method: Method::GET,
api_path: HIRE_V1_EXAM_STATISTICS.to_string(),
supported_access_token_types: vec![AccessTokenType::Tenant],
body: vec![],
..Default::default()
};
if let Some(paper_id) = paper_id {
api_req.query_params.insert("paper_id", paper_id);
}
if let Some(start_date) = start_date {
api_req.query_params.insert("start_date", start_date);
}
if let Some(end_date) = end_date {
api_req.query_params.insert("end_date", end_date);
}
Transport::request(api_req, &self.config, option).await
}
}