1use crate::{ArtifactKind, ArtifactReference, ArtifactReferenceError};
3use serde::{Deserialize, Serialize};
4
5#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
6#[serde(deny_unknown_fields)]
7pub struct MediaReference {
8 pub uri: String,
9}
10
11impl MediaReference {
12 pub fn reference(
13 &self,
14 kind: ArtifactKind,
15 ) -> Result<ArtifactReference, ArtifactReferenceError> {
16 let reference = ArtifactReference::parse(&self.uri)?;
17 if reference.metadata().kind() != kind {
18 return Err(super::invalid(
19 "media artifact kind does not match the field type",
20 ));
21 }
22 Ok(reference)
23 }
24
25 pub fn validate(
26 &self,
27 tenant: &str,
28 scope: &str,
29 kind: ArtifactKind,
30 ) -> Result<ArtifactReference, ArtifactReferenceError> {
31 let reference = self.reference(kind)?;
32 reference.ensure_scope(tenant, scope)?;
33 Ok(reference)
34 }
35}
36
37#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
39#[serde(rename_all = "camelCase", deny_unknown_fields)]
40pub struct ImportArtifactRequest {
41 pub kind: ArtifactKind,
42 pub source_url: String,
43 #[serde(default, skip_serializing_if = "Option::is_none")]
44 pub transform: Option<crate::ImageTransform>,
45 #[serde(default, skip_serializing_if = "Option::is_none")]
46 pub mime_type: Option<String>,
47}
48
49#[cfg(test)]
50mod tests {
51 use super::*;
52 #[test]
53 fn media_rejects_legacy_fields_and_wrong_scope_or_kind() {
54 for value in [
55 serde_json::json!({"url":"https://example.com/a"}),
56 serde_json::json!({"uri":"x","base64":"eA=="}),
57 serde_json::json!({"uri":"x","mimeType":"image/png"}),
58 serde_json::json!({"uri":"x","createdAt":1}),
59 ] {
60 assert!(serde_json::from_value::<MediaReference>(value).is_err());
61 }
62 let reference = ArtifactReference::new(
63 "tenant",
64 "scope",
65 "a".repeat(64),
66 crate::ArtifactMetadata::audio("audio/mpeg", 10, None).unwrap(),
67 )
68 .unwrap();
69 let media = MediaReference {
70 uri: reference.uri().unwrap(),
71 };
72 assert!(media
73 .validate("tenant", "scope", ArtifactKind::Audio)
74 .is_ok());
75 assert!(media
76 .validate("tenant", "other", ArtifactKind::Audio)
77 .is_err());
78 assert!(media
79 .validate("tenant", "scope", ArtifactKind::Image)
80 .is_err());
81 assert!(MediaReference {
82 uri: "https://example.com/a".into()
83 }
84 .reference(ArtifactKind::Audio)
85 .is_err());
86 }
87}