bitwarden_pam/approvals/
models.rs1use bitwarden_api_api::models::{
2 AccessDecisionRequestModel, AccessDecisionVerdict as ApiAccessDecisionVerdict,
3 AccessRequestRevokeRequestModel,
4};
5use serde::{Deserialize, Serialize};
6
7use super::error::ApprovalError;
8use crate::AccessDecisionVerdict;
9
10#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
12#[bitwarden_ffi::wasm_record]
13#[serde(rename_all = "camelCase")]
14pub struct AccessDecisionRequest {
15 pub verdict: AccessDecisionVerdict,
17 pub comment: Option<String>,
19}
20
21impl TryFrom<AccessDecisionRequest> for AccessDecisionRequestModel {
22 type Error = ApprovalError;
23
24 fn try_from(request: AccessDecisionRequest) -> Result<Self, Self::Error> {
25 let verdict = match request.verdict {
26 AccessDecisionVerdict::Approve => ApiAccessDecisionVerdict::Approve,
27 AccessDecisionVerdict::Deny => ApiAccessDecisionVerdict::Deny,
28 AccessDecisionVerdict::Unknown => return Err(ApprovalError::UnsubmittableVerdict),
29 };
30
31 Ok(Self {
32 verdict,
33 comment: request.comment,
34 })
35 }
36}
37
38#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
40#[bitwarden_ffi::wasm_record]
41#[serde(rename_all = "camelCase")]
42pub struct AccessRequestRevokeRequest {
43 pub reason: String,
46}
47
48impl From<AccessRequestRevokeRequest> for AccessRequestRevokeRequestModel {
49 fn from(request: AccessRequestRevokeRequest) -> Self {
50 Self {
51 reason: Some(request.reason),
52 }
53 }
54}
55
56#[cfg(test)]
57mod tests {
58 use super::*;
59
60 #[test]
61 fn approve_converts_to_model() {
62 let request = AccessDecisionRequest {
63 verdict: AccessDecisionVerdict::Approve,
64 comment: Some("Looks fine".to_string()),
65 };
66
67 let model = AccessDecisionRequestModel::try_from(request).unwrap();
68
69 assert_eq!(model.verdict, ApiAccessDecisionVerdict::Approve);
70 assert_eq!(model.comment, Some("Looks fine".to_string()));
71 }
72
73 #[test]
74 fn deny_converts_to_model() {
75 let request = AccessDecisionRequest {
76 verdict: AccessDecisionVerdict::Deny,
77 comment: None,
78 };
79
80 let model = AccessDecisionRequestModel::try_from(request).unwrap();
81
82 assert_eq!(model.verdict, ApiAccessDecisionVerdict::Deny);
83 assert_eq!(model.comment, None);
84 }
85
86 #[test]
87 fn unknown_verdict_is_rejected() {
88 let request = AccessDecisionRequest {
89 verdict: AccessDecisionVerdict::Unknown,
90 comment: None,
91 };
92
93 let result = AccessDecisionRequestModel::try_from(request);
94
95 assert!(matches!(result, Err(ApprovalError::UnsubmittableVerdict)));
96 }
97
98 #[test]
99 fn revoke_converts_to_model() {
100 let model = AccessRequestRevokeRequestModel::from(AccessRequestRevokeRequest {
101 reason: "Approved by mistake".to_string(),
102 });
103
104 assert_eq!(model.reason.as_deref(), Some("Approved by mistake"));
105 }
106}