fix: codex review — scope ack to user, deduplicate inbox entries
- ack_inbox now requires ?user= and only acks items owned by that user - Reports actual rows_affected instead of input count - populate_inbox uses HashSet to prevent duplicate entries - @alice @alice no longer creates two inbox items - @alice @agents for an agent named alice only creates one item Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -90,7 +90,7 @@ impl ColonyClient {
|
||||
pub async fn ack_inbox(&self, ids: &[i64]) -> serde_json::Value {
|
||||
let body = AckRequest { ids: ids.to_vec() };
|
||||
let res = self.http
|
||||
.post(self.url("/api/inbox/ack"))
|
||||
.post(self.url(&format!("/api/inbox/ack?{}", self.config.user_query())))
|
||||
.json(&body)
|
||||
.send().await.unwrap_or_else(|e| { eprintln!("colony unreachable: {e}"); process::exit(1); });
|
||||
if !res.status().is_success() { self.handle_error(res).await; }
|
||||
|
||||
@@ -392,31 +392,37 @@ pub async fn get_inbox(
|
||||
|
||||
pub async fn ack_inbox(
|
||||
State(state): State<AppState>,
|
||||
Query(user_param): Query<UserParam>,
|
||||
Json(body): Json<AckRequest>,
|
||||
) -> Result<impl IntoResponse> {
|
||||
let user_id = resolve_user(&state.db, &user_param).await?;
|
||||
let mut acked = 0i64;
|
||||
for id in &body.ids {
|
||||
sqlx::query("UPDATE inbox SET acked_at = strftime('%Y-%m-%dT%H:%M:%SZ', 'now') WHERE id = ? AND acked_at IS NULL")
|
||||
let result = sqlx::query("UPDATE inbox SET acked_at = strftime('%Y-%m-%dT%H:%M:%SZ', 'now') WHERE id = ? AND user_id = ? AND acked_at IS NULL")
|
||||
.bind(id)
|
||||
.bind(&user_id)
|
||||
.execute(&state.db)
|
||||
.await?;
|
||||
acked += result.rows_affected() as i64;
|
||||
}
|
||||
Ok(Json(serde_json::json!({"acked": body.ids.len()})))
|
||||
Ok(Json(serde_json::json!({"acked": acked})))
|
||||
}
|
||||
|
||||
/// Populate inbox entries when a message is posted
|
||||
async fn populate_inbox(db: &SqlitePool, message_id: &str, channel_id: &str, content: &str, sender_id: &str) {
|
||||
let mentions = crate::db::parse_mentions(content);
|
||||
let mut notified: std::collections::HashSet<String> = std::collections::HashSet::new();
|
||||
|
||||
for mention in &mentions {
|
||||
// Resolve mentioned user
|
||||
if let Ok(Some(user_id)) = sqlx::query_scalar::<_, String>("SELECT id FROM users WHERE username = ?")
|
||||
if let Ok(Some(uid)) = sqlx::query_scalar::<_, String>("SELECT id FROM users WHERE username = ?")
|
||||
.bind(mention)
|
||||
.fetch_optional(db)
|
||||
.await
|
||||
{
|
||||
if user_id != sender_id {
|
||||
if uid != sender_id && notified.insert(uid.clone()) {
|
||||
let _ = sqlx::query("INSERT INTO inbox (user_id, message_id, channel_id, trigger) VALUES (?, ?, ?, 'mention')")
|
||||
.bind(&user_id)
|
||||
.bind(&uid)
|
||||
.bind(message_id)
|
||||
.bind(channel_id)
|
||||
.execute(db)
|
||||
@@ -432,6 +438,7 @@ async fn populate_inbox(db: &SqlitePool, message_id: &str, channel_id: &str, con
|
||||
.await
|
||||
.unwrap_or_default();
|
||||
for agent_id in agents {
|
||||
if notified.insert(agent_id.clone()) {
|
||||
let _ = sqlx::query("INSERT INTO inbox (user_id, message_id, channel_id, trigger) VALUES (?, ?, ?, 'broadcast')")
|
||||
.bind(&agent_id)
|
||||
.bind(message_id)
|
||||
@@ -440,6 +447,7 @@ async fn populate_inbox(db: &SqlitePool, message_id: &str, channel_id: &str, con
|
||||
.await;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Handle @apes broadcast
|
||||
if mention == "apes" {
|
||||
@@ -449,6 +457,7 @@ async fn populate_inbox(db: &SqlitePool, message_id: &str, channel_id: &str, con
|
||||
.await
|
||||
.unwrap_or_default();
|
||||
for ape_id in apes {
|
||||
if notified.insert(ape_id.clone()) {
|
||||
let _ = sqlx::query("INSERT INTO inbox (user_id, message_id, channel_id, trigger) VALUES (?, ?, ?, 'broadcast')")
|
||||
.bind(&ape_id)
|
||||
.bind(message_id)
|
||||
@@ -458,6 +467,7 @@ async fn populate_inbox(db: &SqlitePool, message_id: &str, channel_id: &str, con
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ── Inbox row type ──
|
||||
|
||||
Reference in New Issue
Block a user