use std::collections::HashMap;
use std::error;
use std::fmt;
use std::sync::Arc;
use chrono::naive::NaiveDate;
use chrono::offset::Utc;
use chrono::DateTime;
use rand::distributions::Alphanumeric;
use rand::{thread_rng, Rng};
use reqwest::{header, Client, Method, Request, StatusCode, Url};
use serde::ser::SerializeMap;
use serde::{Deserialize, Serialize, Serializer};
use serde_json::value::Value;
use yup_oauth2::AccessToken;
const DIRECTORY_ENDPOINT: &str = "https://www.googleapis.com/admin/directory/v1/";
const GROUPS_SETTINGS_ENDPOINT: &str = "https://www.googleapis.com/groups/v1/groups/";
const CALENDAR_ENDPOINT: &str = "https://www.googleapis.com/calendar/v3/";
pub struct GSuite {
customer: String,
domain: String,
token: AccessToken,
client: Arc<Client>,
}
impl GSuite {
pub fn new(customer: &str, domain: &str, token: AccessToken) -> Self {
let client = Client::builder().build().expect("creating client failed");
Self {
customer: customer.to_string(),
domain: domain.to_string(),
token,
client: Arc::new(client),
}
}
pub fn get_token(&self) -> &AccessToken {
&self.token
}
fn request<B>(&self, endpoint: &str, method: Method, path: &str, body: B, query: Option<&[(&str, &str)]>) -> Request
where
B: Serialize,
{
let base = Url::parse(endpoint).unwrap();
let url = base.join(path).unwrap();
if self.token.is_expired() {
panic!("token is expired");
}
let bt = format!("Bearer {}", self.token.as_str());
let bearer = header::HeaderValue::from_str(&bt).unwrap();
let mut headers = header::HeaderMap::new();
headers.append(header::AUTHORIZATION, bearer);
headers.append(header::CONTENT_TYPE, header::HeaderValue::from_static("application/json"));
headers.append(header::ACCEPT, header::HeaderValue::from_static("application/json"));
let mut rb = self.client.request(method.clone(), url).headers(headers);
if let Some(val) = query {
rb = rb.query(&val);
}
if method != Method::GET && method != Method::DELETE {
rb = rb.json(&body);
}
rb.build().unwrap()
}
pub async fn list_groups(&self) -> Result<Vec<Group>, APIError> {
let request = self.request(DIRECTORY_ENDPOINT, Method::GET, "groups", (), Some(&[("customer", &self.customer), ("domain", &self.domain)]));
let resp = self.client.execute(request).await.unwrap();
match resp.status() {
StatusCode::OK => (),
s => {
return Err(APIError {
status_code: s,
body: resp.text().await.unwrap(),
});
}
};
let value: Groups = resp.json().await.unwrap();
Ok(value.groups)
}
pub async fn get_group_settings(&self, group_email: &str) -> Result<GroupSettings, APIError> {
let request = self.request(GROUPS_SETTINGS_ENDPOINT, Method::GET, group_email, (), Some(&[("alt", "json")]));
let resp = self.client.execute(request).await.unwrap();
match resp.status() {
StatusCode::OK => (),
s => {
return Err(APIError {
status_code: s,
body: resp.text().await.unwrap(),
});
}
};
Ok(resp.json().await.unwrap())
}
pub async fn update_group(&self, group: &Group) -> Result<(), APIError> {
let request = self.request(DIRECTORY_ENDPOINT, Method::PUT, &format!("groups/{}", group.id), group, None);
let resp = self.client.execute(request).await.unwrap();
match resp.status() {
StatusCode::OK => (),
s => {
return Err(APIError {
status_code: s,
body: resp.text().await.unwrap(),
});
}
};
Ok(())
}
pub async fn update_group_settings(&self, settings: &GroupSettings) -> Result<(), APIError> {
let request = self.request(GROUPS_SETTINGS_ENDPOINT, Method::PUT, &settings.email, settings, Some(&[("alt", "json")]));
let resp = self.client.execute(request).await.unwrap();
match resp.status() {
StatusCode::OK => (),
s => {
return Err(APIError {
status_code: s,
body: resp.text().await.unwrap(),
});
}
};
Ok(())
}
pub async fn create_group(&self, group: &Group) -> Result<Group, APIError> {
let request = self.request(DIRECTORY_ENDPOINT, Method::POST, "groups", group, None);
let resp = self.client.execute(request).await.unwrap();
match resp.status() {
StatusCode::OK => (),
s => {
return Err(APIError {
status_code: s,
body: resp.text().await.unwrap(),
});
}
};
Ok(resp.json().await.unwrap())
}
pub async fn update_group_aliases<A>(&self, group_key: &str, aliases: A)
where
A: IntoIterator,
A::Item: AsRef<str>,
{
for alias in aliases {
self.update_group_alias(group_key, alias.as_ref()).await.unwrap();
}
}
pub async fn update_group_alias(&self, group_key: &str, alias: &str) -> Result<(), APIError> {
let mut a: HashMap<&str, &str> = HashMap::new();
a.insert("alias", alias);
let request = self.request(DIRECTORY_ENDPOINT, Method::POST, &format!("groups/{}/aliases", group_key), a, None);
let resp = self.client.execute(request).await.unwrap();
match resp.status() {
StatusCode::OK => (),
s => {
let body = resp.text().await.unwrap();
if body.contains("duplicate") {
return Ok(());
}
return Err(APIError { status_code: s, body });
}
};
Ok(())
}
pub async fn group_has_member(&self, group_id: &str, email: &str) -> Result<bool, APIError> {
let request = self.request(DIRECTORY_ENDPOINT, Method::GET, &format!("groups/{}/hasMember/{}", group_id, email), (), None);
let resp = self.client.execute(request).await.unwrap();
match resp.status() {
StatusCode::OK => (),
s => {
return Err(APIError {
status_code: s,
body: resp.text().await.unwrap(),
});
}
};
let value: MembersHasMember = resp.json().await.unwrap();
Ok(value.is_member)
}
pub async fn group_update_member(&self, group_id: &str, email: &str, role: &str) -> Result<(), APIError> {
let member = Member {
role: role.to_string(),
email: email.to_string(),
delivery_settings: "ALL_MAIL".to_string(),
etag: "".to_string(),
id: "".to_string(),
kind: "".to_string(),
status: "".to_string(),
typev: "".to_string(),
};
let request = self.request(DIRECTORY_ENDPOINT, Method::PUT, &format!("groups/{}/members/{}", group_id, email), member, None);
let resp = self.client.execute(request).await.unwrap();
match resp.status() {
StatusCode::OK => (),
s => {
return Err(APIError {
status_code: s,
body: resp.text().await.unwrap(),
});
}
};
Ok(())
}
pub async fn group_insert_member(&self, group_id: &str, email: &str, role: &str) -> Result<(), APIError> {
let member = Member {
role: role.to_string(),
email: email.to_string(),
delivery_settings: "ALL_MAIL".to_string(),
etag: "".to_string(),
id: "".to_string(),
kind: "".to_string(),
status: "".to_string(),
typev: "".to_string(),
};
let request = self.request(DIRECTORY_ENDPOINT, Method::POST, &format!("groups/{}/members", group_id), member, None);
let resp = self.client.execute(request).await.unwrap();
match resp.status() {
StatusCode::OK => (),
s => {
return Err(APIError {
status_code: s,
body: resp.text().await.unwrap(),
});
}
};
Ok(())
}
pub async fn group_remove_member(&self, group_id: &str, email: &str) -> Result<(), APIError> {
let request = self.request(DIRECTORY_ENDPOINT, Method::DELETE, &format!("groups/{}/members/{}", group_id, email), (), None);
let resp = self.client.execute(request).await.unwrap();
match resp.status() {
StatusCode::OK => (),
s => {
return Err(APIError {
status_code: s,
body: resp.text().await.unwrap(),
});
}
};
Ok(())
}
pub async fn delete_group(&self, group_key: &str) -> Result<(), APIError> {
let request = self.request(DIRECTORY_ENDPOINT, Method::DELETE, &format!("groups/{}", group_key), (), None);
let resp = self.client.execute(request).await.unwrap();
match resp.status() {
StatusCode::OK => (),
s => {
return Err(APIError {
status_code: s,
body: resp.text().await.unwrap(),
});
}
};
Ok(())
}
pub async fn list_users(&self) -> Result<Vec<User>, APIError> {
let request = self.request(
DIRECTORY_ENDPOINT,
Method::GET,
"users",
(),
Some(&[("customer", &self.customer), ("domain", &self.domain), ("projection", "full")]),
);
let resp = self.client.execute(request).await.unwrap();
match resp.status() {
StatusCode::OK => (),
s => {
return Err(APIError {
status_code: s,
body: resp.text().await.unwrap(),
});
}
};
let value: Users = resp.json().await.unwrap();
Ok(value.users)
}
pub async fn update_user(&self, user: &User) -> Result<(), APIError> {
let request = self.request(DIRECTORY_ENDPOINT, Method::PUT, &format!("users/{}", user.id), user, None);
let resp = self.client.execute(request).await.unwrap();
match resp.status() {
StatusCode::OK => (),
s => {
return Err(APIError {
status_code: s,
body: resp.text().await.unwrap(),
});
}
};
Ok(())
}
pub async fn create_user(&self, user: &User) -> Result<User, APIError> {
let request = self.request(DIRECTORY_ENDPOINT, Method::POST, "users", user, None);
let resp = self.client.execute(request).await.unwrap();
match resp.status() {
StatusCode::OK => (),
s => {
return Err(APIError {
status_code: s,
body: resp.text().await.unwrap(),
});
}
};
Ok(resp.json().await.unwrap())
}
pub async fn delete_user(&self, user_key: &str) -> Result<(), APIError> {
let request = self.request(DIRECTORY_ENDPOINT, Method::DELETE, &format!("users/{}", user_key), (), None);
let resp = self.client.execute(request).await.unwrap();
match resp.status() {
StatusCode::OK => (),
s => {
return Err(APIError {
status_code: s,
body: resp.text().await.unwrap(),
});
}
};
Ok(())
}
pub async fn update_user_aliases<A>(&self, user_id: &str, aliases: A)
where
A: IntoIterator,
A::Item: AsRef<str>,
{
for alias in aliases {
self.update_user_alias(user_id, alias.as_ref()).await.unwrap();
}
}
pub async fn update_user_alias(&self, user_id: &str, alias: &str) -> Result<(), APIError> {
let mut a: HashMap<&str, &str> = HashMap::new();
a.insert("alias", alias);
let request = self.request(DIRECTORY_ENDPOINT, Method::POST, &format!("users/{}/aliases", user_id), a, None);
let resp = self.client.execute(request).await.unwrap();
match resp.status() {
StatusCode::OK => (),
StatusCode::NOT_FOUND => {
println!("Got 404 while updating user alias for user {} alias {}, trying again", user_id, alias);
}
s => {
let body = resp.text().await.unwrap();
if body.contains("duplicate") {
return Ok(());
}
return Err(APIError { status_code: s, body });
}
};
Ok(())
}
pub async fn list_calendar_resources(&self) -> Result<Vec<CalendarResource>, APIError> {
let request = self.request(DIRECTORY_ENDPOINT, Method::GET, &format!("customer/{}/resources/calendars", self.customer), (), None);
let resp = self.client.execute(request).await.unwrap();
match resp.status() {
StatusCode::OK => (),
s => {
return Err(APIError {
status_code: s,
body: resp.text().await.unwrap(),
});
}
};
let value: CalendarResources = resp.json().await.unwrap();
Ok(value.items)
}
pub async fn update_calendar_resource(&self, resource: &CalendarResource) -> Result<(), APIError> {
let request = self.request(
DIRECTORY_ENDPOINT,
Method::PUT,
&format!("customer/{}/resources/calendars/{}", self.customer, resource.id),
resource,
None,
);
let resp = self.client.execute(request).await.unwrap();
match resp.status() {
StatusCode::OK => (),
s => {
return Err(APIError {
status_code: s,
body: resp.text().await.unwrap(),
});
}
};
Ok(())
}
pub async fn create_calendar_resource(&self, resource: &CalendarResource) -> Result<(), APIError> {
let request = self.request(DIRECTORY_ENDPOINT, Method::POST, &format!("customer/{}/resources/calendars", self.customer), resource, None);
let resp = self.client.execute(request).await.unwrap();
match resp.status() {
StatusCode::OK => (),
s => {
return Err(APIError {
status_code: s,
body: resp.text().await.unwrap(),
});
}
};
Ok(())
}
pub async fn delete_calendar_resource(&self, id: &str) -> Result<(), APIError> {
let request = self.request(DIRECTORY_ENDPOINT, Method::DELETE, &format!("customer/{}/resources/calendars/{}", self.customer, id), (), None);
let resp = self.client.execute(request).await.unwrap();
match resp.status() {
StatusCode::OK => (),
StatusCode::NO_CONTENT => (),
s => {
return Err(APIError {
status_code: s,
body: resp.text().await.unwrap(),
});
}
};
Ok(())
}
pub async fn list_buildings(&self) -> Result<Vec<Building>, APIError> {
let request = self.request(DIRECTORY_ENDPOINT, Method::GET, &format!("customer/{}/resources/buildings", self.customer), (), None);
let resp = self.client.execute(request).await.unwrap();
match resp.status() {
StatusCode::OK => (),
s => {
return Err(APIError {
status_code: s,
body: resp.text().await.unwrap(),
});
}
};
let value: Buildings = resp.json().await.unwrap();
Ok(value.buildings)
}
pub async fn update_building(&self, building: &Building) -> Result<(), APIError> {
let request = self.request(
DIRECTORY_ENDPOINT,
Method::PUT,
&format!("customer/{}/resources/buildings/{}", self.customer, building.id),
building,
None,
);
let resp = self.client.execute(request).await.unwrap();
match resp.status() {
StatusCode::OK => (),
s => {
return Err(APIError {
status_code: s,
body: resp.text().await.unwrap(),
});
}
};
Ok(())
}
pub async fn create_building(&self, building: &Building) -> Result<(), APIError> {
let request = self.request(DIRECTORY_ENDPOINT, Method::POST, &format!("customer/{}/resources/buildings", self.customer), building, None);
let resp = self.client.execute(request).await.unwrap();
match resp.status() {
StatusCode::OK => (),
s => {
return Err(APIError {
status_code: s,
body: resp.text().await.unwrap(),
});
}
};
Ok(())
}
pub async fn delete_building(&self, id: &str) -> Result<(), APIError> {
let request = self.request(DIRECTORY_ENDPOINT, Method::DELETE, &format!("customer/{}/resources/buildings/{}", self.customer, id), (), None);
let resp = self.client.execute(request).await.unwrap();
match resp.status() {
StatusCode::OK => (),
StatusCode::NO_CONTENT => (),
s => {
return Err(APIError {
status_code: s,
body: resp.text().await.unwrap(),
});
}
};
Ok(())
}
pub async fn list_calendars(&self) -> Result<Vec<Calendar>, APIError> {
let request = self.request(CALENDAR_ENDPOINT, Method::GET, "users/me/calendarList", (), None);
let resp = self.client.execute(request).await.unwrap();
match resp.status() {
StatusCode::OK => (),
s => {
return Err(APIError {
status_code: s,
body: resp.text().await.unwrap(),
});
}
};
let value: Calendars = resp.json().await.unwrap();
Ok(value.items)
}
pub async fn list_calendar_events(&self, calendar_id: &str, show_deleted: bool) -> Result<Vec<CalendarEvent>, APIError> {
let request = self.request(
CALENDAR_ENDPOINT,
Method::GET,
&format!("calendars/{}/events", calendar_id),
(),
Some(&[("singleEvents", "true"), ("maxResults", "2500"), ("showDeleted", &show_deleted.to_string())]),
);
let resp = self.client.execute(request).await.unwrap();
match resp.status() {
StatusCode::OK => (),
s => {
return Err(APIError {
status_code: s,
body: resp.text().await.unwrap(),
});
}
};
let value: CalendarEvents = resp.json().await.unwrap();
Ok(value.items)
}
pub async fn list_past_calendar_events(&self, calendar_id: &str) -> Result<Vec<CalendarEvent>, APIError> {
let request = self.request(
CALENDAR_ENDPOINT,
Method::GET,
&format!("calendars/{}/events", calendar_id),
(),
Some(&[("singleEvents", "true"), ("maxResults", "2500"), ("timeMax", &Utc::now().to_rfc3339())]),
);
let resp = self.client.execute(request).await.unwrap();
match resp.status() {
StatusCode::OK => (),
s => {
return Err(APIError {
status_code: s,
body: resp.text().await.unwrap(),
});
}
};
let value: CalendarEvents = resp.json().await.unwrap();
Ok(value.items)
}
pub async fn create_calendar_event(&self, calendar_id: &str, event: &CalendarEvent) -> Result<CalendarEvent, APIError> {
let request = self.request(CALENDAR_ENDPOINT, Method::POST, &format!("calendars/{}/events", calendar_id), event, None);
let resp = self.client.execute(request).await.unwrap();
match resp.status() {
StatusCode::OK => (),
s => {
return Err(APIError {
status_code: s,
body: resp.text().await.unwrap(),
});
}
};
Ok(resp.json().await.unwrap())
}
pub async fn update_calendar_event(&self, calendar_id: &str, event_id: &str, event: &CalendarEvent) -> Result<CalendarEvent, APIError> {
let request = self.request(CALENDAR_ENDPOINT, Method::PUT, &format!("calendars/{}/events/{}", calendar_id, event_id), event, None);
let resp = self.client.execute(request).await.unwrap();
match resp.status() {
StatusCode::OK => (),
s => {
return Err(APIError {
status_code: s,
body: resp.text().await.unwrap(),
});
}
};
Ok(resp.json().await.unwrap())
}
pub async fn get_calendar_event(&self, calendar_id: &str, event_id: &str) -> Result<CalendarEvent, APIError> {
let request = self.request(CALENDAR_ENDPOINT, Method::GET, &format!("calendars/{}/events/{}", calendar_id, event_id), (), None);
let resp = self.client.execute(request).await.unwrap();
match resp.status() {
StatusCode::OK => (),
s => {
return Err(APIError {
status_code: s,
body: resp.text().await.unwrap(),
});
}
};
Ok(resp.json().await.unwrap())
}
pub async fn delete_calendar_event(&self, calendar_id: &str, event_id: &str) -> Result<(), APIError> {
let request = self.request(CALENDAR_ENDPOINT, Method::DELETE, &format!("calendars/{}/events/{}", calendar_id, event_id), (), None);
let resp = self.client.execute(request).await.unwrap();
match resp.status() {
StatusCode::OK => (),
StatusCode::NO_CONTENT => (),
StatusCode::NOT_FOUND => (),
s => {
return Err(APIError {
status_code: s,
body: resp.text().await.unwrap(),
});
}
};
Ok(())
}
}
pub struct APIError {
pub status_code: StatusCode,
pub body: String,
}
impl fmt::Display for APIError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "APIError: status code -> {}, body -> {}", self.status_code.to_string(), self.body)
}
}
impl fmt::Debug for APIError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "APIError: status code -> {}, body -> {}", self.status_code.to_string(), self.body)
}
}
impl error::Error for APIError {
fn source(&self) -> Option<&(dyn error::Error + 'static)> {
None
}
}
pub fn generate_password() -> String {
thread_rng().sample_iter(&Alphanumeric).take(30).collect()
}
#[derive(Default, Clone, Debug, Serialize, Deserialize)]
pub struct Calendars {
#[serde(default, skip_serializing_if = "String::is_empty", rename = "nextPageToken")]
pub next_page_token: String,
#[serde(default, skip_serializing_if = "String::is_empty", rename = "nextSyncToken")]
pub next_sync_token: String,
#[serde(default, skip_serializing_if = "String::is_empty")]
pub kind: String,
#[serde(default, skip_serializing_if = "String::is_empty")]
pub etag: String,
#[serde(default, skip_serializing_if = "String::is_empty")]
pub trigger_event: String,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub items: Vec<Calendar>,
}
#[derive(Default, Clone, Debug, Serialize, Deserialize)]
pub struct Calendar {
#[serde(default, skip_serializing_if = "String::is_empty")]
pub kind: String,
#[serde(default, skip_serializing_if = "String::is_empty")]
pub etag: String,
#[serde(default, skip_serializing_if = "String::is_empty")]
pub id: String,
#[serde(default, skip_serializing_if = "String::is_empty")]
pub summary: String,
#[serde(default, skip_serializing_if = "String::is_empty")]
pub description: String,
#[serde(default, skip_serializing_if = "String::is_empty")]
pub location: String,
#[serde(default, skip_serializing_if = "String::is_empty", rename = "timeZone")]
pub time_zone: String,
}
#[derive(Default, Clone, Debug, Serialize, Deserialize)]
pub struct CalendarEvents {
#[serde(default, skip_serializing_if = "String::is_empty", rename = "nextPageToken")]
pub next_page_token: String,
#[serde(default, skip_serializing_if = "String::is_empty", rename = "nextSyncToken")]
pub next_sync_token: String,
#[serde(default, skip_serializing_if = "String::is_empty")]
pub kind: String,
#[serde(default, skip_serializing_if = "String::is_empty")]
pub etag: String,
#[serde(default, skip_serializing_if = "String::is_empty")]
pub trigger_event: String,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub items: Vec<CalendarEvent>,
}
#[derive(Clone, Debug, Default, Serialize, Deserialize)]
pub struct CalendarEvent {
#[serde(default, skip_serializing_if = "String::is_empty")]
pub kind: String,
#[serde(default, skip_serializing_if = "String::is_empty")]
pub etag: String,
#[serde(default, skip_serializing_if = "String::is_empty")]
pub id: String,
#[serde(default, skip_serializing_if = "String::is_empty")]
pub status: String,
#[serde(default, skip_serializing_if = "String::is_empty", rename = "htmlLink")]
pub html_link: String,
pub created: Option<DateTime<Utc>>,
pub updated: Option<DateTime<Utc>>,
#[serde(default, skip_serializing_if = "String::is_empty")]
pub summary: String,
#[serde(default, skip_serializing_if = "String::is_empty")]
pub description: String,
#[serde(default, skip_serializing_if = "String::is_empty")]
pub location: String,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub recurrence: Vec<String>,
#[serde(default, skip_serializing_if = "String::is_empty", rename = "recurringEventId")]
pub recurring_event_id: String,
#[serde(default, skip_serializing_if = "String::is_empty")]
pub transparency: String,
#[serde(default, skip_serializing_if = "String::is_empty")]
pub visibility: String,
#[serde(default)]
pub sequence: i64,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub attendees: Vec<Attendee>,
pub start: Date,
pub end: Date,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub attachments: Vec<Attachment>,
}
#[derive(Default, Clone, Debug, Serialize, Deserialize)]
pub struct Date {
#[serde(default, skip_serializing_if = "String::is_empty", rename = "timeZone")]
pub time_zone: String,
#[serde(default)]
pub date: Option<NaiveDate>,
#[serde(default, rename = "dateTime")]
pub date_time: Option<DateTime<Utc>>,
}
#[derive(Default, Clone, Debug, Serialize, Deserialize)]
pub struct Attendee {
#[serde(default, skip_serializing_if = "String::is_empty")]
pub id: String,
#[serde(default, skip_serializing_if = "String::is_empty")]
pub email: String,
#[serde(default, skip_serializing_if = "String::is_empty", rename = "displayName")]
pub display_name: String,
#[serde(default)]
pub organizer: bool,
#[serde(default)]
pub resource: bool,
#[serde(default)]
pub optional: bool,
#[serde(default, skip_serializing_if = "String::is_empty", rename = "responseStatus")]
pub response_status: String,
#[serde(default, skip_serializing_if = "String::is_empty")]
pub comment: String,
#[serde(default, rename = "additionalGuests")]
pub additional_guests: i64,
}
#[derive(Default, Clone, Debug, Serialize, Deserialize)]
pub struct Attachment {
#[serde(default, skip_serializing_if = "String::is_empty", rename = "fileUrl")]
pub file_url: String,
#[serde(default, skip_serializing_if = "String::is_empty")]
pub title: String,
#[serde(default, skip_serializing_if = "String::is_empty", rename = "mimeType")]
pub mime_type: String,
#[serde(default, skip_serializing_if = "String::is_empty", rename = "iconLink")]
pub icon_link: String,
#[serde(default, skip_serializing_if = "String::is_empty", rename = "fileId")]
pub file_id: String,
}
#[derive(Default, Clone, Debug, Serialize, Deserialize)]
pub struct Group {
#[serde(skip_serializing_if = "Option::is_none", rename = "adminCreated")]
pub admin_created: Option<bool>,
#[serde(skip_serializing_if = "Vec::is_empty", default)]
pub aliases: Vec<String>,
#[serde(default, skip_serializing_if = "String::is_empty")]
pub description: String,
#[serde(default, skip_serializing_if = "String::is_empty", rename = "directMembersCount")]
pub direct_members_count: String,
#[serde(default, skip_serializing_if = "String::is_empty")]
pub email: String,
#[serde(default, skip_serializing_if = "String::is_empty")]
pub etag: String,
#[serde(default, skip_serializing_if = "String::is_empty")]
pub id: String,
#[serde(default, skip_serializing_if = "String::is_empty")]
pub kind: String,
#[serde(default, skip_serializing_if = "String::is_empty")]
pub name: String,
#[serde(default, skip_serializing_if = "Vec::is_empty", rename = "nonEditableAliases")]
pub non_editable_aliases: Vec<String>,
}
#[derive(Default, Clone, Debug, Serialize, Deserialize)]
pub struct GroupSettings {
#[serde(default, skip_serializing_if = "String::is_empty", rename = "whoCanBanUsers")]
pub who_can_ban_users: String,
#[serde(default, skip_serializing_if = "String::is_empty", rename = "whoCanAssistContent")]
pub who_can_assist_content: String,
#[serde(default, skip_serializing_if = "String::is_empty", rename = "allowExternalMembers")]
pub allow_external_members: String,
#[serde(default, skip_serializing_if = "String::is_empty", rename = "whoCanEnterFreeFormTags")]
pub who_can_enter_free_form_tags: String,
#[serde(default, skip_serializing_if = "String::is_empty", rename = "whoCanApproveMessages")]
pub who_can_approve_messages: String,
#[serde(default, skip_serializing_if = "String::is_empty", rename = "whoCanMarkDuplicate")]
pub who_can_mark_duplicate: String,
#[serde(default, skip_serializing_if = "String::is_empty", rename = "whoCanJoin")]
pub who_can_join: String,
#[serde(default, skip_serializing_if = "String::is_empty", rename = "whoCanModifyTagsAndCategories")]
pub who_can_modify_tags_and_categories: String,
#[serde(default, skip_serializing_if = "String::is_empty", rename = "whoCanMarkNoResponseNeeded")]
pub who_can_mark_no_response_needed: String,
#[serde(default, skip_serializing_if = "String::is_empty", rename = "whoCanUnmarkFavoriteReplyOnAnyTopic")]
pub who_can_unmark_favorite_reply_on_any_topic: String,
#[serde(default, skip_serializing_if = "String::is_empty", rename = "whoCanModerateContent")]
pub who_can_moderate_content: String,
#[serde(default, skip_serializing_if = "String::is_empty", rename = "primaryLanguage")]
pub primary_language: String,
#[serde(default, skip_serializing_if = "String::is_empty", rename = "whoCanMarkFavoriteReplyOnOwnTopic")]
pub who_can_mark_favorite_reply_on_own_topic: String,
#[serde(default, skip_serializing_if = "String::is_empty", rename = "whoCanViewMembership")]
pub who_can_view_membership: String,
#[serde(default, skip_serializing_if = "String::is_empty", rename = "favoriteRepliesOnTop")]
pub favorite_replies_on_top: String,
#[serde(default, skip_serializing_if = "String::is_empty", rename = "whoCanMarkFavoriteReplyOnAnyTopic")]
pub who_can_mark_favorite_reply_on_any_topic: String,
#[serde(default, skip_serializing_if = "String::is_empty", rename = "includeCustomFooter")]
pub include_custom_footer: String,
#[serde(default, skip_serializing_if = "String::is_empty", rename = "whoCanMoveTopicsOut")]
pub who_can_move_topics_out: String,
#[serde(default, skip_serializing_if = "String::is_empty", rename = "defaultMessageDenyNotificationText")]
pub default_message_deny_notification_text: String,
#[serde(default, rename = "includeInGlobalAddressList", skip_serializing_if = "String::is_empty")]
pub include_in_global_address_list: String,
#[serde(default, skip_serializing_if = "String::is_empty", rename = "archiveOnly")]
pub archive_only: String,
#[serde(default, skip_serializing_if = "String::is_empty", rename = "whoCanDeleteTopics")]
pub who_can_delete_topics: String,
#[serde(default, skip_serializing_if = "String::is_empty", rename = "whoCanDeleteAnyPost")]
pub who_can_delete_any_post: String,
#[serde(default, skip_serializing_if = "String::is_empty", rename = "isArchived")]
pub is_archived: String,
#[serde(default, skip_serializing_if = "String::is_empty", rename = "membersCanPostAsTheGroup")]
pub members_can_post_as_the_group: String,
#[serde(default, skip_serializing_if = "String::is_empty", rename = "whoCanMakeTopicsSticky")]
pub who_can_make_topics_sticky: String,
#[serde(default, skip_serializing_if = "String::is_empty", rename = "customRolesEnabledForSettingsToBeMerged")]
pub custom_roles_enabled_for_settings_to_be_merged: String,
pub email: String,
#[serde(default, skip_serializing_if = "String::is_empty", rename = "whoCanDiscoverGroup")]
pub who_can_discover_group: String,
#[serde(default, skip_serializing_if = "String::is_empty", rename = "whoCanModifyMembers")]
pub who_can_modify_members: String,
#[serde(default, skip_serializing_if = "String::is_empty", rename = "messageModerationLevel")]
pub message_moderation_level: String,
#[serde(default, skip_serializing_if = "String::is_empty")]
pub description: String,
#[serde(default, skip_serializing_if = "String::is_empty", rename = "whoCanUnassignTopic")]
pub who_can_unassign_topic: String,
#[serde(default, skip_serializing_if = "String::is_empty", rename = "replyTo")]
pub reply_to: String,
#[serde(default, skip_serializing_if = "String::is_empty", rename = "customReplyTo")]
pub custom_reply_to: String,
#[serde(default, skip_serializing_if = "String::is_empty", rename = "sendMessageDenyNotification")]
pub send_message_deny_notification: String,
#[serde(default, skip_serializing_if = "String::is_empty", rename = "enableCollaborativeInbox")]
pub enable_collaborative_inbox: String,
#[serde(default, skip_serializing_if = "String::is_empty", rename = "whoCanContactOwner")]
pub who_can_contact_owner: String,
#[serde(default, skip_serializing_if = "String::is_empty", rename = "messageDisplayFont")]
pub message_display_font: String,
#[serde(default, skip_serializing_if = "String::is_empty", rename = "whoCanLeaveGroup")]
pub who_can_leave_group: String,
#[serde(default, skip_serializing_if = "String::is_empty", rename = "whoCanAdd")]
pub who_can_add: String,
#[serde(default, skip_serializing_if = "String::is_empty", rename = "whoCanPostMessage")]
pub who_can_post_message: String,
#[serde(default, skip_serializing_if = "String::is_empty", rename = "whoCanMoveTopicsIn")]
pub who_can_move_topics_in: String,
#[serde(default, skip_serializing_if = "String::is_empty", rename = "whoCanTakeTopics")]
pub who_can_take_topics: String,
#[serde(default, skip_serializing_if = "String::is_empty")]
pub name: String,
#[serde(default, skip_serializing_if = "String::is_empty")]
pub kind: String,
#[serde(default, skip_serializing_if = "Option::is_none", rename = "maxMessageBytes")]
pub max_message_bytes: Option<i32>,
#[serde(default, skip_serializing_if = "String::is_empty", rename = "whoCanInvite")]
pub who_can_invite: String,
#[serde(default, skip_serializing_if = "String::is_empty", rename = "whoCanApproveMembers")]
pub who_can_approve_members: String,
#[serde(default, skip_serializing_if = "String::is_empty", rename = "spamModerationLevel")]
pub spam_moderation_level: String,
#[serde(default, skip_serializing_if = "String::is_empty", rename = "allowWebPosting")]
pub allow_web_posting: String,
#[serde(default, skip_serializing_if = "String::is_empty", rename = "whoCanModerateMembers")]
pub who_can_moderate_members: String,
#[serde(default, skip_serializing_if = "String::is_empty", rename = "whoCanAddReferences")]
pub who_can_add_references: String,
#[serde(default, skip_serializing_if = "String::is_empty", rename = "whoCanViewGroup")]
pub who_can_view_group: String,
#[serde(default, skip_serializing_if = "String::is_empty", rename = "showInGroupGSuite")]
pub show_in_group_directory: String,
#[serde(default, skip_serializing_if = "String::is_empty", rename = "whoCanPostAnnouncements")]
pub who_can_post_announcements: String,
#[serde(default, skip_serializing_if = "String::is_empty", rename = "whoCanLockTopics")]
pub who_can_lock_topics: String,
#[serde(default, skip_serializing_if = "String::is_empty", rename = "whoCanAssignTopics")]
pub who_can_assign_topics: String,
#[serde(default, skip_serializing_if = "String::is_empty", rename = "customFooterText")]
pub custom_footer_text: String,
#[serde(default, skip_serializing_if = "String::is_empty", rename = "allowGoogleCommunication")]
pub allow_google_communication: String,
#[serde(default, skip_serializing_if = "String::is_empty", rename = "whoCanHideAbuse")]
pub who_can_hide_abuse: String,
}
#[derive(Default, Clone, Debug, Serialize, Deserialize)]
struct Groups {
#[serde(default, skip_serializing_if = "String::is_empty", rename = "nextPageToken")]
pub next_page_token: String,
#[serde(default, skip_serializing_if = "String::is_empty")]
pub kind: String,
#[serde(default, skip_serializing_if = "String::is_empty")]
pub etag: String,
#[serde(default, skip_serializing_if = "String::is_empty")]
pub trigger_event: String,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub groups: Vec<Group>,
}
#[derive(Default, Clone, Debug, Serialize, Deserialize)]
struct MembersHasMember {
#[serde(default, rename = "isMember")]
pub is_member: bool,
}
#[derive(Default, Clone, Debug, Serialize, Deserialize)]
struct Members {
#[serde(default, skip_serializing_if = "String::is_empty", rename = "nextPageToken")]
pub next_page_token: String,
#[serde(default, skip_serializing_if = "String::is_empty")]
pub kind: String,
#[serde(default, skip_serializing_if = "String::is_empty")]
pub etag: String,
#[serde(default, skip_serializing_if = "String::is_empty")]
pub trigger_event: String,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub members: Vec<Member>,
}
#[derive(Default, Clone, Debug, Serialize, Deserialize)]
struct Member {
#[serde(default, skip_serializing_if = "String::is_empty")]
pub status: String,
#[serde(default, skip_serializing_if = "String::is_empty")]
pub kind: String,
#[serde(default, skip_serializing_if = "String::is_empty")]
pub delivery_settings: String,
#[serde(default, skip_serializing_if = "String::is_empty")]
pub email: String,
#[serde(default, skip_serializing_if = "String::is_empty")]
pub etag: String,
#[serde(default, skip_serializing_if = "String::is_empty")]
pub role: String,
#[serde(default, skip_serializing_if = "String::is_empty", rename = "type")]
pub typev: String,
#[serde(default, skip_serializing_if = "String::is_empty")]
pub id: String,
}
#[derive(Default, Clone, Debug, Serialize, Deserialize)]
pub struct User {
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub addresses: Vec<UserAddress>,
#[serde(skip_serializing_if = "Option::is_none", rename = "agreedToTerms")]
pub agreed_to_terms: Option<bool>,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub aliases: Vec<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub archived: Option<bool>,
#[serde(default, rename = "changePasswordAtNextLogin")]
pub change_password_at_next_login: bool,
#[serde(skip_serializing_if = "Option::is_none", rename = "creationTime")]
pub creation_time: Option<DateTime<Utc>>,
#[serde(default, skip_serializing_if = "HashMap::is_empty", rename = "customSchemas")]
pub custom_schemas: HashMap<String, UserCustomProperties>,
#[serde(default, skip_serializing_if = "String::is_empty", rename = "customerId")]
pub customer_id: String,
#[serde(skip_serializing_if = "Option::is_none", rename = "deletionTime")]
pub deletion_time: Option<DateTime<Utc>>,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub emails: Vec<UserEmail>,
#[serde(default, skip_serializing_if = "String::is_empty")]
pub etag: String,
#[serde(default, skip_serializing_if = "Vec::is_empty", rename = "externalIds")]
pub external_ids: Vec<UserExternalId>,
#[serde(skip_serializing_if = "Option::is_none")]
pub gender: Option<UserGender>,
#[serde(default, skip_serializing_if = "String::is_empty", rename = "hashFunction")]
pub hash_function: String,
#[serde(default, skip_serializing_if = "String::is_empty")]
pub id: String,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub ims: Vec<UserInstantMessenger>,
#[serde(default, rename = "includeInGlobalAddressList")]
pub include_in_global_address_list: bool,
#[serde(default, rename = "ipWhitelisted")]
pub ip_whitelisted: bool,
#[serde(skip_serializing_if = "Option::is_none", rename = "isAdmin")]
pub is_admin: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none", rename = "isDelegatedAdmin")]
pub is_delegated_admin: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none", rename = "isEnforcedIn2Sv")]
pub is_enforced_in2_sv: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none", rename = "isEnrolledIn2Sv")]
pub is_enrolled_in2_sv: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none", rename = "isMailboxSetup")]
pub is_mailbox_setup: Option<bool>,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub keywords: Vec<UserKeyword>,
#[serde(default, skip_serializing_if = "String::is_empty")]
pub kind: String,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub languages: Vec<UserLanguage>,
#[serde(skip_serializing_if = "Option::is_none", rename = "lastLoginTime")]
pub last_login_time: Option<DateTime<Utc>>,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub locations: Vec<UserLocation>,
pub name: UserName,
#[serde(default, skip_serializing_if = "Vec::is_empty", rename = "nonEditableAliases")]
pub non_editable_aliases: Vec<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub notes: Option<UserNotes>,
#[serde(default, skip_serializing_if = "String::is_empty", rename = "orgUnitPath")]
pub org_unit_path: String,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub organizations: Vec<Organization>,
#[serde(default, skip_serializing_if = "String::is_empty")]
pub password: String,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub phones: Vec<UserPhone>,
#[serde(default, skip_serializing_if = "Vec::is_empty", rename = "posixAccounts")]
pub posix_accounts: Vec<UserPosixAccount>,
#[serde(default, skip_serializing_if = "String::is_empty", rename = "primaryEmail")]
pub primary_email: String,
#[serde(default, skip_serializing_if = "String::is_empty", rename = "recoveryEmail")]
pub recovery_email: String,
#[serde(default, skip_serializing_if = "String::is_empty", rename = "recoveryPhone")]
pub recovery_phone: String,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub relations: Vec<UserRelation>,
#[serde(default, skip_serializing_if = "Vec::is_empty", rename = "sshPublicKeys")]
pub ssh_public_keys: Vec<UserSSHKey>,
#[serde(default)]
pub suspended: bool,
#[serde(default, skip_serializing_if = "String::is_empty", rename = "suspensionReason")]
pub suspension_reason: String,
#[serde(default, skip_serializing_if = "String::is_empty", rename = "thumbnailPhotoEtag")]
pub thumbnail_photo_etag: String,
#[serde(default, skip_serializing_if = "String::is_empty", rename = "thumbnailPhotoUrl")]
pub thumbnail_photo_url: String,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub websites: Vec<UserWebsite>,
}
#[derive(Default, Clone, Debug, Serialize, Deserialize)]
pub struct UserAddress {
#[serde(default, skip_serializing_if = "String::is_empty")]
pub country: String,
#[serde(default, skip_serializing_if = "String::is_empty", rename = "countryCode")]
pub country_code: String,
#[serde(default, skip_serializing_if = "String::is_empty", rename = "customType")]
pub custom_type: String,
#[serde(default, skip_serializing_if = "String::is_empty", rename = "extendedAddress")]
pub extended_address: String,
#[serde(default, skip_serializing_if = "String::is_empty")]
pub formatted: String,
#[serde(default, skip_serializing_if = "String::is_empty")]
pub locality: String,
#[serde(default, skip_serializing_if = "String::is_empty", rename = "poBox")]
pub po_box: String,
#[serde(default, rename = "postalCode", skip_serializing_if = "String::is_empty")]
pub postal_code: String,
#[serde(default)]
pub primary: bool,
#[serde(default, skip_serializing_if = "String::is_empty")]
pub region: String,
#[serde(default, rename = "sourceIsStructured")]
pub source_is_structured: bool,
#[serde(default, rename = "street_address", skip_serializing_if = "String::is_empty")]
pub street_address: String,
#[serde(default, skip_serializing_if = "String::is_empty", rename = "type")]
pub typev: String,
}
#[derive(Default, Clone, Debug, Serialize, Deserialize)]
pub struct UserEmail {
#[serde(default, skip_serializing_if = "String::is_empty")]
pub address: String,
#[serde(default, skip_serializing_if = "String::is_empty", rename = "customType")]
pub custom_type: String,
#[serde(default)]
pub primary: bool,
#[serde(default, skip_serializing_if = "String::is_empty", rename = "type")]
pub typev: String,
}
#[derive(Default, Clone, Debug, Serialize, Deserialize)]
pub struct UserExternalId {
#[serde(default, skip_serializing_if = "String::is_empty", rename = "customType")]
pub custom_type: String,
#[serde(default, skip_serializing_if = "String::is_empty", rename = "type")]
pub typev: String,
#[serde(default, skip_serializing_if = "String::is_empty")]
pub value: String,
}
#[derive(Default, Clone, Debug, Serialize, Deserialize)]
pub struct UserGender {
#[serde(default, rename = "addressMeAs", skip_serializing_if = "String::is_empty")]
pub address_me_as: String,
#[serde(default, rename = "customGender", skip_serializing_if = "String::is_empty")]
pub custom_gender: String,
#[serde(default, rename = "type", skip_serializing_if = "String::is_empty")]
pub typev: String,
}
#[derive(Default, Clone, Debug, Serialize, Deserialize)]
pub struct UserInstantMessenger {
#[serde(default, skip_serializing_if = "String::is_empty", rename = "customProtocol")]
pub custom_protocol: String,
#[serde(default, skip_serializing_if = "String::is_empty", rename = "customType")]
pub custom_type: String,
#[serde(default, skip_serializing_if = "String::is_empty")]
pub im: String,
#[serde(default)]
pub primary: bool,
#[serde(default, skip_serializing_if = "String::is_empty")]
pub protocol: String,
#[serde(default, skip_serializing_if = "String::is_empty", rename = "type")]
pub typev: String,
}
#[derive(Default, Clone, Debug, Serialize, Deserialize)]
pub struct UserKeyword {
#[serde(default, skip_serializing_if = "String::is_empty", rename = "customType")]
pub custom_type: String,
#[serde(default, skip_serializing_if = "String::is_empty", rename = "type")]
pub typev: String,
#[serde(default, skip_serializing_if = "String::is_empty")]
pub value: String,
}
#[derive(Default, Clone, Debug, Serialize, Deserialize)]
pub struct UserLanguage {
#[serde(default, skip_serializing_if = "String::is_empty", rename = "customLanguage")]
pub custom_language: String,
#[serde(default, skip_serializing_if = "String::is_empty", rename = "languageCode")]
pub language_code: String,
}
#[derive(Default, Clone, Debug, Serialize, Deserialize)]
pub struct UserLocation {
#[serde(default)]
pub area: String,
#[serde(default, skip_serializing_if = "String::is_empty", rename = "buildingId")]
pub building_id: String,
#[serde(default, skip_serializing_if = "String::is_empty", rename = "customType")]
pub custom_type: String,
#[serde(default, skip_serializing_if = "String::is_empty", rename = "deskCode")]
pub desk_code: String,
#[serde(default, skip_serializing_if = "String::is_empty", rename = "floorName")]
pub floor_name: String,
#[serde(default, skip_serializing_if = "String::is_empty", rename = "floorSection")]
pub floor_section: String,
#[serde(default, skip_serializing_if = "String::is_empty", rename = "type")]
pub typev: String,
}
#[derive(Default, Clone, Debug, Serialize, Deserialize)]
pub struct UserName {
#[serde(default, skip_serializing_if = "String::is_empty", rename = "familyName")]
pub family_name: String,
#[serde(default, skip_serializing_if = "String::is_empty", rename = "fullName")]
pub full_name: String,
#[serde(default, skip_serializing_if = "String::is_empty", rename = "givenName")]
pub given_name: String,
}
#[derive(Default, Clone, Debug, Serialize, Deserialize)]
pub struct UserNotes {
#[serde(default, rename = "contentType", skip_serializing_if = "String::is_empty")]
pub content_type: String,
#[serde(default, skip_serializing_if = "String::is_empty")]
pub value: String,
}
#[derive(Default, Clone, Debug, Serialize, Deserialize)]
pub struct Organization {
#[serde(default, skip_serializing_if = "String::is_empty", rename = "costCenter")]
pub cost_center: String,
#[serde(default, skip_serializing_if = "String::is_empty", rename = "customType")]
pub custom_type: String,
#[serde(default, skip_serializing_if = "String::is_empty")]
pub department: String,
#[serde(default, skip_serializing_if = "String::is_empty")]
pub description: String,
#[serde(default, skip_serializing_if = "String::is_empty")]
pub domain: String,
#[serde(default, rename = "fullTimeEquivalent")]
pub full_time_equivalent: u64,
#[serde(default, skip_serializing_if = "String::is_empty")]
pub location: String,
#[serde(default, skip_serializing_if = "String::is_empty")]
pub name: String,
#[serde(default)]
pub primary: bool,
#[serde(default, skip_serializing_if = "String::is_empty")]
pub symbol: String,
#[serde(default, skip_serializing_if = "String::is_empty")]
pub title: String,
#[serde(default, skip_serializing_if = "String::is_empty", rename = "type")]
pub typev: String,
}
#[derive(Default, Clone, Debug, Serialize, Deserialize)]
pub struct UserPhone {
#[serde(default, skip_serializing_if = "String::is_empty", rename = "customType")]
pub custom_type: String,
#[serde(default)]
pub primary: bool,
#[serde(default, rename = "type", skip_serializing_if = "String::is_empty")]
pub typev: String,
#[serde(default, skip_serializing_if = "String::is_empty")]
pub value: String,
}
#[derive(Default, Clone, Debug, Serialize, Deserialize)]
pub struct UserPosixAccount {
#[serde(default, skip_serializing_if = "String::is_empty", rename = "accountId")]
pub account_id: String,
#[serde(default, skip_serializing_if = "String::is_empty")]
pub gecos: String,
#[serde(default)]
pub gid: isize,
#[serde(default, skip_serializing_if = "String::is_empty", rename = "homeDirectory")]
pub home_directory: String,
#[serde(default, skip_serializing_if = "String::is_empty", rename = "operatingSystemType")]
pub operating_system_type: String,
#[serde(default)]
pub primary: bool,
#[serde(default, skip_serializing_if = "String::is_empty")]
pub shell: String,
#[serde(default, skip_serializing_if = "String::is_empty", rename = "systemId")]
pub system_id: String,
#[serde(default)]
pub uid: isize,
#[serde(default, skip_serializing_if = "String::is_empty")]
pub username: String,
}
#[derive(Default, Clone, Debug, Serialize, Deserialize)]
pub struct UserRelation {
#[serde(default, skip_serializing_if = "String::is_empty", rename = "customType")]
pub custom_type: String,
#[serde(default, rename = "type", skip_serializing_if = "String::is_empty")]
pub typev: String,
#[serde(default, skip_serializing_if = "String::is_empty")]
pub value: String,
}
#[derive(Default, Clone, Debug, Serialize, Deserialize)]
pub struct UserSSHKey {
#[serde(default, skip_serializing_if = "String::is_empty")]
pub key: String,
#[serde(default, skip_serializing_if = "Option::is_none", rename = "expirationTimeUsec")]
pub expiration_time_usec: Option<i128>,
#[serde(default, skip_serializing_if = "String::is_empty")]
pub fingerprint: String,
}
#[derive(Default, Clone, Debug, Serialize, Deserialize)]
pub struct UserWebsite {
#[serde(default, skip_serializing_if = "String::is_empty", rename = "customType")]
pub custom_type: String,
#[serde(default, alias = "is_group_admin")]
pub primary: bool,
#[serde(default, rename = "type", skip_serializing_if = "String::is_empty")]
pub typev: String,
#[serde(default, skip_serializing_if = "String::is_empty")]
pub value: String,
}
#[derive(Default, Clone, Debug, Deserialize)]
pub struct UserCustomProperties(pub Option<HashMap<String, Value>>);
impl Serialize for UserCustomProperties {
fn serialize<S>(&self, s: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let ucp = self.0.as_ref().unwrap();
let mut map = s.serialize_map(Some(ucp.len())).unwrap();
for (k, v) in ucp {
if v.is_string() {
map.serialize_entry(&k, v.as_str().unwrap()).unwrap();
} else if v.is_array() {
let val: Vec<HashMap<String, String>> = serde_json::from_str(&v.to_string()).unwrap();
map.serialize_entry(&k, &val).unwrap();
}
}
map.end()
}
}
#[derive(Default, Clone, Debug, Serialize, Deserialize)]
struct Users {
#[serde(default, skip_serializing_if = "String::is_empty", rename = "nextPageToken")]
pub next_page_token: String,
#[serde(default, skip_serializing_if = "String::is_empty")]
pub kind: String,
#[serde(default, skip_serializing_if = "String::is_empty")]
pub etag: String,
#[serde(default, skip_serializing_if = "String::is_empty")]
pub trigger_event: String,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub users: Vec<User>,
}
#[derive(Default, Clone, Debug, Serialize, Deserialize)]
pub struct CalendarResource {
#[serde(default, skip_serializing_if = "String::is_empty")]
pub kind: String,
pub capacity: Option<i32>,
#[serde(default, skip_serializing_if = "String::is_empty", rename = "resourceType")]
pub typev: String,
#[serde(default, skip_serializing_if = "String::is_empty", rename = "resourceDescription")]
pub description: String,
#[serde(default, skip_serializing_if = "String::is_empty", rename = "generatedResourceName")]
pub generated_resource_name: String,
#[serde(default, skip_serializing_if = "String::is_empty")]
pub etags: String,
#[serde(default, skip_serializing_if = "String::is_empty", rename = "resourceCategory")]
pub category: String,
#[serde(default, skip_serializing_if = "String::is_empty", rename = "resourceEmail")]
pub email: String,
#[serde(rename = "resourceName", skip_serializing_if = "String::is_empty", default)]
pub name: String,
#[serde(default, skip_serializing_if = "Vec::is_empty", rename = "featureInstances")]
pub feature_instances: Vec<CalendarFeatures>,
#[serde(default, skip_serializing_if = "String::is_empty", rename = "floorSection")]
pub floor_section: String,
#[serde(default, rename = "resourceId", skip_serializing_if = "String::is_empty")]
pub id: String,
#[serde(default, skip_serializing_if = "String::is_empty", rename = "buildingId")]
pub building_id: String,
#[serde(default, skip_serializing_if = "String::is_empty", rename = "floorName")]
pub floor_name: String,
#[serde(default, skip_serializing_if = "String::is_empty", rename = "userVisibleDescription")]
pub user_visible_description: String,
}
#[derive(Default, Clone, Debug, Serialize, Deserialize)]
struct CalendarResources {
#[serde(default, skip_serializing_if = "String::is_empty", rename = "nextPageToken")]
pub next_page_token: String,
#[serde(default, skip_serializing_if = "String::is_empty")]
pub kind: String,
#[serde(default, skip_serializing_if = "String::is_empty")]
pub etag: String,
#[serde(default, skip_serializing_if = "String::is_empty")]
pub trigger_event: String,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub items: Vec<CalendarResource>,
}
#[derive(Default, Clone, Debug, Serialize, Deserialize)]
pub struct CalendarFeature {
#[serde(default, skip_serializing_if = "String::is_empty")]
pub name: String,
#[serde(default, skip_serializing_if = "String::is_empty")]
pub kind: String,
#[serde(default, skip_serializing_if = "String::is_empty")]
pub etags: String,
}
#[derive(Default, Clone, Debug, Serialize, Deserialize)]
pub struct CalendarFeatures {
pub feature: Option<CalendarFeature>,
}
#[derive(Default, Clone, Debug, Serialize, Deserialize)]
pub struct Building {
#[serde(default, skip_serializing_if = "String::is_empty")]
pub kind: String,
#[serde(rename = "buildingName", default, skip_serializing_if = "String::is_empty")]
pub name: String,
pub coordinates: Option<BuildingCoordinates>,
#[serde(default, skip_serializing_if = "String::is_empty")]
pub etags: String,
#[serde(default)]
pub address: BuildingAddress,
#[serde(rename = "floorNames", default, skip_serializing_if = "Vec::is_empty")]
pub floor_names: Vec<String>,
#[serde(rename = "buildingId", default, skip_serializing_if = "String::is_empty")]
pub id: String,
#[serde(default, skip_serializing_if = "String::is_empty")]
pub description: String,
}
#[derive(Default, Clone, Debug, Serialize, Deserialize)]
struct Buildings {
#[serde(default, skip_serializing_if = "String::is_empty", rename = "nextPageToken")]
pub next_page_token: String,
#[serde(default, skip_serializing_if = "String::is_empty")]
pub kind: String,
#[serde(default, skip_serializing_if = "String::is_empty")]
pub etag: String,
#[serde(default, skip_serializing_if = "String::is_empty")]
pub trigger_event: String,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub buildings: Vec<Building>,
}
#[derive(Default, Clone, Debug, Serialize, Deserialize)]
pub struct BuildingCoordinates {
#[serde(default)]
pub latitude: f64,
#[serde(default)]
pub longitude: f64,
}
#[derive(Default, Clone, Debug, Serialize, Deserialize)]
pub struct BuildingAddress {
#[serde(rename = "languageCode", default, skip_serializing_if = "String::is_empty")]
pub language_code: String,
#[serde(rename = "administrativeArea", default, skip_serializing_if = "String::is_empty")]
pub administrative_area: String,
#[serde(rename = "regionCode", default, skip_serializing_if = "String::is_empty")]
pub region_code: String,
#[serde(default, skip_serializing_if = "String::is_empty")]
pub locality: String,
#[serde(rename = "postalCode", default, skip_serializing_if = "String::is_empty")]
pub postal_code: String,
#[serde(default, skip_serializing_if = "String::is_empty")]
pub sublocality: String,
#[serde(rename = "addressLines", default, skip_serializing_if = "Vec::is_empty")]
pub address_lines: Vec<String>,
}