/*
* Copyright (C) 2025 Jonni Liljamo <jonni@liljamo.com>
*
* This file is licensed under AGPL-3.0-or-later, see NOTICE and LICENSE for
* more information.
*/
use std::{collections::HashMap, sync::Arc};
use axum::{Json, http::HeaderMap, response::IntoResponse};
use reqwest::StatusCode;
use serde::Deserialize;
use crate::{
routes::{extract_token, message::MessageForm},
state::State,
};
const ALERTMANAGER_JSON_VERSION_4: &str = "4";
#[derive(Debug, Deserialize)]
pub struct V4Alert {
annotations: HashMap<String, String>,
}
#[derive(Debug, Deserialize)]
pub struct V4Form {
version: String,
alerts: Vec<V4Alert>,
}
impl From<V4Alert> for MessageForm {
fn from(value: V4Alert) -> Self {
MessageForm {
title: value
.annotations
.get("summary")
.cloned()
.unwrap_or("Summary N/A".into()),
message: value
.annotations
.get("description")
.cloned()
.unwrap_or("Description N/A".into()),
format_commonmark: false,
}
}
}
pub async fn alertmanager_v4(
state: Arc<State>,
headers: HeaderMap,
Json(message): Json<V4Form>,
) -> impl IntoResponse {
let token = extract_token!(headers).trim_start_matches("Bearer ");
let notifier = match state.find_notifier(token) {
Some(n) => n,
None => return (StatusCode::UNAUTHORIZED, "unauthorized"),
};
if message.version != ALERTMANAGER_JSON_VERSION_4 {
return (
StatusCode::BAD_REQUEST,
"wrong alertmanager json version, this API is for version 4",
);
}
for alert in message.alerts {
if let Err(err) = state.send_message(notifier, &alert.into()).await {
tracing::error!(?err, "message sending failed");
return (StatusCode::INTERNAL_SERVER_ERROR, "failed to send message");
};
}
(StatusCode::OK, "")
}