zulip-api 0.0.8

Client library for interacting with the Zulip API
Documentation
use serde::{Deserialize, Serialize};
use serde_repr::{Deserialize_repr, Serialize_repr};

use crate::{field_access, impl_cow, impl_default, impl_display};

/// Represents the details of the field type with the field type as the name of the
/// property itself. The current supported field types are as follows:
///
/// - `SHORT_TEXT`
/// - `LONG_TEXT`
/// - `DATE` for date-based fields.
/// - `SELECT` for a list of options.
/// - `URL` for links.
/// - `EXTERNAL_ACCOUNT` for external accounts.
/// - `USER` for selecting a user for the field.
/// - `PRONOUNS` for a short text field with convenient typeahead for one's preferred pronouns.
///
/// **Changes**: `PRONOUNS` type added in Zulip 6.0 (feature level 151).
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct CustomProfileFieldType {
    id: CustomProfileFieldTypeId,
    name: String,
}

impl CustomProfileFieldType {
    /// Creates a new [CustomProfileFieldType].
    pub const fn new() -> Self {
        Self {
            id: CustomProfileFieldTypeId::new(),
            name: String::new(),
        }
    }
}

field_access! {
    CustomProfileFieldType {
        /// The ID of the custom profile field type.
        id: CustomProfileFieldTypeId,
    }
}

field_access! {
    CustomProfileFieldType {
        name: cow { str },
    }
}

impl_cow!(CustomProfileFieldType);
impl_default!(CustomProfileFieldType);
impl_display!(CustomProfileFieldType);

impl From<CustomProfileFieldTypeId> for CustomProfileFieldType {
    fn from(val: CustomProfileFieldTypeId) -> Self {
        Self {
            id: val,
            name: val.as_str().into(),
        }
    }
}

/// Represents the details of the field type with the field type as the name of the property itself.
///
/// The current supported field types are as follows:
///
/// - `SHORT_TEXT`
/// - `LONG_TEXT`
/// - `DATE` for date-based fields.
/// - `SELECT` for a list of options.
/// - `URL` for links.
/// - `EXTERNAL_ACCOUNT` for external accounts.
/// - `USER` for selecting a user for the field.
/// - `PRONOUNS` for a short text field with convenient typeahead for one's preferred pronouns.
///
/// **Changes**: `PRONOUNS` type added in Zulip 6.0 (feature level 151).
#[repr(u8)]
#[derive(Clone, Copy, Debug, Eq, PartialEq, Deserialize_repr, Serialize_repr)]
pub enum CustomProfileFieldTypeId {
    ShortText = 1,
    LongText = 2,
    Date = 3,
    Select = 4,
    Url = 5,
    ExternalAccount = 6,
    User = 7,
    Pronouns = 8,
}

impl CustomProfileFieldTypeId {
    /// Represents the short text field type.
    pub const SHORT_TEXT: &str = "SHORT_TEXT";
    /// Represents the long text field type.
    pub const LONG_TEXT: &str = "LONG_TEXT";
    /// Represents the date field type.
    pub const DATE: &str = "DATE";
    /// Represents the select field type.
    pub const SELECT: &str = "SELECT";
    /// Represents the url field type.
    pub const URL: &str = "URL";
    /// Represents the external account field type.
    pub const EXTERNAL_ACCOUNT: &str = "EXTERNAL_ACCOUNT";
    /// Represents the user field type.
    pub const USER: &str = "USER";
    /// Represents the pronouns field type.
    pub const PRONOUNS: &str = "PRONOUNS";

    /// Creates a new [CustomProfileFieldTypeId].
    pub const fn new() -> Self {
        Self::ShortText
    }

    /// Gets the [CustomProfileFieldTypeId] string representation.
    pub const fn as_str(&self) -> &'static str {
        match self {
            Self::ShortText => Self::SHORT_TEXT,
            Self::LongText => Self::LONG_TEXT,
            Self::Date => Self::DATE,
            Self::Select => Self::SELECT,
            Self::Url => Self::URL,
            Self::ExternalAccount => Self::EXTERNAL_ACCOUNT,
            Self::User => Self::USER,
            Self::Pronouns => Self::PRONOUNS,
        }
    }
}

impl_default!(CustomProfileFieldTypeId);
impl_display!(CustomProfileFieldTypeId);

/// Represents the details of a custom profile field configured for this organization.
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct CustomProfileField {
    id: u64,
    #[serde(rename = "type")]
    field_type: CustomProfileFieldTypeId,
    order: u64,
    name: String,
    hint: String,
    #[serde(skip_serializing_if = "Option::is_none")]
    field_data: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    display_in_profile_summary: Option<bool>,
    required: bool,
    #[serde(rename = "editable_by_user")]
    editable_by_user: bool,
}

impl CustomProfileField {
    /// Dictionary containing the details of a custom profile field configured for this organization.
    pub const fn new() -> Self {
        Self {
            id: 0,
            field_type: CustomProfileFieldTypeId::new(),
            order: 0,
            name: String::new(),
            hint: String::new(),
            field_data: None,
            display_in_profile_summary: None,
            required: false,
            editable_by_user: false,
        }
    }
}

field_access! {
    CustomProfileField {
        /// The ID of the custom profile field. This will be referenced in the custom
        /// profile fields section of user objects.
        id: u64,
        /// An integer indicating the type of the custom profile field, which determines
        /// how it is configured and displayed to users.
        field_type: CustomProfileFieldTypeId,
        /// Custom profile fields are displayed in both settings UI and UI showing
        /// users' profiles in increasing `order`.
        order: u64,
        /// Whether an organization administrator has configured this profile field
        /// as required.
        ///
        /// Because the required property is mutable, clients cannot assume that a
        /// required custom profile field has a value. The Zulip web application
        /// displays a prominent banner to any user who has not set a value for a
        /// required field.
        ///
        /// **Changes**: New in Zulip 9.0 (feature level 244).
        required: bool,
        /// Whether regular users can edit this profile field on their own account.
        ///
        /// Note that organization administrators can edit custom profile fields
        /// for any user regardless of this setting.
        ///
        /// **Changes**: New in Zulip 10.0 (feature level 296).
        editable_by_user: bool,
    }
}

field_access! {
    CustomProfileField {
        /// The name of the custom profile field.
        name: cow { str },
        /// The help text to be displayed for the custom profile field in
        /// user-facing settings UI for configuring custom profile fields.
        hint: cow { str },
    }
}

field_access! {
    CustomProfileField {
        /// Whether the custom profile field, display or not on the user card.
        ///
        /// 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).
        ///
        /// This field is only included when its value is `true`.
        ///
        /// **Changes**: New in Zulip 6.0 (feature level 146).
        display_in_profile_summary: option { bool },
    }
}

field_access! {
    CustomProfileField {
        /// Field types 3 (List of options) and 7 (External account) support storing
        /// additional configuration for the field type in the `field_data` attribute.
        ///
        /// For field type 3 (List of options), this attribute is a JSON dictionary
        /// defining the choices and the order they will be displayed in the dropdown
        /// UI for individual users to select an option.
        ///
        /// The interface for field type 7 is not yet stabilized.
        field_data: option_cow_deref { str, String },
    }
}

impl_cow!(CustomProfileField);
impl_default!(CustomProfileField);
impl_display!(CustomProfileField);

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_custom_profile_field() {
        let id = 1;
        let field_type = CustomProfileFieldTypeId::new();
        let order = 2;
        let name = "test name";
        let hint = "test hint";
        let field_data = "test field data";
        let display_in_profile_summary = true;
        let required = false;
        let editable_by_user = true;

        let field = CustomProfileField::new()
            .with_id(id)
            .with_field_type(field_type)
            .with_order(order)
            .with_name(name)
            .with_hint(hint)
            .with_field_data(field_data)
            .with_display_in_profile_summary(display_in_profile_summary)
            .with_required(required)
            .with_editable_by_user(editable_by_user);

        assert_eq!(field.id(), id);
        assert_eq!(field.field_type(), field_type);
        assert_eq!(field.order(), order);
        assert_eq!(field.name(), name);
        assert_eq!(field.hint(), hint);
        assert_eq!(field.field_data(), Some(field_data));
        assert_eq!(
            field.display_in_profile_summary(),
            Some(display_in_profile_summary)
        );
        assert_eq!(field.required(), required);
        assert_eq!(field.editable_by_user(), editable_by_user);
    }
}