diff --git a/src/webhook.rs b/src/webhook.rs index 074e5da..1ca2e3a 100644 --- a/src/webhook.rs +++ b/src/webhook.rs @@ -1,20 +1,78 @@ +use axum::async_trait; +use axum::extract::FromRequest; +use axum::extract::Request; use axum::http::HeaderMap; use axum::http::StatusCode; +use axum::response::IntoResponse; +use axum::response::Response; use axum::Json; +use axum::RequestExt; use serde::Deserialize; use serde::Serialize; use serde_json::Value; +use tracing::debug; pub(crate) async fn hook( headers: HeaderMap, - Json(payload): Json, + payload: HookRequest, ) -> (StatusCode, Json) { - (StatusCode::OK, Json(HookResponse { ok: true })) + debug!("REQ: {:?}", payload); + match payload { + HookRequest::Push(payload) => ( + StatusCode::OK, + Json(HookResponse { + ok: true, + message: None, + }), + ), + HookRequest::Unrecognized(payload) => ( + StatusCode::BAD_REQUEST, + Json(HookResponse { + ok: false, + message: Some(format!("unrecognized input: {payload}")), + }), + ), + } +} + +#[derive(Debug)] +pub(crate) enum HookRequest { + Push(HookPush), + Unrecognized(String), +} + +#[async_trait] +impl FromRequest for HookRequest +where + S: Send + Sync, +{ + type Rejection = Response; + + async fn from_request(req: Request, _state: &S) -> Result { + let event_type = req + .headers() + .get("X-Gitea-Event-Type") + .ok_or(StatusCode::UNSUPPORTED_MEDIA_TYPE.into_response())?; + let event_type = event_type + .to_str() + .map_err(|_| StatusCode::UNSUPPORTED_MEDIA_TYPE.into_response())?; + match event_type { + "push" => { + let Json(payload): Json = + req.extract().await.map_err(IntoResponse::into_response)?; + Ok(HookRequest::Push(payload)) + } + _ => { + let body: String = req.extract().await.map_err(IntoResponse::into_response)?; + Ok(HookRequest::Unrecognized(body)) + } + } + } } #[allow(dead_code)] -#[derive(Deserialize)] -pub(crate) struct HookRequest { +#[derive(Debug, Deserialize)] +pub(crate) struct HookPush { #[serde(rename = "ref")] ref_field: String, before: String, @@ -28,7 +86,7 @@ pub(crate) struct HookRequest { } #[allow(dead_code)] -#[derive(Deserialize)] +#[derive(Debug, Deserialize)] pub(crate) struct HookUser { id: u64, login: String, @@ -54,7 +112,7 @@ pub(crate) struct HookUser { } #[allow(dead_code)] -#[derive(Deserialize)] +#[derive(Debug, Deserialize)] pub(crate) struct HookRepository { id: u64, owner: HookUser, @@ -114,7 +172,7 @@ pub(crate) struct HookRepository { } #[allow(dead_code)] -#[derive(Deserialize)] +#[derive(Debug, Deserialize)] pub(crate) struct HookRepositoryPermissions { admin: bool, push: bool, @@ -122,7 +180,7 @@ pub(crate) struct HookRepositoryPermissions { } #[allow(dead_code)] -#[derive(Deserialize)] +#[derive(Debug, Deserialize)] pub(crate) struct HookRepositoryInternalTracker { enable_time_tracker: bool, allow_only_contributors_to_track_time: bool, @@ -130,7 +188,7 @@ pub(crate) struct HookRepositoryInternalTracker { } #[allow(dead_code)] -#[derive(Deserialize)] +#[derive(Debug, Deserialize)] pub(crate) struct HookCommit { id: String, message: String, @@ -145,14 +203,15 @@ pub(crate) struct HookCommit { } #[allow(dead_code)] -#[derive(Deserialize)] +#[derive(Debug, Deserialize)] pub(crate) struct HookGitUser { name: String, email: String, username: String, } -#[derive(Serialize)] +#[derive(Debug, Serialize)] pub(crate) struct HookResponse { ok: bool, + message: Option, }