leptos_forms_rs/error/
reporter.rs1use super::{ErrorContext, FormError};
7
8pub trait ErrorReporter {
10 fn report_error(&self, error: &FormError, context: &ErrorContext);
12}
13
14pub struct ConsoleErrorReporter;
16
17impl ErrorReporter for ConsoleErrorReporter {
18 fn report_error(&self, error: &FormError, context: &ErrorContext) {
19 log::error!("Error reported: {} (context: {:?})", error, context);
20 }
21}
22
23pub struct FileErrorReporter {
25 file_path: String,
26}
27
28impl FileErrorReporter {
29 pub fn new(file_path: impl Into<String>) -> Self {
31 Self {
32 file_path: file_path.into(),
33 }
34 }
35
36 pub fn file_path(&self) -> &str {
38 &self.file_path
39 }
40}
41
42impl ErrorReporter for FileErrorReporter {
43 fn report_error(&self, error: &FormError, context: &ErrorContext) {
44 log::error!(
47 "Error reported to file {}: {} (context: {:?})",
48 self.file_path,
49 error,
50 context
51 );
52 }
53}
54
55pub struct HttpErrorReporter {
57 endpoint: String,
58 api_key: Option<String>,
59}
60
61impl HttpErrorReporter {
62 pub fn new(endpoint: impl Into<String>) -> Self {
64 Self {
65 endpoint: endpoint.into(),
66 api_key: None,
67 }
68 }
69
70 pub fn with_api_key(mut self, api_key: impl Into<String>) -> Self {
72 self.api_key = Some(api_key.into());
73 self
74 }
75
76 pub fn endpoint(&self) -> &str {
78 &self.endpoint
79 }
80
81 pub fn has_api_key(&self) -> bool {
83 self.api_key.is_some()
84 }
85}
86
87impl ErrorReporter for HttpErrorReporter {
88 fn report_error(&self, error: &FormError, context: &ErrorContext) {
89 log::error!(
92 "Error reported to HTTP endpoint {}: {} (context: {:?})",
93 self.endpoint,
94 error,
95 context
96 );
97 }
98}
99
100pub struct CompositeErrorReporter {
102 reporters: Vec<Box<dyn ErrorReporter + Send + Sync>>,
103}
104
105impl CompositeErrorReporter {
106 pub fn new() -> Self {
108 Self {
109 reporters: Vec::new(),
110 }
111 }
112
113 pub fn add_reporter(mut self, reporter: Box<dyn ErrorReporter + Send + Sync>) -> Self {
115 self.reporters.push(reporter);
116 self
117 }
118
119 pub fn reporter_count(&self) -> usize {
121 self.reporters.len()
122 }
123}
124
125impl Default for CompositeErrorReporter {
126 fn default() -> Self {
127 Self::new()
128 }
129}
130
131impl ErrorReporter for CompositeErrorReporter {
132 fn report_error(&self, error: &FormError, context: &ErrorContext) {
133 for reporter in &self.reporters {
134 reporter.report_error(error, context);
135 }
136 }
137}
138
139pub mod utils {
141 use super::*;
142 use crate::error::field_error;
143
144 pub fn field_error_from_validation(field: &str, message: &str) -> FormError {
146 FormError::field_error(field, message)
147 }
148
149 pub fn validation_error_from_fields(
151 message: &str,
152 field_errors: Vec<field_error::FieldError>,
153 ) -> FormError {
154 FormError::validation_error(message, field_errors)
155 }
156
157 pub fn extract_field_errors(error: &FormError) -> Vec<field_error::FieldError> {
159 match error {
160 FormError::ValidationError { field_errors, .. } => field_errors.clone(),
161 FormError::FieldError {
162 field,
163 message,
164 code,
165 } => {
166 vec![field_error::FieldError {
167 field: field.clone(),
168 message: message.clone(),
169 code: code.clone(),
170 }]
171 }
172 _ => Vec::new(),
173 }
174 }
175
176 pub fn is_recoverable_error(error: &FormError) -> bool {
178 matches!(
179 error,
180 FormError::FieldError { .. }
181 | FormError::ValidationError { .. }
182 | FormError::SerializationError { .. }
183 )
184 }
185
186 pub fn is_critical_error(error: &FormError) -> bool {
188 matches!(
189 error,
190 FormError::StateError { .. } | FormError::ConfigurationError { .. }
191 )
192 }
193
194 pub fn get_error_severity(error: &FormError) -> ErrorSeverity {
196 match error {
197 FormError::FieldError { .. } => ErrorSeverity::Low,
198 FormError::ValidationError { .. } => ErrorSeverity::Medium,
199 FormError::SerializationError { .. } => ErrorSeverity::Medium,
200 FormError::SubmissionError { .. } => ErrorSeverity::High,
201 FormError::StateError { .. } => ErrorSeverity::Critical,
202 FormError::PersistenceError { .. } => ErrorSeverity::High,
203 FormError::ConfigurationError { .. } => ErrorSeverity::Critical,
204 FormError::Unknown { .. } => ErrorSeverity::High,
205 }
206 }
207
208 pub fn format_error_for_logging(error: &FormError, context: &ErrorContext) -> String {
210 format!("Error: {} | Context: {}", error, context)
211 }
212
213 pub fn format_error_for_reporting(error: &FormError, context: &ErrorContext) -> String {
215 let severity = get_error_severity(error);
216 format!("[{}] {} | Context: {}", severity, error, context)
217 }
218}
219
220#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
222pub enum ErrorSeverity {
223 Low,
224 Medium,
225 High,
226 Critical,
227}
228
229impl std::fmt::Display for ErrorSeverity {
230 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
231 match self {
232 ErrorSeverity::Low => write!(f, "LOW"),
233 ErrorSeverity::Medium => write!(f, "MEDIUM"),
234 ErrorSeverity::High => write!(f, "HIGH"),
235 ErrorSeverity::Critical => write!(f, "CRITICAL"),
236 }
237 }
238}