ocpi_kit/v2_1_1/
credentials.rs1use bon::Builder;
10use serde::{Deserialize, Serialize};
11
12use crate::types::validate_fields;
13use crate::types::{Extensions, OcpiString, PartyRef, Url, Validate, Validator, ViolationCode};
14
15use super::locations::BusinessDetails;
16
17#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, Builder)]
21#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
22#[builder(on(_, into))]
23pub struct Credentials {
24 pub token: OcpiString<64>,
26 pub url: Url,
28 pub business_details: BusinessDetails,
30 pub party_id: OcpiString<3>,
32 pub country_code: OcpiString<2>,
34 #[serde(flatten, default, skip_serializing_if = "Extensions::is_empty")]
36 #[builder(default)]
37 pub extensions: Extensions,
38}
39
40impl Credentials {
41 pub fn party(&self) -> Result<PartyRef, crate::types::InvalidString> {
48 PartyRef::new(self.country_code.as_str(), self.party_id.as_str())
49 }
50}
51
52impl Validate for Credentials {
53 fn validate_in(&self, v: &mut Validator) {
54 validate_fields!(self, v, token, url, business_details, party_id, country_code);
55 if let Some(bad) = self.token.as_str().chars().find(|c| !matches!(c, '!'..='~')) {
56 v.report_at(
57 "token",
58 ViolationCode::IllegalCharacter,
59 format!("a credentials token may only contain U+0021..U+007E; found U+{:04X}", bad as u32),
60 );
61 }
62 }
63}
64
65#[cfg(test)]
66mod tests {
67 use super::*;
68
69 #[test]
70 fn the_2_1_1_credentials_object_is_flat() {
71 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"}"#;
72 let credentials: Credentials = serde_json::from_str(json).unwrap();
73 assert!(credentials.validate().is_ok());
74 assert_eq!(credentials.party().unwrap().to_string(), "NL/EXA");
75 assert_eq!(serde_json::to_string(&credentials).unwrap(), json);
76 assert!(!json.contains("roles"));
78 }
79}