1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
//! Async, idiomatic Rust client for the [Zammad](https://zammad.com) REST API.
//!
//! The entry point is [`Client`]; reach individual resources via the methods
//! on it ([`Client::tickets`], [`Client::users`], ...). All operations are
//! `async` and powered by [`reqwest`].
//!
//! # Quick start
//!
//! ```no_run
//! use futures_util::TryStreamExt;
//! use zammad_api::{Auth, Client, models::NewArticle};
//!
//! # async fn run() -> zammad_api::Result<()> {
//! let zammad = Client::builder()
//! .url("https://help.example.com")
//! .auth(Auth::token("YOUR_TOKEN"))
//! .build()?;
//!
//! // Stream every open ticket.
//! let mut stream = zammad.tickets().search("state.name:open").stream();
//! while let Some(t) = stream.try_next().await? {
//! println!("#{} {}", t.id, t.title.as_deref().unwrap_or(""));
//! }
//!
//! // Reply to a ticket.
//! zammad
//! .articles()
//! .create(42)
//! .article(NewArticle::new("Thanks for the report.").article_type("note"))
//! .send()
//! .await?;
//! # Ok(()) }
//! ```
//!
//! # Authentication
//!
//! Zammad accepts three credential styles on every endpoint:
//!
//! ```
//! use zammad_api::Auth;
//!
//! Auth::token("YOUR_PERSONAL_ACCESS_TOKEN"); // Authorization: Token token=...
//! Auth::bearer("YOUR_OAUTH_TOKEN"); // Authorization: Bearer ...
//! Auth::basic("agent@example.com", "pw"); // Authorization: Basic ...
//! ```
//!
//! [`Auth`] values redact themselves in `Debug` output.
//!
//! # Custom fields
//!
//! Every typed model exposes an `extra: serde_json::Map<String, Value>` that
//! captures any attribute Zammad returns that isn't part of the typed schema -
//! perfect for Object Manager custom fields.
//!
//! ```no_run
//! # use zammad_api::Client;
//! # async fn run(z: &Client) -> zammad_api::Result<()> {
//! let ticket = z.tickets().get(123).await?;
//! let link = ticket.extra.get("espocrm_link").and_then(|v| v.as_str());
//!
//! // Set + verify that the value was actually persisted.
//! z.tickets().set_field(123, "espocrm_link", "https://crm/Contact/abc").await?;
//! # Ok(()) }
//! ```
//!
//! # Pagination
//!
//! List and search builders return a [`futures_core::stream::BoxStream`] from
//! `.stream()` - no `Box::pin` boilerplate needed at the call site. Each
//! builder also exposes `.page(n)` for one-shot fetches.
//!
//! # Cargo features
//!
//! - `rustls-tls` *(default)* - TLS via rustls + webpki roots.
//! - `native-tls` - TLS via the system's native TLS stack.
//!
//! # Expanded vs. compact tickets
//!
//! Passing `expand=true` to Zammad swaps several `*_id: u64` fields for their
//! human-readable string equivalents (`group`, `state`, `priority`, ...).
//! This crate models that as two distinct types - [`models::Ticket`] and
//! [`models::TicketExpanded`] - selected at call time via
//! [`Client::tickets`]`.list()` vs `.list_expanded()`.
pub use Auth;
pub use ;
pub use ;
/// Re-export of [`bytes::Bytes`] (returned by attachment downloads).
pub use Bytes;
/// Re-export of [`futures_core::Stream`] for the streams returned by list/search builders.
pub use Stream;
/// Re-export of [`serde_json::Value`] used for custom-field payloads.
pub use Value;