1use std::any::Any;
2
3use crate::{
4 error::ShieldError,
5 form::Form,
6 provider::Provider,
7 request::{Request, RequestMethod},
8 response::Response,
9 session::{BaseSession, MethodSession},
10};
11use async_trait::async_trait;
12use serde::{Deserialize, Serialize};
13
14#[async_trait]
15pub trait Action: Send + Sync {
16 fn id(&self) -> &'static str;
17
18 fn name(&self) -> &'static str;
19
20 fn openapi_summary(&self) -> &'static str;
21
22 fn openapi_description(&self) -> &'static str;
23
24 fn method(&self) -> RequestMethod;
25
26 async fn forms(&self) -> Result<Vec<Form>, ShieldError>;
27
28 async fn call(&self, session: &BaseSession, request: Request) -> Result<Response, ShieldError>;
29}
30
31#[derive(Clone, Debug, Deserialize, Serialize)]
33#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
34#[serde(rename_all = "camelCase")]
35pub struct ActionForms {
36 pub id: String,
37 pub name: String,
38 pub forms: Vec<Form>,
39 pub method_forms: Vec<ActionMethodForm>,
40}
41
42#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
44#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
45#[serde(rename_all = "camelCase")]
46pub struct ActionMethodForm {
47 pub id: String,
48 pub provider_forms: Vec<ActionProviderForm>,
49}
50
51#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
53#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
54#[serde(rename_all = "camelCase")]
55pub struct ActionProviderForm {
56 pub id: Option<String>,
57 pub form: Form,
58}
59
60#[async_trait]
61pub trait MethodAction<P: Provider, S>: ErasedMethodAction + Send + Sync {
62 fn id(&self) -> String;
63
64 fn name(&self) -> String;
65
66 fn openapi_summary(&self) -> &'static str;
67
68 fn openapi_description(&self) -> &'static str;
69
70 fn method(&self) -> RequestMethod;
71
72 fn condition(&self, _provider: &P, _session: &MethodSession<S>) -> Result<bool, ShieldError> {
73 Ok(true)
74 }
75
76 async fn forms(&self, provider: P) -> Result<Vec<Form>, ShieldError>;
77
78 async fn call(
79 &self,
80 provider: P,
81 session: &MethodSession<S>,
82 request: Request,
83 ) -> Result<Response, ShieldError>;
84}
85
86#[async_trait]
87pub trait ErasedMethodAction: Send + Sync {
88 fn erased_id(&self) -> String;
89
90 fn erased_name(&self) -> String;
91
92 fn erased_openapi_summary(&self) -> &'static str;
93
94 fn erased_openapi_description(&self) -> &'static str;
95
96 fn erased_method(&self) -> RequestMethod;
97
98 fn erased_condition(
99 &self,
100 provider: &(dyn Any + Send + Sync),
101 base_session: &BaseSession,
102 method_session: &(dyn Any + Send + Sync),
103 ) -> Result<bool, ShieldError>;
104
105 async fn erased_forms(
106 &self,
107 provider: Box<dyn Any + Send + Sync>,
108 ) -> Result<Vec<Form>, ShieldError>;
109
110 async fn erased_call(
111 &self,
112 provider: Box<dyn Any + Send + Sync>,
113 base_session: &BaseSession,
114 method_session: &(dyn Any + Send + Sync),
115 request: Request,
116 ) -> Result<Response, ShieldError>;
117}
118
119#[macro_export]
120macro_rules! erased_method_action {
121 ($action:ident $(, < $( $generic_name:ident : $generic_type:ident ),+ > )*) => {
122 #[async_trait]
123 impl $( < $( $generic_name: $generic_type + 'static ),+ > )* $crate::ErasedMethodAction for $action $( < $( $generic_name ),+ > )* {
124 fn erased_id(&self) -> String {
125 self.id()
126 }
127
128 fn erased_name(&self) -> String {
129 self.name()
130 }
131
132 fn erased_openapi_summary(&self) -> &'static str {
133 self.openapi_summary()
134 }
135
136 fn erased_openapi_description(&self) -> &'static str {
137 self.openapi_description()
138 }
139
140 fn erased_method(&self) -> $crate::RequestMethod {
141 self.method()
142 }
143
144 fn erased_condition(
145 &self,
146 provider: &(dyn std::any::Any + Send + Sync),
147 base_session: &$crate::BaseSession,
148 method_session: &(dyn std::any::Any + Send + Sync)
149 ) -> Result<bool, $crate::ShieldError> {
150 self.condition(
151 provider.downcast_ref().expect("Provider should be downcast"),
152 &MethodSession {
153 base: base_session,
154 method: method_session.downcast_ref().expect("Session should be downcast"),
155 },
156 )
157 }
158
159 async fn erased_forms(
160 &self,
161 provider: Box<dyn std::any::Any + Send + Sync>
162 ) -> Result<Vec<$crate::Form>, $crate::ShieldError> {
163 self.forms(*provider.downcast().expect("Provider should be downcast")).await
164 }
165
166 async fn erased_call(
167 &self,
168 provider: Box<dyn std::any::Any + Send + Sync>,
169 base_session: &$crate::BaseSession,
170 method_session: &(dyn std::any::Any + Send + Sync),
171 request: $crate::Request,
172 ) -> Result<$crate::Response, $crate::ShieldError> {
173 self
174 .call(
175 *provider.downcast().expect("Provider should be downcast"),
176 &$crate::MethodSession {
177 base: base_session,
178 method: method_session.downcast_ref().expect("Session should be downcast"),
179 },
180 request
181 )
182 .await
183 }
184 }
185 };
186}