tide_github/payload.rs
1use std::convert::TryInto;
2use octocrab::models::{Repository, User, issues::Comment, issues::Issue};
3use serde::Deserialize;
4
5/// [`Payload`] represents the (JSON) payload of the webhook Github send us.
6///
7/// Every webhook includes this payload. The presence of the `Option`al fields
8/// depends on the event type this payload was send for.
9///
10/// For some event types there exists a specialized type with `Option<T>`
11/// changed for `T` where possible. Conversion from [`Payload`] to a more
12/// specialized type can be done through `TryInto` implementations.
13#[derive(Deserialize, Debug)]
14pub struct Payload {
15 /// The action (created/edited/deleted) that triggered the webhook.
16 pub action: Action,
17 /// The account that triggered the action that triggered the webhook.
18 pub sender: User,
19 /// The repository associated with the webhook.
20 pub repository: Repository,
21 /// The comment involved in the action. Only present for some event types.
22 pub comment: Option<Comment>,
23 /// The issue involved in the action. Only present for some event types.
24 pub issue: Option<Issue>,
25}
26
27/// [`IssueCommentPayload`] is a specialized version of [`Payload`] for the
28/// `IssueComment` event.
29///
30/// Notably, the `Option<T>` fields on [`Payload`] that should always be present
31/// in the case of this event are now `T`. Because conversion can fail in case
32/// the fields on the original [`Payload`] are `None`, conversion happens
33/// through the [`TryInto`](::std::convert::TryInto) trait.
34pub struct IssueCommentPayload {
35 /// The action (created/edited/deleted) that triggered the webhook.
36 pub action: Action,
37 /// The account that triggered the action that triggered the webhook.
38 pub sender: User,
39 /// The issue the comment was placed on.
40 pub issue: Issue,
41 /// The comment involved in the action.
42 pub comment: Comment,
43 /// The repository the issue belongs to.
44 pub repository: Repository,
45}
46
47impl TryInto<IssueCommentPayload> for Payload {
48 type Error = Error;
49
50 fn try_into(self) -> Result<IssueCommentPayload, Self::Error> {
51 let comment = self.comment.ok_or(Error::MissingCommentPayload)?;
52 let issue = self.issue.ok_or(Error::MissingIssuePayload)?;
53
54 Ok(IssueCommentPayload {
55 action: self.action,
56 sender: self.sender,
57 repository: self.repository,
58 comment,
59 issue,
60 })
61 }
62
63}
64
65/// The errors that can occur interpreting the webhook payload.
66#[derive(thiserror::Error, Clone, Debug)]
67pub enum Error {
68 /// The event type indicated in the `X-Github-Event` header should include
69 /// this field in the webhook payload but it didn't.
70 #[error("Expected field \"comment\" not found in webhook payload")]
71 MissingCommentPayload,
72 /// The event type indicated in the `X-Github-Event` header should include
73 /// this field in the webhook payload but it didn't.
74 #[error("Expected field \"issue\" not found in webhook payload")]
75 MissingIssuePayload,
76}
77
78/// Action represents the action the Github webhook is send for.
79#[derive(Deserialize, Debug)]
80#[serde(rename_all = "lowercase")]
81pub enum Action {
82 /// The something was created.
83 Created,
84 /// The something has been edited.
85 Edited,
86 /// The something has been deleted.
87 Deleted,
88}