Add support for reading mail-archive.com RSS feeds

This commit is contained in:
2023-09-20 18:16:30 -07:00
parent 092b29637f
commit dc41aeac14
7 changed files with 1252 additions and 27 deletions

145
src/gitlab_webhook.rs Normal file
View File

@@ -0,0 +1,145 @@
// bebot
// Copyright (C) 2023 Brian Tarricone <brian@tarricone.org>
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
use std::sync::Arc;
use constant_time_eq::constant_time_eq;
use http::StatusCode;
use matrix_sdk::{
ruma::{events::room::message::RoomMessageEventContent, OwnedRoomOrAliasId},
Client,
};
use tokio::sync::mpsc;
use warp::{filters::BoxedFilter, reply::Reply, Filter};
use crate::{
config::GitlabWebhookConfig,
gitlab_event::{parse_ref, GitlabEvent, GitlabEventExt},
matrix,
};
pub fn build_gitlab_messages(event: &GitlabEvent) -> Vec<String> {
let project = event.project();
let refname = event.r#ref().map(parse_ref);
event
.titles()
.iter()
.map(|title| {
format!(
"\\[{}\\] {}*{}* {}",
project.path_with_namespace,
refname
.as_ref()
.map(|rn| format!("`{}` ", rn))
.unwrap_or_else(|| "".to_string()),
event.user(),
title,
)
})
.collect()
}
pub async fn handle_gitlab_event(
event: GitlabEvent,
room_id: &OwnedRoomOrAliasId,
matrix_client: &Client,
) -> anyhow::Result<()> {
let room = matrix::ensure_room_joined(matrix_client, room_id).await?;
for msg in build_gitlab_messages(&event) {
debug!("Sending message to {}: {}", room_id, msg);
let msg_content = RoomMessageEventContent::text_markdown(&msg);
room.send(msg_content, None).await?;
}
Ok(())
}
pub fn build_route(config: GitlabWebhookConfig, matrix_client: Client) -> anyhow::Result<BoxedFilter<(impl Reply,)>> {
let (event_tx, mut event_rx) = mpsc::channel::<(GitlabEvent, OwnedRoomOrAliasId)>(100);
tokio::spawn(async move {
while let Some((event, room)) = event_rx.recv().await {
if let Err(err) = handle_gitlab_event(event, &room, &matrix_client).await {
warn!("Failed to handle payload: {}", err);
}
}
});
let gitlab_root_path = if let Some(url_prefix) = config.url_prefix.as_ref() {
url_prefix.split('/').fold(warp::any().boxed(), |last, segment| {
if segment.is_empty() {
last
} else {
last.and(warp::path(segment.to_string())).boxed()
}
})
} else {
warp::any().boxed()
};
let config = Arc::new(config);
let gitlab = gitlab_root_path
.and(warp::path!("hooks" / "gitlab"))
.and(warp::post())
.and(warp::header::<String>("x-gitlab-token"))
.and(warp::body::json())
.then(move |token: String, event: GitlabEvent| {
let event_tx = event_tx.clone();
let config = Arc::clone(&config);
async move {
match event {
GitlabEvent::Other => {
warp::reply::with_status("Unsupported Gitlab event type", StatusCode::BAD_REQUEST)
}
_ => {
let project = event.project();
let config_key = project.web_url.replace("http://", "").replace("https://", "");
if let Some(repo_config) = config.repo_configs.get(&config_key) {
if !constant_time_eq(token.as_bytes(), repo_config.token.as_bytes()) {
warn!("Invalid token for repo '{}'", config_key);
warp::reply::with_status("Invalid token", StatusCode::FORBIDDEN)
} else {
debug!("payload: {:?}", event);
if let Some(room) = &repo_config.room.as_ref().or(config.default_room.as_ref()) {
let publish_events = repo_config
.publish_events
.as_ref()
.or(config.default_publish_events.as_ref());
if publish_events.map(|ecs| event.should_publish(ecs)).unwrap_or(true) {
if let Err(err) = event_tx.send((event, (*room).clone())).await {
warn!("Failed to enqueue payload: {}", err);
}
}
warp::reply::with_status("OK", StatusCode::OK)
} else {
info!("Channel not configured for repo '{}'", config_key);
warp::reply::with_status(
"Matrix room not configured for repo",
StatusCode::NOT_FOUND,
)
}
}
} else {
info!("Repo '{}' unconfigured", config_key);
warp::reply::with_status("Repo not configured", StatusCode::NOT_FOUND)
}
}
}
}
})
.boxed();
Ok(gitlab)
}