Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,7 @@ Environment variables can be set using a `.env` file. Use the `.env.template` fi

##### Configuration

- `SLACK_WEBHOOK_URL`: URL of Slack webhook for sending notifications (ignored if empty).
- `MAX_UPLOAD_LIMIT`: Maximum number of files that can be uploaded at once.
- `LOG_LOCATION`: The path to a local logfile.
- `STATIC_FILES_URL`: The URL of the static files server. (eg: `https://static.metakgp.org`)
Expand Down
2 changes: 2 additions & 0 deletions backend/.env.template
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ GH_ADMIN_USERNAMES=

JWT_SECRET=

SLACK_WEBHOOK_URL=

MAX_UPLOAD_LIMIT=10
LOG_LOCATION=./log/application.log

Expand Down
2 changes: 1 addition & 1 deletion backend/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ flate2 = "1.0"
hmac = "0.12.1"
http = "1.1.0"
jwt = "0.16.0"
reqwest = { version = "0.12.8", default-features = false, features = ["rustls-tls"] }
reqwest = { version = "0.12.8", default-features = false, features = ["rustls-tls", "json"] }
serde = { version = "1.0.210", features = ["serde_derive"] }
serde_json = "1.0.128"
sha2 = "0.10.8"
Expand Down
3 changes: 3 additions & 0 deletions backend/src/env.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,9 @@ pub struct EnvVars {
#[arg(env, default_value = "")]
/// The usernames of the admins (additional to org team members, comma separated)
pub gh_admin_usernames: String,
#[arg(env, default_value = "")]
/// URL of Slack webhook for sending notifications
pub slack_webhook_url: String,

// Other configs
#[arg(env, default_value = "10")]
Expand Down
1 change: 1 addition & 0 deletions backend/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@ pub mod env;
pub mod pathutils;
pub mod qp;
pub mod routing;
pub mod slack;
1 change: 1 addition & 0 deletions backend/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ mod env;
mod pathutils;
mod qp;
mod routing;
mod slack;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
Expand Down
10 changes: 10 additions & 0 deletions backend/src/routing/handlers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ use crate::{
auth::{self, Auth},
pathutils::PaperCategory,
qp::{self, AdminDashboardQP, Exam, WithUrl},
slack::send_slack_message,
};

use super::{AppError, BackendResponse, RouterState, Status};
Expand Down Expand Up @@ -383,6 +384,15 @@ pub async fn upload(
});
}

let unapproved_count = state.db.get_unapproved_papers().await?.len();

let _ = send_slack_message(
&state.env_vars.slack_webhook_url,
upload_statuses.len(),
unapproved_count,
)
.await;

Ok(BackendResponse::ok(
format!("Successfully processed {} files", upload_statuses.len()),
upload_statuses,
Expand Down
41 changes: 41 additions & 0 deletions backend/src/slack.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
//! Utils for Slack App integration.

use color_eyre::eyre;
use http::StatusCode;

/// Sends a notification to the Slack channel whenever a new paper is uploaded.
pub async fn send_slack_message(
webhook_url: &str,
count: usize,
unapproved: usize,
) -> Result<(), color_eyre::eyre::Error> {
if webhook_url.is_empty() {
return Ok(());
}

let message = format!(
"🔔 {} uploaded to IQPS!\n\n<https://qp.metakgp.org/admin|Review> | Total Unapproved papers: *{}*",
if count == 1 {
"A new paper was".into()
} else {
format!("{} new papers were", count)
},
unapproved
);

let client = reqwest::Client::new();
let response = client
.post(webhook_url)
.json(&serde_json::json!({ "text": message }))
.send()
.await?;

if response.status() != StatusCode::OK {
return Err(eyre::eyre!(
"Failed to send message to Slack: {}",
response.status()
));
}

Ok(())
}