zulip_api/message/custom_profile.rs
1use serde::{Deserialize, Serialize};
2use serde_repr::{Deserialize_repr, Serialize_repr};
3
4use crate::{field_access, impl_cow, impl_default, impl_display};
5
6/// Represents the details of the field type with the field type as the name of the
7/// property itself. The current supported field types are as follows:
8///
9/// - `SHORT_TEXT`
10/// - `LONG_TEXT`
11/// - `DATE` for date-based fields.
12/// - `SELECT` for a list of options.
13/// - `URL` for links.
14/// - `EXTERNAL_ACCOUNT` for external accounts.
15/// - `USER` for selecting a user for the field.
16/// - `PRONOUNS` for a short text field with convenient typeahead for one's preferred pronouns.
17///
18/// **Changes**: `PRONOUNS` type added in Zulip 6.0 (feature level 151).
19#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
20pub struct CustomProfileFieldType {
21 id: CustomProfileFieldTypeId,
22 name: String,
23}
24
25impl CustomProfileFieldType {
26 /// Creates a new [CustomProfileFieldType].
27 pub const fn new() -> Self {
28 Self {
29 id: CustomProfileFieldTypeId::new(),
30 name: String::new(),
31 }
32 }
33}
34
35field_access! {
36 CustomProfileFieldType {
37 /// The ID of the custom profile field type.
38 id: CustomProfileFieldTypeId,
39 }
40}
41
42field_access! {
43 CustomProfileFieldType {
44 name: cow { str },
45 }
46}
47
48impl_cow!(CustomProfileFieldType);
49impl_default!(CustomProfileFieldType);
50impl_display!(CustomProfileFieldType);
51
52impl From<CustomProfileFieldTypeId> for CustomProfileFieldType {
53 fn from(val: CustomProfileFieldTypeId) -> Self {
54 Self {
55 id: val,
56 name: val.as_str().into(),
57 }
58 }
59}
60
61/// Represents the details of the field type with the field type as the name of the property itself.
62///
63/// The current supported field types are as follows:
64///
65/// - `SHORT_TEXT`
66/// - `LONG_TEXT`
67/// - `DATE` for date-based fields.
68/// - `SELECT` for a list of options.
69/// - `URL` for links.
70/// - `EXTERNAL_ACCOUNT` for external accounts.
71/// - `USER` for selecting a user for the field.
72/// - `PRONOUNS` for a short text field with convenient typeahead for one's preferred pronouns.
73///
74/// **Changes**: `PRONOUNS` type added in Zulip 6.0 (feature level 151).
75#[repr(u8)]
76#[derive(Clone, Copy, Debug, Eq, PartialEq, Deserialize_repr, Serialize_repr)]
77pub enum CustomProfileFieldTypeId {
78 ShortText = 1,
79 LongText = 2,
80 Date = 3,
81 Select = 4,
82 Url = 5,
83 ExternalAccount = 6,
84 User = 7,
85 Pronouns = 8,
86}
87
88impl CustomProfileFieldTypeId {
89 /// Represents the short text field type.
90 pub const SHORT_TEXT: &str = "SHORT_TEXT";
91 /// Represents the long text field type.
92 pub const LONG_TEXT: &str = "LONG_TEXT";
93 /// Represents the date field type.
94 pub const DATE: &str = "DATE";
95 /// Represents the select field type.
96 pub const SELECT: &str = "SELECT";
97 /// Represents the url field type.
98 pub const URL: &str = "URL";
99 /// Represents the external account field type.
100 pub const EXTERNAL_ACCOUNT: &str = "EXTERNAL_ACCOUNT";
101 /// Represents the user field type.
102 pub const USER: &str = "USER";
103 /// Represents the pronouns field type.
104 pub const PRONOUNS: &str = "PRONOUNS";
105
106 /// Creates a new [CustomProfileFieldTypeId].
107 pub const fn new() -> Self {
108 Self::ShortText
109 }
110
111 /// Gets the [CustomProfileFieldTypeId] string representation.
112 pub const fn as_str(&self) -> &'static str {
113 match self {
114 Self::ShortText => Self::SHORT_TEXT,
115 Self::LongText => Self::LONG_TEXT,
116 Self::Date => Self::DATE,
117 Self::Select => Self::SELECT,
118 Self::Url => Self::URL,
119 Self::ExternalAccount => Self::EXTERNAL_ACCOUNT,
120 Self::User => Self::USER,
121 Self::Pronouns => Self::PRONOUNS,
122 }
123 }
124}
125
126impl_default!(CustomProfileFieldTypeId);
127impl_display!(CustomProfileFieldTypeId);
128
129/// Represents the details of a custom profile field configured for this organization.
130#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
131pub struct CustomProfileField {
132 id: u64,
133 #[serde(rename = "type")]
134 field_type: CustomProfileFieldTypeId,
135 order: u64,
136 name: String,
137 hint: String,
138 #[serde(skip_serializing_if = "Option::is_none")]
139 field_data: Option<String>,
140 #[serde(skip_serializing_if = "Option::is_none")]
141 display_in_profile_summary: Option<bool>,
142 required: bool,
143 #[serde(rename = "editable_by_user")]
144 editable_by_user: bool,
145}
146
147impl CustomProfileField {
148 /// Dictionary containing the details of a custom profile field configured for this organization.
149 pub const fn new() -> Self {
150 Self {
151 id: 0,
152 field_type: CustomProfileFieldTypeId::new(),
153 order: 0,
154 name: String::new(),
155 hint: String::new(),
156 field_data: None,
157 display_in_profile_summary: None,
158 required: false,
159 editable_by_user: false,
160 }
161 }
162}
163
164field_access! {
165 CustomProfileField {
166 /// The ID of the custom profile field. This will be referenced in the custom
167 /// profile fields section of user objects.
168 id: u64,
169 /// An integer indicating the type of the custom profile field, which determines
170 /// how it is configured and displayed to users.
171 field_type: CustomProfileFieldTypeId,
172 /// Custom profile fields are displayed in both settings UI and UI showing
173 /// users' profiles in increasing `order`.
174 order: u64,
175 /// Whether an organization administrator has configured this profile field
176 /// as required.
177 ///
178 /// Because the required property is mutable, clients cannot assume that a
179 /// required custom profile field has a value. The Zulip web application
180 /// displays a prominent banner to any user who has not set a value for a
181 /// required field.
182 ///
183 /// **Changes**: New in Zulip 9.0 (feature level 244).
184 required: bool,
185 /// Whether regular users can edit this profile field on their own account.
186 ///
187 /// Note that organization administrators can edit custom profile fields
188 /// for any user regardless of this setting.
189 ///
190 /// **Changes**: New in Zulip 10.0 (feature level 296).
191 editable_by_user: bool,
192 }
193}
194
195field_access! {
196 CustomProfileField {
197 /// The name of the custom profile field.
198 name: cow { str },
199 /// The help text to be displayed for the custom profile field in
200 /// user-facing settings UI for configuring custom profile fields.
201 hint: cow { str },
202 }
203}
204
205field_access! {
206 CustomProfileField {
207 /// Whether the custom profile field, display or not on the user card.
208 ///
209 /// Currently it's value not allowed to be `true` of `Long text` and `Person picker` [profile field types](https://zulip.com/help/custom-profile-fields#profile-field-types).
210 ///
211 /// This field is only included when its value is `true`.
212 ///
213 /// **Changes**: New in Zulip 6.0 (feature level 146).
214 display_in_profile_summary: option { bool },
215 }
216}
217
218field_access! {
219 CustomProfileField {
220 /// Field types 3 (List of options) and 7 (External account) support storing
221 /// additional configuration for the field type in the `field_data` attribute.
222 ///
223 /// For field type 3 (List of options), this attribute is a JSON dictionary
224 /// defining the choices and the order they will be displayed in the dropdown
225 /// UI for individual users to select an option.
226 ///
227 /// The interface for field type 7 is not yet stabilized.
228 field_data: option_cow_deref { str, String },
229 }
230}
231
232impl_cow!(CustomProfileField);
233impl_default!(CustomProfileField);
234impl_display!(CustomProfileField);
235
236#[cfg(test)]
237mod tests {
238 use super::*;
239
240 #[test]
241 fn test_custom_profile_field() {
242 let id = 1;
243 let field_type = CustomProfileFieldTypeId::new();
244 let order = 2;
245 let name = "test name";
246 let hint = "test hint";
247 let field_data = "test field data";
248 let display_in_profile_summary = true;
249 let required = false;
250 let editable_by_user = true;
251
252 let field = CustomProfileField::new()
253 .with_id(id)
254 .with_field_type(field_type)
255 .with_order(order)
256 .with_name(name)
257 .with_hint(hint)
258 .with_field_data(field_data)
259 .with_display_in_profile_summary(display_in_profile_summary)
260 .with_required(required)
261 .with_editable_by_user(editable_by_user);
262
263 assert_eq!(field.id(), id);
264 assert_eq!(field.field_type(), field_type);
265 assert_eq!(field.order(), order);
266 assert_eq!(field.name(), name);
267 assert_eq!(field.hint(), hint);
268 assert_eq!(field.field_data(), Some(field_data));
269 assert_eq!(
270 field.display_in_profile_summary(),
271 Some(display_in_profile_summary)
272 );
273 assert_eq!(field.required(), required);
274 assert_eq!(field.editable_by_user(), editable_by_user);
275 }
276}