Matrix notification

This commit is contained in:
Pascal Engélibert 2022-10-15 23:48:06 +02:00
commit 2de26f5ffc
Signed by: tuxmain
GPG key ID: 3504BC6D362F7DCA
7 changed files with 1090 additions and 17 deletions

View file

@ -32,6 +32,17 @@ pub struct Config {
pub lang: String,
#[serde(default = "Config::default_listen")]
pub listen: SocketAddr,
/// Send a matrix message on new comment
#[serde(default = "Config::default_matrix_notify")]
pub matrix_notify: bool,
#[serde(default = "Config::default_matrix_password")]
pub matrix_password: String,
#[serde(default = "Config::default_matrix_room")]
pub matrix_room: String,
#[serde(default = "Config::default_matrix_server")]
pub matrix_server: String,
#[serde(default = "Config::default_matrix_user")]
pub matrix_user: String,
#[serde(default = "Config::default_root_url")]
pub root_url: String,
}
@ -70,6 +81,21 @@ impl Config {
fn default_listen() -> SocketAddr {
SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 31720)
}
fn default_matrix_notify() -> bool {
false
}
fn default_matrix_password() -> String {
"".into()
}
fn default_matrix_room() -> String {
"#maintenance:matrix.txmn.tk".into()
}
fn default_matrix_server() -> String {
"https://matrix.txmn.tk".into()
}
fn default_matrix_user() -> String {
"@tuxmain:matrix.txmn.tk".into()
}
fn default_root_url() -> String {
"/".into()
}
@ -89,6 +115,11 @@ impl Default for Config {
cookies_domain: Self::default_cookies_domain(),
lang: Self::default_lang(),
listen: Self::default_listen(),
matrix_notify: Self::default_matrix_notify(),
matrix_password: Self::default_matrix_password(),
matrix_room: Self::default_matrix_room(),
matrix_server: Self::default_matrix_server(),
matrix_user: Self::default_matrix_user(),
root_url: Self::default_root_url(),
}
}
@ -107,7 +138,7 @@ pub fn read_config(dir: &Path) -> Config {
std::str::from_utf8(&std::fs::read(path).expect("Cannot read config file"))
.expect("Bad encoding in config file"),
)
.expect("Bad JSON in config file")
.expect("Bad TOML in config file")
}
}

View file

@ -2,6 +2,7 @@ mod cli;
mod config;
mod db;
mod helpers;
mod notify;
mod queries;
mod server;
mod templates;
@ -12,7 +13,7 @@ use argon2::{
};
use clap::Parser;
#[async_std::main]
#[tokio::main]
async fn main() {
let opt = cli::MainOpt::parse();

64
src/notify.rs Normal file
View file

@ -0,0 +1,64 @@
use crate::config::Config;
use crossbeam_channel::Receiver;
use matrix_sdk::ruma;
use std::sync::Arc;
struct Notifier {
matrix: Option<(matrix_sdk::Client, matrix_sdk::room::Joined)>,
}
impl Notifier {
async fn new(config: &Config) -> Self {
Self {
matrix: if config.matrix_notify {
let user = ruma::UserId::parse(&config.matrix_user).unwrap();
let client = matrix_sdk::Client::builder()
.homeserver_url(&config.matrix_server)
.user_agent("Webcomment")
.build()
.await
.unwrap();
client
.login_username(&user, &config.matrix_password)
.send()
.await
.unwrap();
client
.sync_once(matrix_sdk::config::SyncSettings::default())
.await
.unwrap();
let room_id = <&ruma::RoomId>::try_from(config.matrix_room.as_str()).unwrap();
let room = client.get_room(room_id).unwrap();
if let matrix_sdk::room::Room::Joined(room) = room {
Some((client, room))
} else {
None
}
} else {
None
},
}
}
async fn notify(&self) {
if let Some((_client, room)) = &self.matrix {
room.send(
ruma::events::room::message::RoomMessageEventContent::text_plain("New comment."),
None,
)
.await
.unwrap();
}
}
}
pub async fn run_notifier(config: Arc<Config>, recv: Receiver<()>) {
let notifier = Notifier::new(&config).await;
for () in recv {
notifier.notify().await;
}
}

View file

@ -1,6 +1,7 @@
use crate::{config::*, db::*, helpers, queries::*, templates::*};
use argon2::{Argon2, PasswordHash, PasswordVerifier};
use crossbeam_channel::Sender;
use log::error;
use std::sync::Arc;
use tera::Context;
@ -11,6 +12,9 @@ pub async fn start_server(config: Config, dbs: Dbs, templates: Templates) {
let templates = Arc::new(templates);
let config = Arc::new(config);
let (notify_send, notify_recv) = crossbeam_channel::bounded(10);
tokio::spawn(crate::notify::run_notifier(config.clone(), notify_recv));
let mut app = tide::new();
app.at(&format!("{}t/:topic", config.root_url)).get({
let config = config.clone();
@ -25,7 +29,13 @@ pub async fn start_server(config: Config, dbs: Dbs, templates: Templates) {
let templates = templates.clone();
let dbs = dbs.clone();
move |req: tide::Request<()>| {
handle_post_comments(req, config.clone(), templates.clone(), dbs.clone())
handle_post_comments(
req,
config.clone(),
templates.clone(),
dbs.clone(),
notify_send.clone(),
)
}
});
app.at(&format!("{}admin", config.root_url)).get({
@ -176,6 +186,7 @@ async fn handle_post_comments(
config: Arc<Config>,
templates: Arc<Templates>,
dbs: Dbs,
notify_send: Sender<()>,
) -> tide::Result<tide::Response> {
match req.body_form::<CommentQuery>().await? {
CommentQuery::NewComment(query) => {
@ -215,6 +226,7 @@ async fn handle_post_comments(
helpers::new_pending_comment(&comment, &dbs)
.map_err(|e| error!("Adding pending comment: {:?}", e))
.ok();
notify_send.send(()).ok();
}
_ => todo!(),
}