use bon::Builder;
use serde::{Deserialize, Serialize};
use crate::types::validate_fields;
use crate::types::{Extensions, OcpiString, PartyRef, Url, Validate, Validator, ViolationCode};
use super::locations::BusinessDetails;
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, Builder)]
#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
#[builder(on(_, into))]
pub struct Credentials {
pub token: OcpiString<64>,
pub url: Url,
pub business_details: BusinessDetails,
pub party_id: OcpiString<3>,
pub country_code: OcpiString<2>,
#[serde(flatten, default, skip_serializing_if = "Extensions::is_empty")]
#[builder(default)]
pub extensions: Extensions,
}
impl Credentials {
pub fn party(&self) -> Result<PartyRef, crate::types::InvalidString> {
PartyRef::new(self.country_code.as_str(), self.party_id.as_str())
}
}
impl Validate for Credentials {
fn validate_in(&self, v: &mut Validator) {
validate_fields!(self, v, token, url, business_details, party_id, country_code);
if let Some(bad) = self.token.as_str().chars().find(|c| !matches!(c, '!'..='~')) {
v.report_at(
"token",
ViolationCode::IllegalCharacter,
format!("a credentials token may only contain U+0021..U+007E; found U+{:04X}", bad as u32),
);
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn the_2_1_1_credentials_object_is_flat() {
let json = r#"{"token":"ebf3b399-779f-4497-9b9d-ac6ad3cc44d2","url":"https://example.com/ocpi/cpo/","business_details":{"name":"Example Operator"},"party_id":"EXA","country_code":"NL"}"#;
let credentials: Credentials = serde_json::from_str(json).unwrap();
assert!(credentials.validate().is_ok());
assert_eq!(credentials.party().unwrap().to_string(), "NL/EXA");
assert_eq!(serde_json::to_string(&credentials).unwrap(), json);
assert!(!json.contains("roles"));
}
}