Ver Fonte

Implement acknowledging notifications

Mark Rousskov há 5 anos atrás
pai
commit
0c421a82d7
3 ficheiros alterados com 52 adições e 8 exclusões
  1. 11 0
      src/db/notifications.rs
  2. 2 1
      src/github.rs
  3. 39 7
      src/handlers/notification.rs

+ 11 - 0
src/db/notifications.rs

@@ -24,3 +24,14 @@ pub async fn record_ping(db: &DbClient, notification: &Notification) -> anyhow::
 
     Ok(())
 }
+
+pub async fn delete_ping(db: &DbClient, user_id: i64, origin_url: &str) -> anyhow::Result<()> {
+    db.execute(
+        "DELETE FROM notifications WHERE user_id = $1, origin_url = $2",
+        &[&user_id, &origin_url],
+    )
+    .await
+    .context("deleting notification")?;
+
+    Ok(())
+}

+ 2 - 1
src/github.rs

@@ -10,6 +10,7 @@ use std::fmt;
 #[derive(Debug, PartialEq, Eq, serde::Deserialize)]
 pub struct User {
     pub login: String,
+    pub id: Option<i64>,
 }
 
 impl GithubClient {
@@ -125,7 +126,7 @@ pub struct Issue {
     created_at: chrono::DateTime<Utc>,
     title: String,
     html_url: String,
-    user: User,
+    pub user: User,
     labels: Vec<Label>,
     assignees: Vec<User>,
     pull_request: Option<PullRequestDetails>,

+ 39 - 7
src/handlers/notification.rs

@@ -15,9 +15,47 @@ use std::convert::TryFrom;
 
 lazy_static::lazy_static! {
     static ref PING_RE: Regex = Regex::new(r#"@([-\w\d]+)"#,).unwrap();
+    static ref ACKNOWLEDGE_RE: Regex = Regex::new(r#"acknowledge (https?://[^ ]+)"#,).unwrap();
 }
 
 pub async fn handle(ctx: &Context, event: &Event) -> anyhow::Result<()> {
+    let body = match event.comment_body() {
+        Some(v) => v,
+        // Skip events that don't have comment bodies associated
+        None => return Ok(()),
+    };
+
+    // Permit editing acknowledgement
+
+    let acks = ACKNOWLEDGE_RE
+        .captures_iter(body)
+        .map(|c| c.get(1).unwrap().as_str().to_owned())
+        .collect::<Vec<_>>();
+    log::trace!("Captured acknowledgements: {:?}", acks);
+    for url in acks {
+        let user = match event {
+            Event::Issue(e) => &e.issue.user,
+            Event::IssueComment(e) => &e.comment.user,
+        };
+        let id = match user.id {
+            Some(id) => id,
+            // If the user was not in the team(s) then just don't record it.
+            None => {
+                log::trace!("Skipping {} because no id found", user.login);
+                return Ok(());
+            }
+        };
+
+        if let Err(e) = notifications::delete_ping(&ctx.db, id, &url).await {
+            log::warn!(
+                "failed to delete notification: url={}, user={:?}: {:?}",
+                url,
+                user,
+                e
+            );
+        }
+    }
+
     if let Event::Issue(e) = event {
         if e.action != github::IssuesAction::Opened {
             // skip events other than opening the issue to avoid retriggering commands in the
@@ -37,19 +75,13 @@ pub async fn handle(ctx: &Context, event: &Event) -> anyhow::Result<()> {
         }
     }
 
-    let body = match event.comment_body() {
-        Some(v) => v,
-        // Skip events that don't have comment bodies associated
-        None => return Ok(()),
-    };
-
     let caps = PING_RE
         .captures_iter(body)
         .map(|c| c.get(1).unwrap().as_str().to_owned())
         .collect::<Vec<_>>();
     log::trace!("Captured usernames in comment: {:?}", caps);
     for login in caps {
-        let user = github::User { login };
+        let user = github::User { login, id: None };
         let id = user
             .get_id(&ctx.github)
             .await