Skip to main content

zulip_api/message/
basic_channel.rs

1use serde::{Deserialize, Serialize};
2
3use crate::message::channel_permission::*;
4use crate::{field_access, StreamPostPolicy, TopicsPolicy};
5
6/// Represents basic details about the channel.
7#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
8pub struct BasicChannel {
9    #[serde(skip_serializing_if = "Option::is_none")]
10    stream_id: Option<u64>,
11    #[serde(skip_serializing_if = "Option::is_none")]
12    name: Option<String>,
13    #[serde(skip_serializing_if = "Option::is_none")]
14    is_archived: Option<bool>,
15    #[serde(skip_serializing_if = "Option::is_none")]
16    description: Option<String>,
17    #[serde(skip_serializing_if = "Option::is_none")]
18    date_created: Option<u64>,
19    #[serde(skip_serializing_if = "Option::is_none")]
20    creator_id: Option<u64>,
21    #[serde(skip_serializing_if = "Option::is_none")]
22    invite_only: Option<bool>,
23    #[serde(skip_serializing_if = "Option::is_none")]
24    rendered_description: Option<String>,
25    #[serde(skip_serializing_if = "Option::is_none")]
26    is_web_public: Option<bool>,
27    #[serde(skip_serializing_if = "Option::is_none")]
28    stream_post_policy: Option<StreamPostPolicy>,
29    #[serde(skip_serializing_if = "Option::is_none")]
30    message_retention_days: Option<i64>,
31    #[serde(skip_serializing_if = "Option::is_none")]
32    history_public_to_subscribers: Option<bool>,
33    #[serde(skip_serializing_if = "Option::is_none")]
34    topics_policy: Option<TopicsPolicy>,
35    #[serde(skip_serializing_if = "Option::is_none")]
36    first_message_id: Option<u64>,
37    #[serde(skip_serializing_if = "Option::is_none")]
38    folder_id: Option<u64>,
39    #[serde(skip_serializing_if = "Option::is_none")]
40    is_recently_active: Option<bool>,
41    #[serde(skip_serializing_if = "Option::is_none")]
42    is_announcement_only: Option<bool>,
43    #[serde(skip_serializing_if = "Option::is_none")]
44    can_add_subscribers_group: Option<CanAddSubscribersGroup>,
45    #[serde(skip_serializing_if = "Option::is_none")]
46    can_remove_subscribers_group: Option<CanRemoveSubscribersGroup>,
47    #[serde(skip_serializing_if = "Option::is_none")]
48    can_administer_channel_group: Option<CanAdministerChannelGroup>,
49    #[serde(skip_serializing_if = "Option::is_none")]
50    can_delete_any_message_group: Option<CanDeleteAnyMessageGroup>,
51    #[serde(skip_serializing_if = "Option::is_none")]
52    can_delete_own_message_group: Option<CanDeleteOwnMessageGroup>,
53    #[serde(skip_serializing_if = "Option::is_none")]
54    can_move_messages_out_of_channel_group: Option<CanMoveMessagesOutOfChannelGroup>,
55    #[serde(skip_serializing_if = "Option::is_none")]
56    can_move_messages_within_channel_group: Option<CanMoveMessagesWithinChannelGroup>,
57    #[serde(skip_serializing_if = "Option::is_none")]
58    can_send_message_group: Option<CanSendMessageGroup>,
59    #[serde(skip_serializing_if = "Option::is_none")]
60    can_subscribe_group: Option<CanSubscribeGroup>,
61    #[serde(skip_serializing_if = "Option::is_none")]
62    can_resolve_topics_group: Option<CanResolveTopicsGroup>,
63    #[serde(skip_serializing_if = "Option::is_none")]
64    subscriber_count: Option<f64>,
65}
66
67impl BasicChannel {
68    /// Creates a new [BasicChannel].
69    pub const fn new() -> Self {
70        Self {
71            stream_id: None,
72            name: None,
73            is_archived: None,
74            description: None,
75            date_created: None,
76            creator_id: None,
77            invite_only: None,
78            rendered_description: None,
79            is_web_public: None,
80            stream_post_policy: None,
81            message_retention_days: None,
82            history_public_to_subscribers: None,
83            topics_policy: None,
84            first_message_id: None,
85            folder_id: None,
86            is_recently_active: None,
87            is_announcement_only: None,
88            can_add_subscribers_group: None,
89            can_remove_subscribers_group: None,
90            can_administer_channel_group: None,
91            can_delete_any_message_group: None,
92            can_delete_own_message_group: None,
93            can_move_messages_out_of_channel_group: None,
94            can_move_messages_within_channel_group: None,
95            can_send_message_group: None,
96            can_subscribe_group: None,
97            can_resolve_topics_group: None,
98            subscriber_count: None,
99        }
100    }
101}
102
103field_access! {
104    BasicChannel {
105        /// The unique ID of the channel.
106        stream_id: option { u64 },
107        /// A boolean indicating whether the channel is [archived](https://zulip.com/help/archive-a-channel).
108        ///
109        /// **Changes**: New in Zulip 10.0 (feature level 315). Previously, this endpoint never returned archived channels.
110        is_archived: option { bool },
111        /// The UNIX timestamp for when the channel was created, in UTC seconds.
112        ///
113        /// **Changes**: New in Zulip 4.0 (feature level 30).
114        date_created: option { u64 },
115        /// The ID of the user who created this channel.
116        ///
117        /// A `null` value means the channel has no recorded creator, which is often because the channel is very old,
118        /// was created during realm creation or because it was created via a data import tool or [management command](https://zulip.readthedocs.io/en/latest/production/management-commands.html).
119        ///
120        /// **Changes**: New in Zulip 9.0 (feature level 254).
121        creator_id: option { u64 },
122        /// Specifies whether the channel is private or not.
123        ///
124        /// Only people who have been invited can access a private channel.
125        invite_only: option { bool },
126        /// Whether the channel has been configured to allow unauthenticated access to its message history from the web.
127        ///
128        /// **Changes**: New in Zulip 2.1.0.
129        is_web_public: option { bool },
130        /// A deprecated representation of a superset of the users who have permission to post messages to the channel available for backwards-compatibility.
131        stream_post_policy: option { StreamPostPolicy },
132        /// Number of days that messages sent to this channel will be stored before being automatically deleted by the [message retention policy](https://zulip.com/help/message-retention-policy).
133        ///
134        /// There are two special values:
135        ///
136        /// - `null`, the default, means the channel will inherit the organization level setting.
137        /// - `-1` encodes retaining messages in this channel forever.
138        ///
139        /// **Changes**: New in Zulip 3.0 (feature level 17).
140        message_retention_days: option { i64 },
141        /// Whether the history of the channel is public to its subscribers.
142        ///
143        /// Currently always true for public channels (i.e. `\"invite_only\": false` implies `\"history_public_to_subscribers\": true`), but clients should not make that assumption,
144        /// as we may change that behavior in the future.
145        history_public_to_subscribers: option { bool },
146        /// Whether [named topics](https://zulip.com/help/introduction-to-topics) and the empty topic
147        /// (i.e., ["general chat" topic](https://zulip.com/help/general-chat-topic)) are enabled in this channel.
148        topics_policy: option { TopicsPolicy },
149        /// The ID of the first message in the channel.
150        ///
151        /// Intended to help clients determine whether they need to display UI like the \"show all topics\" widget that would suggest the channel has older history that can be accessed.
152        ///
153        /// Is `null` for channels with no message history.
154        ///
155        /// **Changes**: New in Zulip 2.1.0.
156        first_message_id: option { u64 },
157        /// The ID of the folder to which the channel belongs.
158        ///
159        /// Is `null` if channel does not belong to any folder.
160        ///
161        /// **Changes**: New in Zulip 11.0 (feature level 389).
162        folder_id: option { u64 },
163        /// Whether the channel has recent message activity.
164        ///
165        /// Clients should use this to implement [hide inactive channels](https://zulip.com/help/manage-inactive-channels) if `demote_inactive_streams` is enabled.
166        ///
167        /// **Changes**: New in Zulip 10.0 (feature level 323). Previously, clients implemented the demote_inactive_streams from local message history, resulting in a choppy loading experience.
168        is_recently_active: option { bool },
169        /// Whether the given channel is announcement only or not.
170        ///
171        /// **Changes**: Deprecated in Zulip 3.0 (feature level 1). Clients should use `stream_post_policy` instead.
172        is_announcement_only: option { bool },
173        /// The total number of non-deactivated users (including bots) who are subscribed to the channel.
174        ///
175        /// Clients are responsible for updating this value using `peer_add` and `peer_remove` events.
176        ///
177        /// The server's internals cannot guarantee this value is correctly synced with `peer_add` and `peer_remove` events for the channel.
178        /// As a result, if a (rare) race occurs between a change in the channel's subscribers and fetching this value, it is possible for a client that is correctly following the events
179        /// protocol to end up with a permanently off-by-one error in the channel's subscriber count.
180        ///
181        /// Clients are recommended to fetch full subscriber data for a channel in contexts where it is important to avoid this risk.
182        /// The official web application, for example, uses this field primarily while waiting to fetch a given channel's full subscriber list from the server.
183        ///
184        /// **Changes**: New in Zulip 11.0 (feature level 394).
185        subscriber_count: option { f64 },
186    }
187}
188
189field_access! {
190    BasicChannel {
191        /// The name of the channel.
192        name: option_cow_deref { str, String },
193        /// The short description of the channel in [Zulip-flavored Markdown](https://zulip.com/help/format-your-message-using-markdown) format, intended to be used to prepopulate UI for editing a channel's description.
194        ///
195        /// See [Markdown message formatting](https://zulip.com/api/message-formatting) for details on Zulip's HTML format.
196        description: option_cow_deref { str, String },
197        /// The short description of the channel rendered as HTML, intended to be used when displaying the channel description in a UI.
198        ///
199        /// One should use the standard Zulip rendered_markdown CSS when displaying this content so that emoji, LaTeX, and other syntax work correctly.
200        /// And any client-side security logic for user-generated message content should be applied when displaying this HTML as though it were the body of a Zulip message.
201        rendered_description: option_cow_deref { str, String },
202    }
203}
204
205field_access! {
206    BasicChannel {
207        /// A [group-setting value](https://zulip.com/api/group-setting-values) defining the set of users
208        /// who have permission to add subscribers to this channel.
209        can_add_subscribers_group: option_cow_ref { CanAddSubscribersGroup },
210        /// A [group-setting value](https://zulip.com/api/group-setting-values) defining the set of users
211        /// who have permission to remove subscribers from this channel.
212        can_remove_subscribers_group: option_cow_ref { CanRemoveSubscribersGroup },
213        /// A [group-setting value](https://zulip.com/api/group-setting-values) defining the set of users
214        /// who have permission to administer this channel.
215        can_administer_channel_group: option_cow_ref { CanAdministerChannelGroup },
216        /// A [group-setting value](https://zulip.com/api/group-setting-values) defining the set of users
217        /// who have permission to delete any message in the channel.
218        can_delete_any_message_group: option_cow_ref { CanDeleteAnyMessageGroup },
219        /// A [group-setting value](https://zulip.com/api/group-setting-values) defining the set of users
220        /// who have permission to delete the messages that they have sent in the channel.
221        can_delete_own_message_group: option_cow_ref { CanDeleteOwnMessageGroup },
222        /// A [group-setting value](https://zulip.com/api/group-setting-values) defining the set of users
223        /// who have permission to move messages out of this channel.
224        can_move_messages_out_of_channel_group: option_cow_ref { CanMoveMessagesOutOfChannelGroup },
225        /// A [group-setting value](https://zulip.com/api/group-setting-values) defining the set of users
226        /// who have permission to move messages within this channel.
227        can_move_messages_within_channel_group: option_cow_ref { CanMoveMessagesWithinChannelGroup },
228        /// A [group-setting value](https://zulip.com/api/group-setting-values) defining the set of users
229        /// who have permission to post in this channel.
230        can_send_message_group: option_cow_ref { CanSendMessageGroup },
231        /// A [group-setting value](https://zulip.com/api/group-setting-values) defining the set of users
232        /// who have permission to subscribe themselves to this channel.
233        can_subscribe_group: option_cow_ref { CanSubscribeGroup },
234        /// A [group-setting value](https://zulip.com/api/group-setting-values) defining the set of users
235        /// who have permission to resolve topics in the channel.
236        can_resolve_topics_group: option_cow_ref { CanResolveTopicsGroup },
237    }
238}
239
240impl Default for BasicChannel {
241    fn default() -> Self {
242        Self::new()
243    }
244}
245
246impl std::fmt::Display for BasicChannel {
247    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
248        serde_json::to_string(self)
249            .map_err(|_| std::fmt::Error)
250            .and_then(|s| write!(f, "{s}"))
251    }
252}
253
254#[cfg(test)]
255mod tests {
256    use super::*;
257
258    #[test]
259    fn test_basic_channel() {
260        let stream_id = 1;
261        let name = "test_name";
262        let is_archived = false;
263        let description = "test_description";
264        let date_created = 2;
265        let creator_id = 3;
266        let invite_only = true;
267        let rendered_description = "<p>test</p>";
268        let is_web_public = true;
269        let stream_post_policy = StreamPostPolicy::new();
270        let message_retention_days = -1;
271        let history_public_to_subscribers = true;
272        let topics_policy = TopicsPolicy::new();
273        let first_message_id = 4;
274        let folder_id = 5;
275        let is_recently_active = true;
276        let is_announcement_only = false;
277        let can_add_subscribers_group = CanAddSubscribersGroup::new();
278        let can_remove_subscribers_group = CanRemoveSubscribersGroup::new();
279        let can_administer_channel_group = CanAdministerChannelGroup::new();
280        let can_delete_any_message_group = CanDeleteAnyMessageGroup::new();
281        let can_delete_own_message_group = CanDeleteOwnMessageGroup::new();
282        let can_move_messages_out_of_channel_group = CanMoveMessagesOutOfChannelGroup::new();
283        let can_move_messages_within_channel_group = CanMoveMessagesWithinChannelGroup::new();
284        let can_send_message_group = CanSendMessageGroup::new();
285        let can_subscribe_group = CanSubscribeGroup::new();
286        let can_resolve_topics_group = CanResolveTopicsGroup::new();
287        let subscriber_count = 1.0f64;
288
289        let basic_channel = BasicChannel::new()
290            .with_stream_id(stream_id)
291            .with_name(name)
292            .with_is_archived(is_archived)
293            .with_description(description)
294            .with_date_created(date_created)
295            .with_creator_id(creator_id)
296            .with_invite_only(invite_only)
297            .with_rendered_description(rendered_description)
298            .with_is_web_public(is_web_public)
299            .with_stream_post_policy(stream_post_policy)
300            .with_message_retention_days(message_retention_days)
301            .with_history_public_to_subscribers(history_public_to_subscribers)
302            .with_topics_policy(topics_policy)
303            .with_first_message_id(first_message_id)
304            .with_folder_id(folder_id)
305            .with_is_recently_active(is_recently_active)
306            .with_is_announcement_only(is_announcement_only)
307            .with_can_add_subscribers_group(&can_add_subscribers_group)
308            .with_can_remove_subscribers_group(&can_remove_subscribers_group)
309            .with_can_administer_channel_group(&can_administer_channel_group)
310            .with_can_delete_any_message_group(&can_delete_any_message_group)
311            .with_can_delete_own_message_group(&can_delete_own_message_group)
312            .with_can_move_messages_out_of_channel_group(&can_move_messages_out_of_channel_group)
313            .with_can_move_messages_within_channel_group(&can_move_messages_within_channel_group)
314            .with_can_send_message_group(&can_send_message_group)
315            .with_can_subscribe_group(&can_subscribe_group)
316            .with_can_resolve_topics_group(&can_resolve_topics_group)
317            .with_subscriber_count(subscriber_count);
318        let basic_channel_json = basic_channel.to_string();
319
320        assert_eq!(
321            serde_json::to_string(&basic_channel).unwrap(),
322            basic_channel_json
323        );
324        assert_eq!(
325            serde_json::from_str::<BasicChannel>(&basic_channel_json).unwrap(),
326            basic_channel
327        );
328
329        assert_eq!(basic_channel.stream_id(), Some(stream_id));
330        assert_eq!(basic_channel.name(), Some(name));
331        assert_eq!(basic_channel.is_archived(), Some(is_archived));
332        assert_eq!(basic_channel.description(), Some(description));
333        assert_eq!(basic_channel.date_created(), Some(date_created));
334        assert_eq!(basic_channel.creator_id(), Some(creator_id));
335        assert_eq!(basic_channel.invite_only(), Some(invite_only));
336        assert_eq!(
337            basic_channel.rendered_description(),
338            Some(rendered_description)
339        );
340        assert_eq!(basic_channel.is_web_public(), Some(is_web_public));
341        assert_eq!(basic_channel.stream_post_policy(), Some(stream_post_policy));
342        assert_eq!(
343            basic_channel.message_retention_days(),
344            Some(message_retention_days)
345        );
346        assert_eq!(
347            basic_channel.history_public_to_subscribers(),
348            Some(history_public_to_subscribers)
349        );
350        assert_eq!(basic_channel.topics_policy(), Some(topics_policy));
351        assert_eq!(basic_channel.first_message_id(), Some(first_message_id));
352        assert_eq!(basic_channel.folder_id(), Some(folder_id));
353        assert_eq!(basic_channel.is_recently_active(), Some(is_recently_active));
354        assert_eq!(
355            basic_channel.is_announcement_only(),
356            Some(is_announcement_only)
357        );
358        assert_eq!(
359            basic_channel.can_add_subscribers_group(),
360            Some(&can_add_subscribers_group)
361        );
362        assert_eq!(
363            basic_channel.can_remove_subscribers_group(),
364            Some(&can_remove_subscribers_group)
365        );
366        assert_eq!(
367            basic_channel.can_administer_channel_group(),
368            Some(&can_administer_channel_group)
369        );
370        assert_eq!(
371            basic_channel.can_delete_any_message_group(),
372            Some(&can_delete_any_message_group)
373        );
374        assert_eq!(
375            basic_channel.can_delete_own_message_group(),
376            Some(&can_delete_own_message_group)
377        );
378        assert_eq!(
379            basic_channel.can_move_messages_out_of_channel_group(),
380            Some(&can_move_messages_out_of_channel_group)
381        );
382        assert_eq!(
383            basic_channel.can_move_messages_within_channel_group(),
384            Some(&can_move_messages_within_channel_group)
385        );
386        assert_eq!(
387            basic_channel.can_send_message_group(),
388            Some(&can_send_message_group)
389        );
390        assert_eq!(
391            basic_channel.can_subscribe_group(),
392            Some(&can_subscribe_group)
393        );
394        assert_eq!(
395            basic_channel.can_resolve_topics_group(),
396            Some(&can_resolve_topics_group)
397        );
398        assert_eq!(basic_channel.subscriber_count(), Some(subscriber_count));
399    }
400}