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}