Skip to main content

agentics_domain/models/challenge_creation/
responses.rs

1//! Challenge review record response DTOs.
2
3use serde::{Deserialize, Serialize};
4
5use crate::models::auth::GithubUserId;
6use crate::models::github::GithubPullRequestNumber;
7use crate::models::hashes::{GitCommitSha, Sha256Digest};
8use crate::models::ids::{ChallengeReviewRecordId, ChallengeReviewValidationRecordId, HumanId};
9use crate::models::names::ChallengeName;
10use crate::models::paths::RepoRelativePath;
11use crate::models::urls::{GithubPullRequestUrl, GithubRepoRemote};
12
13use super::lifecycle::{ChallengeReviewRecordStatus, ChallengeReviewValidationStatus};
14use super::manifest::{ChallengeCreationManifest, ChallengeCreationRequestKind};
15use super::private_assets::ChallengePrivateAssetResponse;
16
17/// API response for one validation record.
18#[derive(Debug, Clone, Serialize, Deserialize, schemars::JsonSchema)]
19pub struct ChallengeReviewValidationRecordResponse {
20    pub id: ChallengeReviewValidationRecordId,
21    pub review_record_id: ChallengeReviewRecordId,
22    pub status: ChallengeReviewValidationStatus,
23    pub message: String,
24    pub repository_path: String,
25    pub manifest_sha256: Sha256Digest,
26    #[serde(skip_serializing_if = "Option::is_none")]
27    pub bundle_sha256: Option<Sha256Digest>,
28    pub created_at: String,
29}
30
31/// Creator-facing validation record response without server-local checkout paths.
32#[derive(Debug, Clone, Serialize, Deserialize, schemars::JsonSchema)]
33pub struct CreatorChallengeReviewValidationRecordResponse {
34    pub id: ChallengeReviewValidationRecordId,
35    pub review_record_id: ChallengeReviewRecordId,
36    pub status: ChallengeReviewValidationStatus,
37    pub message: String,
38    pub manifest_sha256: Sha256Digest,
39    #[serde(skip_serializing_if = "Option::is_none")]
40    pub bundle_sha256: Option<Sha256Digest>,
41    pub created_at: String,
42}
43
44/// API response for one challenge review record.
45#[derive(Debug, Clone, Serialize, Deserialize, schemars::JsonSchema)]
46pub struct ChallengeReviewRecordResponse {
47    pub id: ChallengeReviewRecordId,
48    pub challenge_name: ChallengeName,
49    pub request: ChallengeCreationRequestKind,
50    pub status: ChallengeReviewRecordStatus,
51    pub creator_human_id: HumanId,
52    pub creator_github_user_id: GithubUserId,
53    pub creator_github_login: String,
54    pub repo_url: GithubRepoRemote,
55    pub pr_number: GithubPullRequestNumber,
56    pub pr_url: GithubPullRequestUrl,
57    pub commit_sha: GitCommitSha,
58    pub challenge_path: RepoRelativePath,
59    pub manifest_sha256: Sha256Digest,
60    pub manifest: ChallengeCreationManifest,
61    #[serde(skip_serializing_if = "Option::is_none")]
62    pub validation_bundle_sha256: Option<Sha256Digest>,
63    #[serde(skip_serializing_if = "Option::is_none")]
64    pub approved_bundle_sha256: Option<Sha256Digest>,
65    #[serde(skip_serializing_if = "Option::is_none")]
66    pub validation_message: Option<String>,
67    #[serde(skip_serializing_if = "Option::is_none")]
68    pub validation_repository_path: Option<String>,
69    #[serde(skip_serializing_if = "Option::is_none")]
70    pub published_challenge_name: Option<ChallengeName>,
71    #[serde(default)]
72    pub private_assets: Vec<ChallengePrivateAssetResponse>,
73    #[serde(default)]
74    pub validation_records: Vec<ChallengeReviewValidationRecordResponse>,
75    pub created_at: String,
76    pub updated_at: String,
77}
78
79/// Creator-facing response for one challenge review record.
80#[derive(Debug, Clone, Serialize, Deserialize, schemars::JsonSchema)]
81pub struct CreatorChallengeReviewRecordResponse {
82    pub id: ChallengeReviewRecordId,
83    pub challenge_name: ChallengeName,
84    pub request: ChallengeCreationRequestKind,
85    pub status: ChallengeReviewRecordStatus,
86    pub creator_human_id: HumanId,
87    pub creator_github_user_id: GithubUserId,
88    pub creator_github_login: String,
89    pub repo_url: GithubRepoRemote,
90    pub pr_number: GithubPullRequestNumber,
91    pub pr_url: GithubPullRequestUrl,
92    pub commit_sha: GitCommitSha,
93    pub challenge_path: RepoRelativePath,
94    pub manifest_sha256: Sha256Digest,
95    pub manifest: ChallengeCreationManifest,
96    #[serde(skip_serializing_if = "Option::is_none")]
97    pub validation_bundle_sha256: Option<Sha256Digest>,
98    #[serde(skip_serializing_if = "Option::is_none")]
99    pub approved_bundle_sha256: Option<Sha256Digest>,
100    #[serde(skip_serializing_if = "Option::is_none")]
101    pub validation_message: Option<String>,
102    #[serde(skip_serializing_if = "Option::is_none")]
103    pub published_challenge_name: Option<ChallengeName>,
104    #[serde(default)]
105    pub private_assets: Vec<ChallengePrivateAssetResponse>,
106    #[serde(default)]
107    pub validation_records: Vec<CreatorChallengeReviewValidationRecordResponse>,
108    pub created_at: String,
109    pub updated_at: String,
110}
111
112impl From<ChallengeReviewValidationRecordResponse>
113    for CreatorChallengeReviewValidationRecordResponse
114{
115    /// Drop admin-only checkout path data for creator surfaces.
116    fn from(record: ChallengeReviewValidationRecordResponse) -> Self {
117        Self {
118            id: record.id,
119            review_record_id: record.review_record_id,
120            status: record.status,
121            message: record.message,
122            manifest_sha256: record.manifest_sha256,
123            bundle_sha256: record.bundle_sha256,
124            created_at: record.created_at,
125        }
126    }
127}
128
129impl From<ChallengeReviewRecordResponse> for CreatorChallengeReviewRecordResponse {
130    /// Drop admin-only checkout path data for creator surfaces.
131    fn from(review_record: ChallengeReviewRecordResponse) -> Self {
132        Self {
133            id: review_record.id,
134            challenge_name: review_record.challenge_name,
135            request: review_record.request,
136            status: review_record.status,
137            creator_human_id: review_record.creator_human_id,
138            creator_github_user_id: review_record.creator_github_user_id,
139            creator_github_login: review_record.creator_github_login,
140            repo_url: review_record.repo_url,
141            pr_number: review_record.pr_number,
142            pr_url: review_record.pr_url,
143            commit_sha: review_record.commit_sha,
144            challenge_path: review_record.challenge_path,
145            manifest_sha256: review_record.manifest_sha256,
146            manifest: review_record.manifest,
147            validation_bundle_sha256: review_record.validation_bundle_sha256,
148            approved_bundle_sha256: review_record.approved_bundle_sha256,
149            validation_message: review_record.validation_message,
150            published_challenge_name: review_record.published_challenge_name,
151            private_assets: review_record.private_assets,
152            validation_records: review_record
153                .validation_records
154                .into_iter()
155                .map(CreatorChallengeReviewValidationRecordResponse::from)
156                .collect(),
157            created_at: review_record.created_at,
158            updated_at: review_record.updated_at,
159        }
160    }
161}
162
163/// List response for admin challenge review record review.
164#[derive(Debug, Clone, Serialize, Deserialize, schemars::JsonSchema)]
165pub struct ChallengeReviewRecordListResponse {
166    pub items: Vec<ChallengeReviewRecordResponse>,
167}
168
169/// Admin response returned after abandoning stale review records and deleting
170/// purge-eligible unpublished private asset records.
171#[derive(Debug, Clone, Serialize, Deserialize, schemars::JsonSchema)]
172pub struct ChallengeReviewRecordCleanupResponse {
173    pub abandoned_review_records: i64,
174    pub purged_private_assets: i64,
175    pub purged_temporary_storage_objects: i64,
176}