Skip to content
This repository was archived by the owner on Oct 19, 2026. It is now read-only.

Commit df70bf6

Browse files
231220075genedna
andauthored
feat: support editing and modifying CLA protocol content and performing object storage. (#2000)
fix errors Signed-off-by: Ruizhi Huang <231220075@smail.nju.edu.cn> Co-authored-by: Quanyi Ma <eli@patch.sh>
1 parent 4dc4cf3 commit df70bf6

3 files changed

Lines changed: 115 additions & 2 deletions

File tree

‎ceres/src/api_service/mono_api_service.rs‎

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ use common::{
5555
errors::{BuckError, MegaError},
5656
utils::MEGA_BRANCH_NAME,
5757
};
58+
use futures::{StreamExt, stream};
5859
use git_internal::{
5960
DiffItem,
6061
diff::Diff as GitDiff,
@@ -69,6 +70,7 @@ use git_internal::{
6970
},
7071
},
7172
};
73+
use io_orbit::object_storage::{ObjectKey, ObjectMeta, ObjectNamespace};
7274
use jupiter::{
7375
service::buck_service::{
7476
CommitArtifacts, CompletePayload as SvcCompletePayload,
@@ -130,6 +132,8 @@ impl From<&ImportRepo> for MonoApiService {
130132
}
131133
}
132134
}
135+
// Key for storing the current CLA content in the object storage
136+
const CLA_CONTENT_OBJECT_KEY: &str = "cla/content/current.txt";
133137

134138
pub struct TreeUpdateResult {
135139
pub updated_trees: Vec<Tree>,
@@ -1300,6 +1304,60 @@ impl MonoApiService {
13001304
Ok((model.cla_signed, model.cla_signed_at))
13011305
}
13021306

1307+
pub async fn get_cla_content(&self) -> Result<String, MegaError> {
1308+
let key = ObjectKey {
1309+
namespace: ObjectNamespace::Log,
1310+
key: CLA_CONTENT_OBJECT_KEY.to_string(),
1311+
};
1312+
1313+
let stream = self
1314+
.storage
1315+
.git_service
1316+
.obj_storage
1317+
.inner
1318+
.get_stream(&key)
1319+
.await;
1320+
let (mut stream, _meta) = match stream {
1321+
Ok(result) => result,
1322+
Err(MegaError::ObjStorageNotFound(_)) => return Ok(String::new()),
1323+
Err(e) => return Err(e),
1324+
};
1325+
1326+
let mut data = Vec::new();
1327+
while let Some(chunk) = stream.next().await {
1328+
let chunk = chunk?;
1329+
data.extend_from_slice(&chunk);
1330+
}
1331+
1332+
String::from_utf8(data).map_err(|e| {
1333+
MegaError::Other(format!(
1334+
"Invalid UTF-8 in CLA content from object storage: {e}"
1335+
))
1336+
})
1337+
}
1338+
1339+
pub async fn update_cla_content(&self, content: &str) -> Result<(), MegaError> {
1340+
let key = ObjectKey {
1341+
namespace: ObjectNamespace::Log,
1342+
key: CLA_CONTENT_OBJECT_KEY.to_string(),
1343+
};
1344+
1345+
let bytes = Bytes::from(content.as_bytes().to_vec());
1346+
let stream = stream::once(async move { Ok::<Bytes, std::io::Error>(bytes) });
1347+
let meta = ObjectMeta {
1348+
size: content.len() as i64,
1349+
content_type: Some("text/plain; charset=utf-8".to_string()),
1350+
..Default::default()
1351+
};
1352+
1353+
self.storage
1354+
.git_service
1355+
.obj_storage
1356+
.inner
1357+
.put_stream(&key, Box::pin(stream), meta)
1358+
.await
1359+
}
1360+
13031361
pub async fn change_cla_sign_status(
13041362
&self,
13051363
username: &str,

‎ceres/src/model/user.rs‎

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,3 +61,13 @@ pub struct ClaSignStatusRes {
6161
pub cla_signed: bool,
6262
pub cla_signed_at: Option<i64>,
6363
}
64+
65+
#[derive(Debug, Deserialize, Serialize, ToSchema)]
66+
pub struct UpdateClaContentPayload {
67+
pub content: String,
68+
}
69+
70+
#[derive(Debug, Serialize, Deserialize, ToSchema)]
71+
pub struct ClaContentRes {
72+
pub content: String,
73+
}

‎mono/src/api/router/user_router.rs‎

Lines changed: 47 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,9 @@ use axum::{
44
extract::{Path, State},
55
routing::get,
66
};
7-
use ceres::model::user::{AddSSHKey, ClaSignStatusRes, ListSSHKey, ListToken};
7+
use ceres::model::user::{
8+
AddSSHKey, ClaContentRes, ClaSignStatusRes, ListSSHKey, ListToken, UpdateClaContentPayload,
9+
};
810
use common::errors::MegaError;
911
use russh::keys::{HashAlg, parse_public_key_base64};
1012
use utoipa_axum::{router::OpenApiRouter, routes};
@@ -26,7 +28,9 @@ pub fn routers() -> OpenApiRouter<MonoApiServiceState> {
2628
.routes(routes!(list_token))
2729
.routes(routes!(remove_token))
2830
.routes(routes!(get_cla_sign_status))
29-
.routes(routes!(change_sign_status)),
31+
.routes(routes!(change_sign_status))
32+
.routes(routes!(get_cla_content))
33+
.routes(routes!(update_cla_content)),
3034
)
3135
}
3236

@@ -228,3 +232,44 @@ async fn change_sign_status(
228232
};
229233
Ok(Json(CommonResult::success(Some(res))))
230234
}
235+
236+
/// Get latest CLA text content
237+
#[utoipa::path(
238+
get,
239+
path = "/cla/content",
240+
responses(
241+
(status = 200, body = CommonResult<ClaContentRes>, content_type = "application/json")
242+
),
243+
tag = USER_TAG
244+
)]
245+
async fn get_cla_content(
246+
_user: LoginUser,
247+
state: State<MonoApiServiceState>,
248+
) -> Result<Json<CommonResult<ClaContentRes>>, ApiError> {
249+
let content = state.monorepo().get_cla_content().await?;
250+
Ok(Json(CommonResult::success(Some(ClaContentRes { content }))))
251+
}
252+
253+
/// Update latest CLA text content
254+
#[utoipa::path(
255+
post,
256+
path = "/cla/content",
257+
request_body = UpdateClaContentPayload,
258+
responses(
259+
(status = 200, body = CommonResult<ClaContentRes>, content_type = "application/json")
260+
),
261+
tag = USER_TAG
262+
)]
263+
async fn update_cla_content(
264+
_user: LoginUser,
265+
state: State<MonoApiServiceState>,
266+
Json(payload): Json<UpdateClaContentPayload>,
267+
) -> Result<Json<CommonResult<ClaContentRes>>, ApiError> {
268+
state
269+
.monorepo()
270+
.update_cla_content(&payload.content)
271+
.await?;
272+
Ok(Json(CommonResult::success(Some(ClaContentRes {
273+
content: payload.content,
274+
}))))
275+
}

0 commit comments

Comments
 (0)