use serde::{Deserialize, Serialize};
use crate::clients::RestClient;
use crate::rest::{ReadOnlyResource, ResourceError, ResourceOperation, ResourcePath, ResourceResponse, RestResource};
use crate::HttpMethod;
#[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq, Eq)]
pub struct User {
#[serde(skip_serializing)]
pub id: Option<u64>,
#[serde(skip_serializing)]
pub first_name: Option<String>,
#[serde(skip_serializing)]
pub last_name: Option<String>,
#[serde(skip_serializing)]
pub email: Option<String>,
#[serde(skip_serializing)]
pub phone: Option<String>,
#[serde(skip_serializing)]
pub url: Option<String>,
#[serde(skip_serializing)]
pub bio: Option<String>,
#[serde(skip_serializing)]
pub im: Option<String>,
#[serde(skip_serializing)]
pub screen_name: Option<String>,
#[serde(skip_serializing)]
pub locale: Option<String>,
#[serde(skip_serializing)]
pub user_type: Option<String>,
#[serde(skip_serializing)]
pub account_owner: Option<bool>,
#[serde(skip_serializing)]
pub receive_announcements: Option<i32>,
#[serde(skip_serializing)]
pub permissions: Option<Vec<String>>,
#[serde(skip_serializing)]
pub admin_graphql_api_id: Option<String>,
}
impl User {
pub async fn current(client: &RestClient) -> Result<ResourceResponse<Self>, ResourceError> {
let url = "users/current";
let response = client.get(url, None).await?;
if !response.is_ok() {
return Err(ResourceError::from_http_response(
response.code,
&response.body,
Self::NAME,
Some("current"),
response.request_id(),
));
}
let key = Self::resource_key();
ResourceResponse::from_http_response(response, &key)
}
}
impl RestResource for User {
type Id = u64;
type FindParams = UserFindParams;
type AllParams = UserListParams;
type CountParams = ();
const NAME: &'static str = "User";
const PLURAL: &'static str = "users";
const PATHS: &'static [ResourcePath] = &[
ResourcePath::new(
HttpMethod::Get,
ResourceOperation::Find,
&["id"],
"users/{id}",
),
ResourcePath::new(HttpMethod::Get, ResourceOperation::All, &[], "users"),
];
fn get_id(&self) -> Option<Self::Id> {
self.id
}
}
impl ReadOnlyResource for User {}
#[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq, Eq)]
pub struct UserFindParams {
#[serde(skip_serializing_if = "Option::is_none")]
pub fields: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq, Eq)]
pub struct UserListParams {
#[serde(skip_serializing_if = "Option::is_none")]
pub limit: Option<u32>,
#[serde(skip_serializing_if = "Option::is_none")]
pub page_info: Option<String>,
}
#[cfg(test)]
mod tests {
use super::*;
use crate::rest::{get_path, ReadOnlyResource, ResourceOperation, RestResource};
#[test]
fn test_user_implements_read_only_resource() {
fn assert_read_only<T: ReadOnlyResource>() {}
assert_read_only::<User>();
}
#[test]
fn test_user_deserialization() {
let json = r#"{
"id": 548380009,
"first_name": "John",
"last_name": "Smith",
"email": "john@example.com",
"phone": "+1-555-0100",
"url": "https://store.myshopify.com/admin/users/548380009",
"bio": "Store manager",
"im": null,
"screen_name": null,
"locale": "en",
"user_type": "regular",
"account_owner": false,
"receive_announcements": 1,
"permissions": ["full"],
"admin_graphql_api_id": "gid://shopify/StaffMember/548380009"
}"#;
let user: User = serde_json::from_str(json).unwrap();
assert_eq!(user.id, Some(548380009));
assert_eq!(user.first_name, Some("John".to_string()));
assert_eq!(user.last_name, Some("Smith".to_string()));
assert_eq!(user.email, Some("john@example.com".to_string()));
assert_eq!(user.phone, Some("+1-555-0100".to_string()));
assert_eq!(user.locale, Some("en".to_string()));
assert_eq!(user.user_type, Some("regular".to_string()));
assert_eq!(user.account_owner, Some(false));
assert_eq!(user.receive_announcements, Some(1));
assert_eq!(user.permissions, Some(vec!["full".to_string()]));
}
#[test]
fn test_user_read_only_paths() {
let find_path = get_path(User::PATHS, ResourceOperation::Find, &["id"]);
assert!(find_path.is_some());
assert_eq!(find_path.unwrap().template, "users/{id}");
let all_path = get_path(User::PATHS, ResourceOperation::All, &[]);
assert!(all_path.is_some());
assert_eq!(all_path.unwrap().template, "users");
let count_path = get_path(User::PATHS, ResourceOperation::Count, &[]);
assert!(count_path.is_none());
let create_path = get_path(User::PATHS, ResourceOperation::Create, &[]);
assert!(create_path.is_none());
let update_path = get_path(User::PATHS, ResourceOperation::Update, &["id"]);
assert!(update_path.is_none());
let delete_path = get_path(User::PATHS, ResourceOperation::Delete, &["id"]);
assert!(delete_path.is_none());
}
#[test]
fn test_user_current_method_exists() {
let _: fn(&RestClient) -> std::pin::Pin<Box<dyn std::future::Future<Output = Result<ResourceResponse<User>, ResourceError>> + Send + '_>> = |client| Box::pin(User::current(client));
}
#[test]
fn test_user_constants() {
assert_eq!(User::NAME, "User");
assert_eq!(User::PLURAL, "users");
}
#[test]
fn test_user_get_id() {
let user_with_id = User {
id: Some(548380009),
first_name: Some("John".to_string()),
..Default::default()
};
assert_eq!(user_with_id.get_id(), Some(548380009));
let user_without_id = User::default();
assert_eq!(user_without_id.get_id(), None);
}
#[test]
fn test_user_all_fields_are_read_only() {
let user = User {
id: Some(548380009),
first_name: Some("John".to_string()),
last_name: Some("Smith".to_string()),
email: Some("john@example.com".to_string()),
phone: Some("+1-555-0100".to_string()),
locale: Some("en".to_string()),
user_type: Some("regular".to_string()),
account_owner: Some(true),
receive_announcements: Some(1),
permissions: Some(vec!["full".to_string()]),
..Default::default()
};
let json = serde_json::to_value(&user).unwrap();
assert_eq!(json, serde_json::json!({}));
}
}