#![allow(missing_docs, clippy::upper_case_acronyms)]
use crate::{f32_or_str, Error};
use num_derive::FromPrimitive;
use num_traits::FromPrimitive;
use serde::{Deserialize, Deserializer, Serialize};
use serde_json::Value;
use serde_repr::{Deserialize_repr, Serialize_repr};
use std::{clone::Clone, default::Default, fmt, iter::Iterator, str::FromStr};
pub use crate::datetime::{DateTime, Utc};
pub use crate::{
item::Item,
list::{
fset_f, fset_i, fset_id, fset_s, fset_t, fset_vid, fset_vs, fup_f, fup_i, fup_id, fup_s,
fup_t, fup_vid, fup_vs, FieldSetVal, FieldVal, ListInfo,
},
};
pub type ID = u64;
pub type ShortId = String; pub type UUID = String; pub type ErrorCode = String;
pub type JsonMap = serde_json::map::Map<String, Value>;
pub type Field = Element;
fn default_bool() -> bool {
false
}
fn empty_string() -> String {
String::from("")
}
#[derive(Debug)]
pub enum AllId {
#[allow(non_camel_case_types)]
ID(u64),
ShortId(String),
UUID(String),
Any(String),
}
pub trait ZKObjectID {
fn get_id(&self) -> ID;
fn get_uuid(&self) -> &UUID;
}
impl fmt::Display for AllId {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let tmp: String;
write!(
f,
"{}",
match self {
AllId::ID(val) => {
tmp = val.to_string();
&tmp
}
AllId::ShortId(s) => (*s).as_str(),
AllId::UUID(s) => (*s).as_str(),
AllId::Any(s) => (*s).as_str(),
}
)
}
}
impl From<ID> for AllId {
fn from(id: ID) -> AllId {
AllId::ID(id)
}
}
impl From<&ID> for AllId {
fn from(pid: &ID) -> AllId {
AllId::ID(*pid)
}
}
impl From<String> for AllId {
fn from(s: String) -> AllId {
AllId::Any(s)
}
}
impl From<&String> for AllId {
fn from(s: &String) -> AllId {
AllId::Any(s.clone())
}
}
impl From<&'_ str> for AllId {
fn from(s: &str) -> AllId {
AllId::Any(s.to_string())
}
}
#[derive(Serialize, Deserialize, Debug)]
#[serde(rename_all = "lowercase")]
pub enum SortDirection {
Asc,
Desc,
}
#[derive(
strum_macros::Display,
Serialize_repr,
Deserialize_repr,
PartialEq,
Debug,
Copy,
Clone,
FromPrimitive,
)]
#[repr(u8)]
pub enum ElementCategoryId {
Text = 1,
Number = 2,
#[allow(non_camel_case_types)]
URL = 3,
Date = 4,
Checkbox = 5,
Categories = 6,
Formula = 7,
DateCreated = 8,
DateUpdated = 9,
DateDeprecated = 10,
UserCreatedBy = 11,
UserUpdatedBy = 12,
UserDeprecatedBy = 13,
Persons = 14,
Files = 15,
References = 16,
Hierarchy = 17,
SubEntries = 18,
Dependencies = 19,
}
#[derive(Serialize, Deserialize, PartialEq, Debug)]
pub struct PredefinedCategory {
pub id: ID,
#[serde(rename = "shortId")]
pub short_id: ShortId,
pub uuid: UUID,
pub name: String,
#[serde(rename = "colorHex")]
pub color: String,
pub created_at: DateTime<Utc>,
pub updated_at: DateTime<Utc>,
pub deprecated_at: Option<DateTime<Utc>>,
#[serde(rename = "elementId")]
pub element_id: ID,
#[serde(rename = "listId")]
pub list_id: ID,
#[serde(rename = "resourceTags")]
pub resource_tags: Vec<Value>,
#[serde(rename = "sortOrder", deserialize_with = "f32_or_str")]
pub sort_order: f32,
}
impl ZKObjectID for PredefinedCategory {
fn get_id(&self) -> ID {
self.id
}
fn get_uuid(&self) -> &UUID {
&self.uuid
}
}
#[derive(Serialize, Deserialize, PartialEq, Debug)]
#[serde(untagged)]
pub enum ChildList {
Child(List),
NoList(NoAccessList),
}
#[derive(Serialize, Deserialize, PartialEq, Debug)]
pub struct NoAccessList {
#[serde(rename = "ACCESS_DENIED")]
pub access_denied: bool,
pub deprecated_at: Option<DateTime<Utc>>,
pub name: String,
pub uuid: String,
}
#[derive(Serialize, Deserialize, PartialEq, Debug)]
pub struct ElementData {
#[serde(rename = "predefinedCategories")]
pub predefined_categories: Option<Vec<PredefinedCategory>>,
#[serde(default = "default_bool")]
pub multiple: bool,
#[serde(rename = "childList")]
pub child_list: Option<ChildList>,
#[serde(rename = "childListUUID")]
pub child_list_uuid: Option<UUID>,
#[serde(rename = "mirrorElementUUID")]
pub mirror_element_uuid: Option<UUID>,
#[serde(flatten)]
pub fields: JsonMap,
}
#[derive(Serialize, Deserialize, PartialEq, Debug)]
pub struct BusinessData {
#[serde(flatten)]
pub fields: JsonMap,
}
#[derive(Serialize, Deserialize, PartialEq, Debug)]
pub struct ElementDataCategories {
#[serde(rename = "allowInlineCreation")]
pub allow_inline_creation: bool,
#[serde(default = "default_bool")]
pub multiple: bool,
#[serde(rename = "predefinedCategories")]
pub predefined_categories: Vec<PredefinedCategory>,
}
#[derive(Serialize, Deserialize, Debug)]
pub struct OrderBy {
pub column: Option<String>,
pub direction: SortDirection,
}
#[derive(Serialize, Deserialize, Debug)]
pub struct GetEntriesRequest {
pub filter: Value,
pub limit: usize,
pub skip: usize,
#[serde(rename = "allowDeprecated")]
pub allow_deprecated: bool,
#[serde(rename = "orderBy")]
pub order_by: Vec<OrderBy>,
}
impl Default for GetEntriesRequest {
fn default() -> Self {
Self {
filter: Value::Object(JsonMap::new()),
limit: 0,
skip: 0,
allow_deprecated: false,
order_by: Vec::new(),
}
}
}
#[derive(Serialize, Debug)]
#[serde(rename_all = "camelCase")]
pub struct GetEntriesViewRequest {
pub filter: Value,
pub group_by_element_id: ID,
pub limit: u64,
pub skip: u64,
pub allow_deprecated: bool,
pub task_style: bool,
}
impl Default for GetEntriesViewRequest {
fn default() -> Self {
Self {
filter: Value::Object(JsonMap::new()),
group_by_element_id: 0,
limit: 0,
skip: 0,
allow_deprecated: false,
task_style: false,
}
}
}
#[derive(Deserialize, Debug)]
#[serde(rename_all = "camelCase")]
pub struct FilterCountData {
pub total: u64,
pub filtered_total: u64,
#[serde(flatten)]
pub fields: JsonMap,
}
#[derive(Deserialize, Debug)]
#[serde(rename_all = "camelCase")]
pub struct GetEntriesViewResponse {
pub count_data: FilterCountData,
pub count_data_per_group: Vec<FilterCountData>,
pub list_entries: Vec<Entry>,
}
#[derive(Deserialize, Debug)]
pub struct ErrorInfo {
pub name: String,
pub code: ErrorCode,
#[serde(rename = "statusCode")]
pub status_code: u16,
pub message: String,
pub description: String,
}
#[derive(Deserialize, Debug)]
pub struct ErrorResult {
pub error: ErrorInfo,
}
#[derive(Serialize, Deserialize, Debug)]
#[serde(rename_all = "camelCase")]
pub enum RoleID {
ListOwner,
ListAdmin,
ListUser,
CommentOnlyListUser,
ReadOnlyListUser,
WorkspaceOwner,
WorkspaceUser,
WorkspaceAdmin,
CommentOnlyWorkspaceUser,
ReadOnlyWorkspaceUser,
OrganizationOwner,
OrganizationUser,
}
#[derive(Serialize, Deserialize, Debug)]
#[serde(rename_all = "lowercase")]
pub enum LoginProvider {
Local,
Facebook,
Google,
Github,
Slack,
Trello,
}
#[derive(Serialize, Deserialize, Debug)]
pub enum AccessType {
Organization,
Workspace,
List,
Project,
}
#[derive(Serialize, Deserialize, Debug)]
pub struct Access {
pub id: Option<ID>,
#[serde(rename = "shortId")]
pub short_id: Option<ShortId>,
pub uuid: Option<UUID>,
#[serde(rename = "accessType")]
pub access_type: AccessType,
#[serde(rename = "userId")]
pub user_id: Option<ID>,
#[serde(rename = "workspaceId")]
pub workspace_id: Option<ID>,
#[serde(rename = "listId")]
pub list_id: Option<ID>,
#[serde(rename = "organizationId")]
pub organization_id: Option<ID>,
#[serde(rename = "roleId")]
pub role_id: RoleID,
pub created_at: Option<DateTime<Utc>>,
}
#[derive(Serialize, Deserialize, Debug)]
#[allow(non_camel_case_types)]
pub enum DeviceOperatingSystem {
Android,
iOS,
}
#[derive(Serialize, Deserialize, Debug)]
#[serde(rename_all = "camelCase")]
pub enum FilterKeys {
Text,
NumberFrom,
NumberTo,
DateType,
DateFrom,
DateTo,
Checked,
FilterCategories,
FilterPersons,
FilterReference,
Level,
}
#[derive(Serialize, Deserialize, Debug)]
pub enum ElementCategoryGroup {
Control,
}
#[derive(Serialize, Deserialize, Debug)]
#[serde(rename_all = "camelCase")]
pub struct ElementCategory {
pub id: ElementCategoryId,
pub short_id: ShortId,
pub uuid: UUID,
pub name: String,
pub group: ElementCategoryGroup,
pub display_name: String,
pub placeholder_schema: String,
pub container: bool,
pub listable: bool,
pub filterable: bool,
pub filter_keys: Vec<String>,
pub sort_key: String,
pub searchable: bool,
pub is_static: bool,
pub min_width: String,
pub width: String,
pub max_width: String,
pub is_width_fixed: bool,
pub can_set: bool,
pub can_add: bool,
pub can_remove: bool,
pub can_replace: bool,
pub business_data_definition: Value,
pub business_data_defaults: Value,
pub element_data_definition: Value,
pub element_data_defaults: Value,
#[serde(rename = "created_at")]
pub created_at: DateTime<Utc>,
}
#[derive(Serialize, Deserialize, PartialEq, Debug)]
pub struct Element {
pub id: ID, #[serde(rename = "shortId")]
pub short_id: ShortId,
pub uuid: UUID,
pub name: String,
pub description: Option<String>,
#[serde(rename = "businessData")]
pub business_data: BusinessData,
#[serde(rename = "elementData")]
pub element_data: ElementData,
#[serde(rename = "isPrimary")]
pub is_primary: bool,
#[serde(rename = "isAutoCreated")]
pub is_auto_created: bool,
#[serde(rename = "sortOrder", deserialize_with = "f32_or_str")]
pub sort_order: f32,
pub visible: bool,
pub created_at: DateTime<Utc>,
pub updated_at: DateTime<Utc>,
pub deprecated_at: Option<DateTime<Utc>>,
#[serde(rename = "elementcategory")]
pub element_category: ElementCategoryId,
#[serde(rename = "listId")]
pub list_id: ID,
#[serde(rename = "visibleInPublicList")]
pub visible_in_public_list: Option<bool>,
}
impl Element {
pub fn get_description(&self) -> &str {
match &self.description {
Some(s) => s.as_str(),
None => "",
}
}
pub fn get_choice_id(&self, choice_name: &str) -> Result<ID, Error> {
if self.element_category == ElementCategoryId::Categories {
if let Some(categories) = &self.element_data.predefined_categories {
for c in categories {
if c.uuid == choice_name || c.name == choice_name {
return Ok(c.id);
}
}
}
}
Err(Error::Other(format!(
"Invalid choice '{}' for field '{}'",
choice_name, &self.name
)))
}
pub fn numeric_type(&self) -> Option<NumericType> {
if self.element_category == ElementCategoryId::Number {
if let Some(format_val) = self.element_data.fields.get("format") {
if let Some(format_obj) = format_val.as_object() {
if let Some(name_val) = format_obj.get("name") {
return match name_val.as_str() {
Some("integer") => Some(NumericType::Integer),
Some("decimal") => Some(NumericType::Decimal),
_ => None,
};
}
}
}
}
None
}
}
impl ZKObjectID for Element {
fn get_id(&self) -> ID {
self.id
}
fn get_uuid(&self) -> &UUID {
&self.uuid
}
}
pub enum NumericType {
Integer,
Decimal,
}
#[derive(Serialize_repr, Deserialize_repr, PartialEq, Debug)]
#[repr(u8)]
pub enum ActivityFilter {
All = 0,
SystemMessages = 1,
Comments = 2,
Deleted = 3,
}
#[derive(Serialize_repr, Deserialize_repr, PartialEq, Debug)]
#[repr(u8)]
pub enum ActivityType {
Comment = 0,
ResourceCreated = 1,
ResourceUpdated = 2,
ResourceDeprecated = 3,
ResourceImported = 4,
ResourceCopied = 5,
ResourceRestored = 6,
BulkOperationInList = 7,
ResourceDeleted = 8,
}
#[derive(Serialize_repr, Deserialize_repr, PartialEq, Debug)]
#[repr(u8)]
pub enum ActivityCreatedIn {
Workspace = 0,
List = 1,
ListEntry = 2,
ListElement = 3,
}
#[derive(Serialize_repr, Deserialize_repr, PartialEq, Debug)]
#[repr(u8)]
pub enum ActivityBulkAction {
Add = 0,
Set = 1,
Remove = 2,
Replace = 3,
}
#[derive(Serialize, Deserialize, Debug)]
#[serde(rename_all = "camelCase")]
pub struct ActivityChangedData {
pub bulk_action: ActivityBulkAction,
}
#[derive(Deserialize, Debug)]
pub struct Activity {
pub id: ID,
pub uuid: UUID,
#[serde(rename = "type")]
pub activity_type: ActivityType,
pub created_in: ActivityCreatedIn,
pub message: Option<String>,
#[serde(rename = "isBulk")]
pub is_bulk: bool,
pub bulk_rowcount: Option<u64>,
#[serde(rename = "changedData")]
pub changed_data: ElementChange,
#[serde(rename = "changedDataElementId")]
pub changed_data_element_id: Option<ID>,
#[serde(rename = "workspaceId")]
pub workspace_id: Option<ID>,
#[serde(rename = "workspaceShortId")]
pub workspace_short_id: Option<ShortId>,
#[serde(rename = "workspaceUUID")]
pub workspace_uuid: Option<UUID>,
#[serde(rename = "workspaceName")]
pub workspace_name: Option<String>,
#[serde(rename = "workspaceDeprecated_at")]
pub workspace_deprecated_at: Option<DateTime<Utc>>,
#[serde(rename = "parentUUID")]
pub parent_uuid: Option<UUID>,
#[serde(rename = "listId")]
pub list_id: Option<ID>,
#[serde(rename = "listShortId")]
pub list_short_id: Option<ShortId>,
#[serde(rename = "listUUID")]
pub list_uuid: Option<UUID>,
#[serde(rename = "listName")]
pub list_name: Option<String>,
#[serde(rename = "listDeprecated_at")]
pub list_deprecated_at: Option<DateTime<Utc>>,
#[serde(rename = "listEntryId")]
pub list_entry_id: Option<ID>,
#[serde(rename = "listEntryUUID")]
pub list_entry_uuid: Option<UUID>,
#[serde(rename = "listEntryName")]
pub list_entry_name: Option<String>,
#[serde(rename = "listEntryDescription")]
pub list_entry_description: Option<String>,
#[serde(rename = "listEntryDeprecated_at")]
pub list_entry_deprecated_at: Option<DateTime<Utc>>,
#[serde(rename = "elementName")]
pub element_name: Option<String>,
pub created_at: DateTime<Utc>,
pub updated_at: DateTime<Utc>,
pub deprecated_at: Option<DateTime<Utc>>,
#[serde(rename = "userId")]
pub user_id: ID,
#[serde(rename = "userDisplayname")] pub user_display_name: String,
#[serde(rename = "userFullname")]
pub user_full_name: String,
#[serde(rename = "userUsername")]
pub user_username: String,
#[serde(rename = "userInitials")]
pub user_initials: String,
#[serde(rename = "userIsImagePreferred")]
pub user_is_image_preferred: bool,
}
impl ZKObjectID for Activity {
fn get_id(&self) -> ID {
self.id
}
fn get_uuid(&self) -> &UUID {
&self.uuid
}
}
#[derive(Serialize, Deserialize, Debug)]
#[serde(rename_all = "camelCase")]
pub struct ChangedValue<T> {
pub value_from: Option<T>,
pub value_to: Option<T>,
}
pub enum FromTo {
From,
To,
}
impl<T> ChangedValue<T> {
fn get(&self, ft: FromTo) -> &Option<T> {
match ft {
FromTo::From => &self.value_from,
FromTo::To => &self.value_to,
}
}
}
#[derive(Serialize, Deserialize, Debug)]
#[serde(rename_all = "camelCase")]
pub struct ChangedArray<T> {
pub value_from: Vec<T>,
pub value_to: Vec<T>,
pub value_from_as_strings: Vec<String>,
pub value_to_as_strings: Vec<String>,
}
impl<T> ChangedArray<T> {
fn get(&self, ft: FromTo) -> &Vec<T> {
match ft {
FromTo::From => &self.value_from,
FromTo::To => &self.value_to,
}
}
fn as_strings(&self, ft: FromTo) -> &Vec<String> {
match ft {
FromTo::From => &self.value_from_as_strings,
FromTo::To => &self.value_to_as_strings,
}
}
}
#[derive(Serialize, Deserialize, Debug)]
#[serde(rename_all = "camelCase")]
pub struct DateValue {
pub date: Option<String>,
pub end_date: Option<String>,
pub has_time: bool,
pub duration: Option<String>, }
#[derive(Deserialize, Debug)]
#[serde(rename_all = "camelCase")]
pub enum ChangedData {
Text(ChangedValue<String>),
Number(ChangedValue<f64>),
Date(ChangedValue<DateValue>),
Categories(ChangedArray<ID>),
Persons(ChangedArray<ID>),
References(ChangedArray<UUID>),
Other(Value),
}
fn opt_to_string<T: ToString>(v: &Option<T>) -> String {
match v {
Some(x) => x.to_string(),
None => "".to_string(),
}
}
impl ChangedData {
pub fn val_to_string(&self, ft: FromTo) -> String {
use crate::join;
match self {
ChangedData::Text(txt_val) => opt_to_string(txt_val.get(ft)),
ChangedData::Number(num_val) => opt_to_string(num_val.get(ft)),
ChangedData::Date(date_val) => match date_val.get(ft) {
Some(DateValue {
date: Some(ref date),
end_date: _,
has_time: _,
duration: _,
}) => date.clone(),
Some(DateValue {
date: None,
end_date: _,
has_time: _,
duration: _,
}) => "".to_string(),
None => "".to_string(),
},
ChangedData::Categories(arr) => join(",", arr.as_strings(ft)),
ChangedData::Persons(arr) => join(",", arr.as_strings(ft)),
ChangedData::References(arr) => join(",", arr.get(ft)),
ChangedData::Other(_) => "<value>".to_string(),
}
}
}
#[derive(Debug)]
pub struct ElementChange {
pub category_id: Option<ElementCategoryId>,
pub data: ChangedData,
}
#[derive(Serialize, Deserialize, Debug)]
pub struct NewActivityElement {
pub name: String,
#[serde(rename = "elementCategory")]
pub element_category: ElementCategoryId,
}
#[derive(Serialize, Deserialize, Debug)]
pub struct NewComment {
pub message: String,
}
#[derive(Serialize_repr, Deserialize_repr, PartialEq, Debug)]
#[repr(u8)]
pub enum BackgroundRole {
UserDefault = 0,
}
#[derive(Serialize_repr, Deserialize_repr, PartialEq, Debug)]
#[repr(u8)]
pub enum BackgroundType {
AdminColor = 0,
AdminImage = 1,
AdminTexture = 2,
UserImage = 3,
WorkspaceImage = 4,
ListImage = 5,
AdminThemes = 6,
}
#[derive(Serialize_repr, Deserialize_repr, PartialEq, Debug)]
#[repr(u8)]
pub enum BackgroundTheme {
Dark = 0,
Light = 1,
Tron = 2,
DarkTransparent = 3,
LightTransparent = 4,
Matrix = 5,
IronMan = 6,
}
#[derive(Serialize_repr, Deserialize_repr, PartialEq, Debug)]
#[repr(u8)]
pub enum BackgroundStyle {
Cover = 0,
Tile = 1,
}
#[derive(Serialize, Deserialize, Debug)]
#[serde(rename_all = "camelCase")]
pub struct Background {
pub id: ID,
pub short_id: ShortId,
pub uuid: UUID,
pub role: BackgroundRole,
pub r#type: BackgroundType,
pub target_id: ID,
pub file_id: ShortId,
#[serde(rename = "color_hex")]
pub color: String,
pub theme: BackgroundTheme,
pub style: BackgroundStyle,
pub description: String,
pub link: String,
pub preview_file_short_id: ShortId,
}
impl ZKObjectID for Background {
fn get_id(&self) -> ID {
self.id
}
fn get_uuid(&self) -> &UUID {
&self.uuid
}
}
#[derive(Serialize, Deserialize, Debug)]
pub struct ChecklistItem {
pub checked: bool,
pub text: String,
}
#[derive(Serialize, Deserialize, Debug)]
#[serde(rename_all = "camelCase")]
pub struct Checklist {
pub uuid: Option<UUID>,
pub name: String,
pub items: Vec<ChecklistItem>,
pub should_checked_items_be_hidden: bool,
}
#[derive(Serialize, Deserialize, Debug)]
pub struct Email {
pub id: ID,
#[serde(rename = "shortId")]
pub short_id: ShortId,
pub uuid: UUID,
pub email: String,
#[serde(rename = "isPrimary")]
pub is_primary: bool,
pub created_at: DateTime<Utc>,
pub updated_at: DateTime<Utc>,
pub deprecated_at: Option<DateTime<Utc>>,
#[serde(rename = "isVerified")]
pub is_verified: bool,
}
impl ZKObjectID for Email {
fn get_id(&self) -> ID {
self.id
}
fn get_uuid(&self) -> &UUID {
&self.uuid
}
}
#[derive(Serialize, Deserialize, Debug)]
pub struct Entry {
pub id: ID,
#[serde(rename = "shortId")]
pub short_id: ShortId,
pub uuid: UUID,
#[serde(rename = "listId")]
pub list_id: ID,
pub created_at: DateTime<Utc>,
pub updated_at: DateTime<Utc>,
pub deprecated_at: Option<DateTime<Utc>>,
pub created_by_displayname: Option<String>,
pub updated_by_displayname: Option<String>,
pub deprecated_by_displayname: Option<String>,
pub created_by: ID,
pub updated_by: ID,
pub deprecated_by: Option<ID>,
#[serde(rename = "displayString", default = "empty_string")]
pub display_string: String,
#[serde(rename = "sortOrder", deserialize_with = "f32_or_str")]
pub sort_order: f32, pub comment_count: u64,
pub checklists: Vec<Checklist>,
#[serde(flatten)]
pub fields: JsonMap,
}
impl ZKObjectID for Entry {
fn get_id(&self) -> ID {
self.id
}
fn get_uuid(&self) -> &UUID {
&self.uuid
}
}
impl Entry {
pub fn get_text_value(&self, field_uuid: &str) -> Result<Option<&str>, Error> {
let field_name = format!("{}_text", field_uuid);
Ok(self
.fields
.get(&field_name)
.map(|v| v.as_str())
.unwrap_or_default())
}
pub fn get_int_value(&self, field_uuid: &str) -> Result<Option<i64>, Error> {
let field_name = format!("{}_number", field_uuid);
Ok(self
.fields
.get(&field_name)
.map(|n| n.as_i64())
.unwrap_or_default())
}
pub fn get_float_value(&self, field_uuid: &str) -> Result<Option<f64>, Error> {
let field_name = format!("{}_number", field_uuid);
Ok(self
.fields
.get(&field_name)
.map(|n| n.as_f64())
.unwrap_or_default())
}
pub fn get_date_value(&self, field_uuid: &str) -> Result<Option<&str>, Error> {
let field_name = format!("{}_date", field_uuid);
Ok(self
.fields
.get(&field_name)
.map(|v| v.as_str())
.unwrap_or_default())
}
pub fn get_category_names(&self, field_uuid: &str) -> Vec<&str> {
self.map_values(field_uuid, "categories_sort", "name", |v| v.as_str())
}
pub fn get_category_ids(&self, field_uuid: &str) -> Vec<ID> {
self.map_values(field_uuid, "categories_sort", "id", |v| v.as_u64())
}
pub fn get_person_names(&self, field_uuid: &str) -> Vec<&str> {
self.map_values(field_uuid, "persons_sort", "displayname", |v| v.as_str())
}
pub fn get_person_ids(&self, field_uuid: &str) -> Vec<ID> {
self.map_values(field_uuid, "persons_sort", "id", |v| v.as_u64())
}
pub fn get_references(&self, field_uuid: &str) -> Vec<&str> {
self.map_values(field_uuid, "references_sort", "uuid", |v| v.as_str())
}
fn map_values<'v, T>(
&'v self,
field_uuid: &'_ str,
field_kind: &'_ str,
key: &'_ str,
pred: fn(&'v Value) -> Option<T>,
) -> Vec<T> {
let field_name = format!("{}_{}", field_uuid, field_kind);
self.fields
.get(&field_name)
.map(|v| v.as_array())
.unwrap_or_default()
.map(|v| {
v.iter()
.filter_map(|val| val.as_object())
.filter_map(|val| val.get(key))
.filter_map(|val| pred(val))
.collect()
})
.unwrap_or_else(Vec::new)
}
}
#[derive(Deserialize, Debug)]
#[serde(rename_all = "camelCase")]
pub struct DeleteListEntryDetail {
pub id: ID,
pub uuid: UUID,
pub short_id: ShortId,
}
impl ZKObjectID for DeleteListEntryDetail {
fn get_id(&self) -> ID {
self.id
}
fn get_uuid(&self) -> &UUID {
&self.uuid
}
}
#[derive(Deserialize, Debug)]
#[serde(rename_all = "camelCase")]
pub struct DeleteListEntryResponse {
pub action: String,
pub list_entry: DeleteListEntryDetail,
}
#[derive(Serialize, Deserialize, Debug)]
pub struct File {
pub id: ID,
#[serde(rename = "shortId")]
pub short_id: ShortId,
pub uuid: UUID,
#[serde(rename = "fileName")]
pub file_name: String,
pub size: Option<i64>,
#[serde(rename = "mimetype")]
pub mime_type: Option<String>,
#[serde(rename = "isImage")]
pub is_image: Option<bool>, #[serde(rename = "s3key")]
pub s3_key: Option<String>,
#[serde(rename = "fileUrl")]
pub file_url: Option<String>,
#[serde(rename = "cropParams")]
pub crop_params: Value,
pub created_at: DateTime<Utc>,
pub updated_at: DateTime<Utc>,
pub deprecated_at: Option<DateTime<Utc>>,
#[serde(rename = "uploaderId")]
pub uploader_id: ID,
#[serde(rename = "listId")]
pub list_id: ID,
#[serde(rename = "elementId")]
pub element_id: ID,
#[serde(rename = "cachedQuerys")]
pub cached_queries: Value, #[serde(rename = "importError")]
pub import_error: Option<String>,
pub provider: Option<String>,
pub metadata: Option<Value>,
}
impl ZKObjectID for File {
fn get_id(&self) -> ID {
self.id
}
fn get_uuid(&self) -> &UUID {
&self.uuid
}
}
#[derive(Serialize, Deserialize, Debug)]
#[serde(rename_all = "camelCase")]
pub enum FilterTermModus {
IsEmpty,
IsNotEmpty,
Contains,
NotContains,
Equals,
NotEquals,
StartsWith,
NotStartsWith,
EndsWith,
NotEndsWith,
InRange,
NotInRange,
GreaterOrEqual,
LessOrEqual,
}
#[derive(Serialize_repr, Deserialize_repr, PartialEq, Debug)]
#[repr(u8)]
pub enum DateFilterTermModus {
Any = 0,
ThisYear = 1,
ThisMonth = 2,
ThisWeek = 3,
Yesterday = 4,
Today = 5,
Tomorrow = 6,
NextWeek = 7,
NextMonth = 8,
NextYear = 9,
Custom = 10,
LastWeek = 11,
LastMonth = 12,
LastYear = 13,
Empty = 14,
NotEmpty = 15,
}
#[derive(Serialize, Deserialize, PartialEq, Debug, Clone)]
pub struct List {
pub id: ID, #[serde(rename = "shortId")]
pub short_id: ShortId,
pub uuid: UUID,
#[serde(default)]
pub name: String,
#[serde(rename = "itemName")]
pub item_name: Option<String>,
#[serde(rename = "itemNamePlural")]
pub item_name_plural: Option<String>,
#[serde(rename = "isBuilding")]
pub is_building: bool,
#[serde(rename = "isMigrating")]
pub is_migrating: bool,
#[serde(rename = "sortOrder", deserialize_with = "f32_or_str")]
pub sort_order: f32,
pub description: String,
#[serde(rename = "formulaTSortOrder")]
pub formula_tsort_order: Option<String>,
#[serde(rename = "listFilePolicy")]
pub list_file_policy: Option<String>,
#[serde(rename = "originProvider")]
pub origin_provider: Option<String>,
#[serde(rename = "originData")]
pub origin_data: Option<Value>,
#[serde(rename = "defaultViewModus")]
pub default_view_modus: i64,
pub created_at: DateTime<Utc>,
pub updated_at: DateTime<Utc>,
pub deprecated_at: Option<DateTime<Utc>>,
pub origin_created_at: Option<DateTime<Utc>>,
pub origin_updated_at: Option<DateTime<Utc>>,
pub origin_deprecated_at: Option<DateTime<Utc>>,
#[serde(rename = "workspaceId")]
pub workspace_id: ID,
#[serde(rename = "backgroundId")]
pub background_id: Option<String>,
pub visibility: i64,
#[serde(rename = "iconColor")]
pub icon_color: Option<String>, #[serde(rename = "iconBackgroundColor")]
pub icon_background_color: Option<String>, pub created_by: ID,
}
impl ZKObjectID for List {
fn get_id(&self) -> ID {
self.id
}
fn get_uuid(&self) -> &UUID {
&self.uuid
}
}
impl List {
pub fn has_id(&self, id: &str) -> bool {
self.uuid == id || self.name == id || self.short_id == id || self.id.to_string() == id
}
}
impl fmt::Display for List {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{:<7} {} {}", self.id, self.uuid, self.name)
}
}
#[derive(Serialize, Deserialize, Debug)]
pub struct ListPrototype {
pub name: String,
}
#[derive(Serialize_repr, Deserialize_repr, PartialEq, Debug)]
#[repr(u8)]
pub enum ListVisibility {
ListMembersOnly = 0,
ListMembersAndWorkspaceMembers = 1,
}
#[derive(Serialize, Deserialize, Debug)]
#[serde(rename_all = "camelCase")]
pub enum NotificationType {
PersonAdded,
ListShare,
WorkspaceShare,
Subscription,
Reminder,
Mention,
}
#[derive(Serialize, Deserialize, Debug)]
#[serde(rename_all = "camelCase")]
pub struct MinNotification {
pub id: ID,
pub short_id: ShortId,
pub uuid: UUID,
pub list_id: ID,
pub workspace_id: ID,
pub list_entry_id: ID,
pub element_id: ID,
pub activity_id: ID,
}
#[derive(Serialize, Deserialize, Debug)]
pub struct User {
pub id: ID,
#[serde(rename = "shortId")]
pub short_id: ShortId,
pub uuid: UUID,
#[serde(rename = "displayname")]
pub display_name: String,
#[serde(rename = "fullname")]
pub full_name: String,
pub initials: String,
#[serde(rename = "username")]
pub user_name: String,
#[serde(rename = "backgroundId")]
pub background_id: Option<ID>,
pub api_key: Option<String>,
#[serde(rename = "imageLink")]
pub image_link: Option<Value>,
#[serde(rename = "isImagePreferred")]
pub is_image_preferred: bool,
pub anonymous: Option<bool>,
pub locale: Option<String>,
pub timezone: Option<String>,
#[serde(rename = "isSuperAdmin")]
pub is_super_admin: Option<bool>,
pub registered_at: Option<Value>,
pub trello_token: Option<String>,
pub settings: Option<Value>,
#[serde(rename = "emailCount")]
pub email_count: u64,
}
impl ZKObjectID for User {
fn get_id(&self) -> ID {
self.id
}
fn get_uuid(&self) -> &UUID {
&self.uuid
}
}
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct Workspace {
pub id: ID,
#[serde(rename = "shortId")]
pub short_id: ShortId,
pub uuid: UUID,
pub name: String,
pub description: Option<String>,
#[serde(rename = "isDefault")]
pub is_default: bool,
pub created_at: DateTime<Utc>,
pub updated_at: DateTime<Utc>,
pub deprecated_at: Option<DateTime<Utc>>,
#[serde(rename = "backgroundId")]
pub background_id: Option<ID>,
pub created_by: ID,
pub lists: Vec<List>,
}
impl ZKObjectID for Workspace {
fn get_id(&self) -> ID {
self.id
}
fn get_uuid(&self) -> &UUID {
&self.uuid
}
}
impl Workspace {
pub fn get_description(&self) -> &str {
match &self.description {
Some(s) => s.as_str(),
None => "",
}
}
pub fn has_id(&self, id: &str) -> bool {
self.uuid == id || self.name == id || self.short_id == id || self.id.to_string() == id
}
pub fn get_id(&self) -> ID {
self.id
}
pub fn get_uuid(&self) -> &UUID {
&self.uuid
}
}
impl fmt::Display for Workspace {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{:<7} {} {}", self.id, self.uuid, self.name)
}
}
#[derive(Serialize, Deserialize, Debug)]
pub struct ResourceTag {
pub uuid: UUID,
pub tag: String,
#[serde(rename = "appType")]
pub app_type: String,
#[serde(rename = "isOwner")]
pub is_owner: bool,
pub created_by: ID,
pub created_at: DateTime<Utc>,
}
#[derive(PartialEq, Debug, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum TextFormat {
Plain,
#[allow(non_camel_case_types)]
HTML,
Markdown,
}
impl fmt::Display for TextFormat {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f,
"{}",
match self {
TextFormat::Plain => "plain",
TextFormat::HTML => "html",
TextFormat::Markdown => "markdown",
}
)
}
}
impl Default for TextFormat {
fn default() -> Self {
TextFormat::Plain
}
}
impl FromStr for TextFormat {
type Err = Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"plain" => Ok(TextFormat::Plain),
"markdown" => Ok(TextFormat::Markdown),
"html" => Ok(TextFormat::HTML),
_ => Err(Error::Other(format!(
"TextFormat parse error: '{}' not 'plain', 'html', or 'markdown'",
s
))),
}
}
}
#[derive(Serialize_repr, Deserialize_repr, PartialEq, Debug)]
#[repr(u8)]
pub enum WebhookTriggerType {
Entry = 0,
Activity = 1,
Notification = 2,
SystemMessage = 3,
Comment = 4,
Element = 5,
}
#[derive(Serialize, Deserialize, Debug)]
#[serde(rename_all = "camelCase")]
pub struct Webhook {
pub id: ID,
pub short_id: ShortId,
pub uuid: UUID,
pub trigger_type: WebhookTriggerType,
pub user_id: ID,
pub workspace_id: Option<ID>,
pub list_id: Option<ID>,
pub list_entry_id: Option<ID>,
pub url: String,
pub provider: Option<String>,
pub locale: String,
pub element_id: Option<ID>,
}
impl ZKObjectID for Webhook {
fn get_id(&self) -> ID {
self.id
}
fn get_uuid(&self) -> &UUID {
&self.uuid
}
}
#[derive(Serialize, Debug)]
#[serde(rename_all = "camelCase")]
pub struct NewWebhook {
pub trigger_type: WebhookTriggerType,
pub url: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub workspace_id: Option<ID>,
#[serde(skip_serializing_if = "Option::is_none")]
pub list_id: Option<ID>,
#[serde(skip_serializing_if = "Option::is_none")]
pub list_entry_id: Option<ID>,
#[serde(skip_serializing_if = "Option::is_none")]
pub element_id: Option<ID>,
pub locale: String,
}
#[derive(Serialize, Deserialize, Debug)]
#[serde(rename_all = "camelCase")]
pub struct OAuthClient {
pub client_name: String,
pub client_url: Option<String>,
pub redirect_uri: String,
}
#[derive(Serialize, Deserialize, Debug)]
#[serde(rename_all = "camelCase")]
pub struct OAuthResponse {
pub client_id: String,
pub client_secret: String,
}
#[derive(Serialize, Deserialize, Debug)]
#[serde(rename_all = "camelCase")]
pub struct SharedAccesses {
pub list_ids: Vec<ID>,
pub workspace_ids: Vec<ID>,
}
#[derive(Serialize, Deserialize, PartialEq, Debug, Copy, Clone)]
#[serde(rename = "lowercase")]
pub enum UpdateAction {
Replace,
Append,
Remove,
Null,
}
impl fmt::Display for UpdateAction {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"{}",
match self {
UpdateAction::Replace => "replace",
UpdateAction::Append => "append",
UpdateAction::Remove => "remove",
_ => "",
}
)
}
}
impl From<char> for UpdateAction {
fn from(c: char) -> Self {
match c {
'=' => UpdateAction::Replace,
'+' => UpdateAction::Append,
'-' => UpdateAction::Remove,
_ => UpdateAction::Null,
}
}
}
impl ElementChange {
fn from(mut v: Value) -> Result<Self, Error> {
use ElementCategoryId::{Categories, Number, Persons, References, Text};
if let Some(map) = v.as_object_mut() {
if let Some(change_val) = map.values_mut().take(1).next() {
let category_id: ElementCategoryId = match change_val
.get("elementcategoryId")
.map(|n| n.as_u64())
.unwrap_or_default()
.map(ElementCategoryId::from_u64)
.unwrap_or_default()
{
Some(cid) => cid,
None => {
return Ok(ElementChange {
category_id: None,
data: ChangedData::Other(v),
});
}
};
let change_val = change_val.take();
let data = match category_id {
Text => ChangedData::Text(serde_json::from_value(change_val)?),
Number => ChangedData::Number(serde_json::from_value(change_val)?),
Persons => ChangedData::Persons(serde_json::from_value(change_val)?),
References => ChangedData::References(serde_json::from_value(change_val)?),
Categories => ChangedData::Categories(serde_json::from_value(change_val)?),
ElementCategoryId::Date => {
ChangedData::Date(serde_json::from_value(change_val)?)
}
ElementCategoryId::URL
| ElementCategoryId::Checkbox
| ElementCategoryId::Formula
| ElementCategoryId::DateCreated
| ElementCategoryId::DateUpdated
| ElementCategoryId::DateDeprecated
| ElementCategoryId::UserCreatedBy
| ElementCategoryId::UserUpdatedBy
| ElementCategoryId::UserDeprecatedBy
| ElementCategoryId::Files
| ElementCategoryId::Hierarchy
| ElementCategoryId::SubEntries
| ElementCategoryId::Dependencies => {
return Ok(ElementChange {
category_id: None,
data: ChangedData::Other(change_val),
});
}
};
return Ok(ElementChange {
category_id: Some(category_id),
data,
});
}
}
if v.is_null() {
return Ok(ElementChange {
category_id: None,
data: ChangedData::Other(Value::Null),
});
}
Err(Error::Other(format!(
"Parse error in changed_data val={:#?}",
v
)))
}
}
impl<'de> Deserialize<'de> for ElementChange {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
let v = Value::deserialize(deserializer)?;
ElementChange::from(v).map_err(|e| {
serde::de::Error::invalid_value(
serde::de::Unexpected::Other(&e.to_string()),
&"changed_data",
)
})
}
}