Skip to main content

concur_api/api/
ess.rs

1//! SAP Concur Event Subscription Service (ESS) v4.
2//!
3//! Endpoints: `events/v4/...`
4
5use crate::client::ConcurClient;
6use crate::error::Result;
7use reqwest::Method;
8use serde::{Deserialize, Serialize};
9
10/// Event Subscription Service API.
11pub struct EssApi<'a> {
12    client: &'a ConcurClient,
13}
14
15impl<'a> EssApi<'a> {
16    pub fn new(client: &'a ConcurClient) -> Self {
17        Self { client }
18    }
19
20    /// Browse available topics.
21    pub async fn topics(&self) -> Result<Vec<String>> {
22        self.client
23            .request(Method::GET, "/events/v4/topics")
24            .await?
25            .send()
26            .await?
27            .json()
28            .await
29            .map_err(Into::into)
30    }
31
32    /// Create or update a webhook subscription.
33    pub async fn create_subscription(
34        &self,
35        subscription: &Subscription,
36    ) -> Result<SubscriptionResult> {
37        let req = self
38            .client
39            .request(Method::PUT, "/events/v4/subscriptions/webhook")
40            .await?;
41        let req = ConcurClient::with_json(req, subscription)?;
42        self.client.execute(req).await
43    }
44
45    /// Get a subscription by ID.
46    pub async fn get_subscription(&self, subscription_id: &str) -> Result<Vec<Subscription>> {
47        self.client
48            .request(
49                Method::GET,
50                &format!("/events/v4/subscriptions/{}", subscription_id),
51            )
52            .await?
53            .send()
54            .await?
55            .json()
56            .await
57            .map_err(Into::into)
58    }
59
60    /// List all subscriptions.
61    pub async fn list_subscriptions(&self) -> Result<Vec<Subscription>> {
62        self.client
63            .request(Method::GET, "/events/v4/subscriptions")
64            .await?
65            .send()
66            .await?
67            .json()
68            .await
69            .map_err(Into::into)
70    }
71
72    /// Delete a subscription.
73    pub async fn delete_subscription(&self, subscription_id: &str) -> Result<SubscriptionResult> {
74        self.client
75            .execute_unit(
76                self.client
77                    .request(
78                        Method::DELETE,
79                        &format!("/events/v4/subscriptions/{}", subscription_id),
80                    )
81                    .await?,
82            )
83            .await?;
84        Ok(SubscriptionResult {
85            message: format!("Subscription '{}' marked for deletion", subscription_id),
86        })
87    }
88}
89
90#[derive(Debug, Clone, Serialize, Deserialize)]
91pub struct Subscription {
92    pub id: String,
93    pub filter: String,
94    pub topic: String,
95    #[serde(rename = "webHookConfig")]
96    pub webhook_config: WebhookConfig,
97    #[serde(skip_serializing_if = "Option::is_none")]
98    #[serde(rename = "applicationId")]
99    pub application_id: Option<String>,
100    #[serde(skip_serializing_if = "Option::is_none")]
101    pub scope: Option<String>,
102    #[serde(skip_serializing_if = "Option::is_none")]
103    pub groups: Option<Vec<String>>,
104    #[serde(skip_serializing_if = "Option::is_none")]
105    #[serde(rename = "companyIds")]
106    pub company_ids: Option<Vec<String>>,
107}
108
109#[derive(Debug, Clone, Serialize, Deserialize)]
110pub struct WebhookConfig {
111    pub endpoint: String,
112}
113
114#[derive(Debug, Clone, Deserialize)]
115pub struct SubscriptionResult {
116    pub message: String,
117}
118
119/// Common ESS event envelope.
120#[derive(Debug, Clone, Deserialize)]
121pub struct EssEvent<T> {
122    #[serde(rename = "eventType")]
123    pub event_type: String,
124    #[serde(rename = "timeStamp")]
125    pub time_stamp: String,
126    #[serde(rename = "correlationId")]
127    pub correlation_id: Option<String>,
128    #[serde(rename = "facts")]
129    pub facts: T,
130}