drawbridge_server/trees/
put.rs1use super::super::{OidcClaims, ScopeContext, ScopeLevel, Store};
5
6use drawbridge_type::{Meta, TreeContext, TreeDirectory};
7
8use async_std::sync::Arc;
9use axum::body::Body;
10use axum::extract::{BodyStream, RequestParts};
11use axum::http::{Request, StatusCode};
12use axum::response::IntoResponse;
13use axum::{Extension, Json};
14use futures::{io, TryStreamExt};
15use tracing::{debug, trace};
16
17pub async fn put(
18 Extension(ref store): Extension<Arc<Store>>,
19 claims: OidcClaims,
20 cx: TreeContext,
21 meta: Meta,
22 req: Request<Body>,
23) -> impl IntoResponse {
24 trace!(target: "app::trees::put", "called for `{cx}`");
25
26 if meta.hash.is_empty() {
27 return Err((
28 StatusCode::BAD_REQUEST,
29 "At least one content digest value must be specified",
30 )
31 .into_response());
32 }
33
34 let user = claims
35 .assert_user(
36 store,
37 &cx.tag.repository.owner,
38 ScopeContext::Tag,
39 ScopeLevel::Write,
40 )
41 .await
42 .map_err(IntoResponse::into_response)?;
43
44 let mut req = RequestParts::new(req);
45 let tag = user.repository(&cx.tag.repository.name).tag(&cx.tag.name);
46 match meta.mime.to_string().as_str() {
47 TreeDirectory::<()>::TYPE => {
48 let dir = req
49 .extract()
50 .await
51 .map(|Json(v)| v)
52 .map_err(|e| (StatusCode::BAD_REQUEST, e).into_response())?;
53 tag.create_directory_node(&cx.path, meta, &dir).await
54 }
55 _ => {
56 let body = req
57 .extract::<BodyStream>()
58 .await
59 .map_err(|e| (StatusCode::BAD_REQUEST, e).into_response())?
60 .map_err(|e| io::Error::new(io::ErrorKind::Other, e));
61 tag.create_file_node(&cx.path, meta, body.into_async_read())
62 .await
63 }
64 }
65 .map_err(|e| {
66 debug!(target: "app::trees::put", "failed for `{cx}`: {:?}", e);
67 e.into_response()
68 })
69 .map(|_| StatusCode::CREATED)
70}