Support multiple types of requests.

This commit is contained in:
Tom Alexander 2024-07-14 18:33:24 -04:00
parent eb0c993e03
commit 2c0a7958a7
Signed by: talexander
GPG Key ID: D3A179C9A53C0EDE
3 changed files with 201 additions and 142 deletions

142
src/hook_push.rs Normal file
View File

@ -0,0 +1,142 @@
use serde::Deserialize;
use serde_json::Value;
#[allow(dead_code)]
#[derive(Debug, Deserialize)]
pub(crate) struct HookPush {
#[serde(rename = "ref")]
ref_field: String,
before: String,
compare_url: String,
commits: Vec<HookCommit>,
total_commits: u64,
head_commit: HookCommit,
repository: HookRepository,
pusher: HookUser,
sender: HookUser,
}
#[allow(dead_code)]
#[derive(Debug, Deserialize)]
pub(crate) struct HookUser {
id: u64,
login: String,
login_name: String,
full_name: String,
email: String,
avatar_url: String,
language: String,
is_admin: bool,
last_login: String, // TODO: parse to datetime
created: String, // TODO: parse to datetime
restricted: bool,
active: bool,
prohibit_login: bool,
location: String,
website: String,
description: String,
visibility: String,
followers_count: u64,
following_count: u64,
starred_repos_count: u64,
username: String,
}
#[allow(dead_code)]
#[derive(Debug, Deserialize)]
pub(crate) struct HookRepository {
id: u64,
owner: HookUser,
name: String,
full_name: String,
description: String,
empty: bool,
private: bool,
fork: bool,
template: bool,
parent: Value, // Was null in test hook
mirror: bool,
size: u64,
language: String,
languages_url: String,
html_url: String,
url: String,
link: String,
ssh_url: String,
clone_url: String,
original_url: String,
website: String,
stars_count: u64,
forks_count: u64,
watchers_count: u64,
open_issues_count: u64,
open_pr_counter: u64,
release_counter: u64,
default_branch: String,
archived: bool,
created_at: String, // TODO: parse to datetime
updated_at: String, // TODO: parse to datetime
archived_at: String, // TODO: parse to datetime
permissions: HookRepositoryPermissions,
has_issues: bool,
internal_tracker: HookRepositoryInternalTracker,
has_wiki: bool,
has_pull_requests: bool,
has_projects: bool,
has_releases: bool,
has_packages: bool,
has_actions: bool,
ignore_whitespace_conflicts: bool,
allow_merge_commits: bool,
allow_rebase: bool,
allow_rebase_explicit: bool,
allow_squash_merge: bool,
allow_rebase_update: bool,
default_delete_branch_after_merge: bool,
default_merge_style: String,
default_allow_maintainer_edit: bool,
avatar_url: String,
internal: bool,
mirror_interval: String,
mirror_updated: String, // TODO: parse to datetime
repo_transfer: Value, // Was null in test hook
}
#[allow(dead_code)]
#[derive(Debug, Deserialize)]
pub(crate) struct HookRepositoryPermissions {
admin: bool,
push: bool,
pull: bool,
}
#[allow(dead_code)]
#[derive(Debug, Deserialize)]
pub(crate) struct HookRepositoryInternalTracker {
enable_time_tracker: bool,
allow_only_contributors_to_track_time: bool,
enable_issue_dependencies: bool,
}
#[allow(dead_code)]
#[derive(Debug, Deserialize)]
pub(crate) struct HookCommit {
id: String,
message: String,
url: String,
author: HookGitUser,
committer: HookGitUser,
verification: Value, // Was null in test hook
timestamp: String, // TODO: parse to datetime
added: Vec<String>,
removed: Vec<String>,
modified: Vec<String>,
}
#[allow(dead_code)]
#[derive(Debug, Deserialize)]
pub(crate) struct HookGitUser {
name: String,
email: String,
username: String,
}

View File

@ -11,6 +11,7 @@ use tracing_subscriber::util::SubscriberInitExt;
use self::webhook::hook;
mod hook_push;
mod webhook;
#[tokio::main]

View File

@ -1,158 +1,74 @@
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 serde::Deserialize;
use axum::RequestExt;
use serde::Serialize;
use serde_json::Value;
use tracing::debug;
use crate::hook_push::HookPush;
pub(crate) async fn hook(
headers: HeaderMap,
Json(payload): Json<HookRequest>,
_headers: HeaderMap,
payload: HookRequest,
) -> (StatusCode, Json<HookResponse>) {
(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 event type: {payload}")),
}),
),
}
}
#[allow(dead_code)]
#[derive(Deserialize)]
pub(crate) struct HookRequest {
#[serde(rename = "ref")]
ref_field: String,
before: String,
compare_url: String,
commits: Vec<HookCommit>,
total_commits: u64,
head_commit: HookCommit,
repository: HookRepository,
pusher: HookUser,
sender: HookUser,
#[derive(Debug)]
pub(crate) enum HookRequest {
Push(HookPush),
Unrecognized(String),
}
#[allow(dead_code)]
#[derive(Deserialize)]
pub(crate) struct HookUser {
id: u64,
login: String,
login_name: String,
full_name: String,
email: String,
avatar_url: String,
language: String,
is_admin: bool,
last_login: String, // TODO: parse to datetime
created: String, // TODO: parse to datetime
restricted: bool,
active: bool,
prohibit_login: bool,
location: String,
website: String,
description: String,
visibility: String,
followers_count: u64,
following_count: u64,
starred_repos_count: u64,
username: String,
#[async_trait]
impl<S> FromRequest<S> for HookRequest
where
S: Send + Sync,
{
type Rejection = Response;
async fn from_request(req: Request, _state: &S) -> Result<Self, Self::Rejection> {
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<HookPush> =
req.extract().await.map_err(IntoResponse::into_response)?;
Ok(HookRequest::Push(payload))
}
_ => Ok(HookRequest::Unrecognized(event_type.to_owned())),
}
}
}
#[allow(dead_code)]
#[derive(Deserialize)]
pub(crate) struct HookRepository {
id: u64,
owner: HookUser,
name: String,
full_name: String,
description: String,
empty: bool,
private: bool,
fork: bool,
template: bool,
parent: Value, // Was null in test hook
mirror: bool,
size: u64,
language: String,
languages_url: String,
html_url: String,
url: String,
link: String,
ssh_url: String,
clone_url: String,
original_url: String,
website: String,
stars_count: u64,
forks_count: u64,
watchers_count: u64,
open_issues_count: u64,
open_pr_counter: u64,
release_counter: u64,
default_branch: String,
archived: bool,
created_at: String, // TODO: parse to datetime
updated_at: String, // TODO: parse to datetime
archived_at: String, // TODO: parse to datetime
permissions: HookRepositoryPermissions,
has_issues: bool,
internal_tracker: HookRepositoryInternalTracker,
has_wiki: bool,
has_pull_requests: bool,
has_projects: bool,
has_releases: bool,
has_packages: bool,
has_actions: bool,
ignore_whitespace_conflicts: bool,
allow_merge_commits: bool,
allow_rebase: bool,
allow_rebase_explicit: bool,
allow_squash_merge: bool,
allow_rebase_update: bool,
default_delete_branch_after_merge: bool,
default_merge_style: String,
default_allow_maintainer_edit: bool,
avatar_url: String,
internal: bool,
mirror_interval: String,
mirror_updated: String, // TODO: parse to datetime
repo_transfer: Value, // Was null in test hook
}
#[allow(dead_code)]
#[derive(Deserialize)]
pub(crate) struct HookRepositoryPermissions {
admin: bool,
push: bool,
pull: bool,
}
#[allow(dead_code)]
#[derive(Deserialize)]
pub(crate) struct HookRepositoryInternalTracker {
enable_time_tracker: bool,
allow_only_contributors_to_track_time: bool,
enable_issue_dependencies: bool,
}
#[allow(dead_code)]
#[derive(Deserialize)]
pub(crate) struct HookCommit {
id: String,
message: String,
url: String,
author: HookGitUser,
committer: HookGitUser,
verification: Value, // Was null in test hook
timestamp: String, // TODO: parse to datetime
added: Vec<String>,
removed: Vec<String>,
modified: Vec<String>,
}
#[allow(dead_code)]
#[derive(Deserialize)]
pub(crate) struct HookGitUser {
name: String,
email: String,
username: String,
}
#[derive(Serialize)]
#[derive(Debug, Serialize)]
pub(crate) struct HookResponse {
ok: bool,
message: Option<String>,
}