Skip to main content

core_invoice/
attachment.rs

1use crate::error::AttachmentError;
2
3/// Binary object: bytes + mime + filename, all mandatory and non-blank.
4#[derive(Debug, Clone, PartialEq, Eq)]
5pub struct Attachment {
6    pub bytes: Vec<u8>,
7    pub mime: String,
8    pub filename: String,
9}
10
11impl Attachment {
12    pub const RECEIVER_MUST_ACCEPT: &'static [&'static str] = &[
13        "application/pdf",
14        "image/png",
15        "image/jpeg",
16        "text/csv",
17        "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
18        "application/vnd.oasis.opendocument.spreadsheet",
19    ];
20
21    pub fn new(
22        bytes: Vec<u8>,
23        mime: impl Into<String>,
24        filename: impl Into<String>,
25    ) -> Result<Self, AttachmentError> {
26        let mime = mime.into();
27        let filename = filename.into();
28        if mime.trim().is_empty() {
29            return Err(AttachmentError::EmptyMime);
30        }
31        if filename.trim().is_empty() {
32            return Err(AttachmentError::EmptyFilename);
33        }
34        Ok(Self {
35            bytes,
36            mime,
37            filename,
38        })
39    }
40
41    pub fn is_universally_accepted(&self) -> bool {
42        Self::RECEIVER_MUST_ACCEPT.contains(&self.mime.as_str())
43    }
44}
45
46#[cfg(test)]
47mod tests {
48    use super::*;
49
50    #[test]
51    fn rejects_blank_mime_or_filename() {
52        assert!(Attachment::new(vec![], "", "x.pdf").is_err());
53        assert!(Attachment::new(vec![], "application/pdf", "  ").is_err());
54        let a = Attachment::new(b"%PDF".to_vec(), "application/pdf", "terms.pdf").unwrap();
55        assert!(a.is_universally_accepted());
56    }
57}