Skip to content

Commit 6c7fdf9

Browse files
Merge pull request #1706 from ehuss/fix-zulip-no-response
Fix Zulip commands that don't give a response.
2 parents b96677b + b9f0d79 commit 6c7fdf9

File tree

1 file changed

+35
-23
lines changed

1 file changed

+35
-23
lines changed

src/zulip.rs

Lines changed: 35 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -57,15 +57,27 @@ pub async fn to_zulip_id(client: &GithubClient, github_id: i64) -> anyhow::Resul
5757
.map(|v| *v.0))
5858
}
5959

60+
/// Top-level handler for Zulip webhooks.
61+
///
62+
/// Returns a JSON response.
6063
pub async fn respond(ctx: &Context, req: Request) -> String {
6164
let content = match process_zulip_request(ctx, req).await {
62-
Ok(s) => s,
65+
Ok(None) => {
66+
return serde_json::to_string(&ResponseNotRequired {
67+
response_not_required: true,
68+
})
69+
.unwrap();
70+
}
71+
Ok(Some(s)) => s,
6372
Err(e) => format!("{:?}", e),
6473
};
6574
serde_json::to_string(&Response { content }).unwrap()
6675
}
6776

68-
async fn process_zulip_request(ctx: &Context, req: Request) -> anyhow::Result<String> {
77+
/// Processes a Zulip webhook.
78+
///
79+
/// Returns a string of the response, or None if no response is needed.
80+
async fn process_zulip_request(ctx: &Context, req: Request) -> anyhow::Result<Option<String>> {
6981
let expected_token = std::env::var("ZULIP_TOKEN").expect("`ZULIP_TOKEN` set for authorization");
7082

7183
if !openssl::memcmp::eq(req.token.as_bytes(), expected_token.as_bytes()) {
@@ -91,7 +103,8 @@ fn handle_command<'a>(
91103
gh_id: anyhow::Result<i64>,
92104
words: &'a str,
93105
message_data: &'a Message,
94-
) -> std::pin::Pin<Box<dyn std::future::Future<Output = anyhow::Result<String>> + Send + 'a>> {
106+
) -> std::pin::Pin<Box<dyn std::future::Future<Output = anyhow::Result<Option<String>>> + Send + 'a>>
107+
{
95108
Box::pin(async move {
96109
log::trace!("handling zulip command {:?}", words);
97110
let mut words = words.split_whitespace();
@@ -152,7 +165,7 @@ fn handle_command<'a>(
152165
next = words.next();
153166
}
154167

155-
Ok(String::from("Unknown command"))
168+
Ok(Some(String::from("Unknown command")))
156169
}
157170
}
158171
})
@@ -166,7 +179,7 @@ async fn execute_for_other_user(
166179
ctx: &Context,
167180
mut words: impl Iterator<Item = &str>,
168181
message_data: &Message,
169-
) -> anyhow::Result<String> {
182+
) -> anyhow::Result<Option<String>> {
170183
// username is a GitHub username, not a Zulip username
171184
let username = match words.next() {
172185
Some(username) => username,
@@ -222,7 +235,9 @@ async fn execute_for_other_user(
222235
.find(|m| m.user_id == zulip_user_id)
223236
.ok_or_else(|| format_err!("Could not find Zulip user email."))?;
224237

225-
let output = handle_command(ctx, Ok(user_id as i64), &command, message_data).await?;
238+
let output = handle_command(ctx, Ok(user_id as i64), &command, message_data)
239+
.await?
240+
.unwrap_or_default();
226241

227242
// At this point, the command has been run.
228243
let sender = match &message_data.sender_short_name {
@@ -255,7 +270,7 @@ async fn execute_for_other_user(
255270
}
256271
}
257272

258-
Ok(output)
273+
Ok(Some(output))
259274
}
260275

261276
#[derive(serde::Deserialize)]
@@ -441,7 +456,7 @@ async fn acknowledge(
441456
ctx: &Context,
442457
gh_id: i64,
443458
mut words: impl Iterator<Item = &str>,
444-
) -> anyhow::Result<String> {
459+
) -> anyhow::Result<Option<String>> {
445460
let filter = match words.next() {
446461
Some(filter) => {
447462
if words.next().is_some() {
@@ -489,14 +504,14 @@ async fn acknowledge(
489504
resp
490505
};
491506

492-
Ok(resp)
507+
Ok(Some(resp))
493508
}
494509

495510
async fn add_notification(
496511
ctx: &Context,
497512
gh_id: i64,
498513
mut words: impl Iterator<Item = &str>,
499-
) -> anyhow::Result<String> {
514+
) -> anyhow::Result<Option<String>> {
500515
let url = match words.next() {
501516
Some(idx) => idx,
502517
None => anyhow::bail!("url not present"),
@@ -525,7 +540,7 @@ async fn add_notification(
525540
)
526541
.await
527542
{
528-
Ok(()) => Ok("Created!".to_string()),
543+
Ok(()) => Ok(Some("Created!".to_string())),
529544
Err(e) => Err(format_err!("Failed to create: {e:?}")),
530545
}
531546
}
@@ -534,7 +549,7 @@ async fn add_meta_notification(
534549
ctx: &Context,
535550
gh_id: i64,
536551
mut words: impl Iterator<Item = &str>,
537-
) -> anyhow::Result<String> {
552+
) -> anyhow::Result<Option<String>> {
538553
let idx = match words.next() {
539554
Some(idx) => idx,
540555
None => anyhow::bail!("idx not present"),
@@ -557,7 +572,7 @@ async fn add_meta_notification(
557572
};
558573
let mut db = ctx.db.get().await;
559574
match add_metadata(&mut db, gh_id, idx, description.as_deref()).await {
560-
Ok(()) => Ok("Added metadata!".to_string()),
575+
Ok(()) => Ok(Some("Added metadata!".to_string())),
561576
Err(e) => Err(format_err!("Failed to add: {e:?}")),
562577
}
563578
}
@@ -566,7 +581,7 @@ async fn move_notification(
566581
ctx: &Context,
567582
gh_id: i64,
568583
mut words: impl Iterator<Item = &str>,
569-
) -> anyhow::Result<String> {
584+
) -> anyhow::Result<Option<String>> {
570585
let from = match words.next() {
571586
Some(idx) => idx,
572587
None => anyhow::bail!("from idx not present"),
@@ -588,7 +603,7 @@ async fn move_notification(
588603
match move_indices(&mut *ctx.db.get().await, gh_id, from, to).await {
589604
Ok(()) => {
590605
// to 1-base indices
591-
Ok(format!("Moved {} to {}.", from + 1, to + 1))
606+
Ok(Some(format!("Moved {} to {}.", from + 1, to + 1)))
592607
}
593608
Err(e) => Err(format_err!("Failed to move: {e:?}.")),
594609
}
@@ -662,7 +677,7 @@ async fn post_waiter(
662677
ctx: &Context,
663678
message: &Message,
664679
waiting: WaitingMessage<'_>,
665-
) -> anyhow::Result<String> {
680+
) -> anyhow::Result<Option<String>> {
666681
let posted = MessageApiRequest {
667682
recipient: Recipient::Stream {
668683
id: message
@@ -692,16 +707,13 @@ async fn post_waiter(
692707
.context("emoji reaction failed")?;
693708
}
694709

695-
Ok(serde_json::to_string(&ResponseNotRequired {
696-
response_not_required: true,
697-
})
698-
.unwrap())
710+
Ok(None)
699711
}
700712

701-
async fn trigger_docs_update() -> anyhow::Result<String> {
713+
async fn trigger_docs_update() -> anyhow::Result<Option<String>> {
702714
match docs_update().await {
703-
Ok(None) => Ok("No updates found.".to_string()),
704-
Ok(Some(pr)) => Ok(format!("Created docs update PR <{}>", pr.html_url)),
715+
Ok(None) => Ok(Some("No updates found.".to_string())),
716+
Ok(Some(pr)) => Ok(Some(format!("Created docs update PR <{}>", pr.html_url))),
705717
Err(e) => {
706718
// Don't send errors to Zulip since they may contain sensitive data.
707719
log::error!("Docs update via Zulip failed: {e:?}");

0 commit comments

Comments
 (0)