uptrakit_web_api_types/
autodiscovery.rs1use serde::{Deserialize, Serialize};
2use time::OffsetDateTime;
3use uuid::Uuid;
4
5use crate::validation::{Validate, ValidationError};
6
7#[derive(Serialize, Deserialize)]
9#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
10pub struct TriggerDiscoveryResponse {
11 pub plugins_queued: u32,
13 pub message: String,
15}
16
17#[derive(Serialize, Deserialize)]
19#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
20pub struct SoftwareIgnoreResponse {
21 pub id: Uuid,
23 pub name: String,
25 #[serde(default, skip_serializing_if = "Option::is_none")]
28 pub host_id: Option<Uuid>,
29 #[serde(with = "time::serde::rfc3339")]
30 #[cfg_attr(feature = "openapi", schema(value_type = String, format = DateTime))]
31 pub created_at: OffsetDateTime,
32}
33
34#[derive(Serialize, Deserialize)]
36#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
37pub struct CreateSoftwareIgnoreRequest {
38 pub name: String,
40 #[serde(default, skip_serializing_if = "Option::is_none")]
43 pub host_id: Option<Uuid>,
44}
45
46impl Validate for CreateSoftwareIgnoreRequest {
47 fn validate(&self) -> Result<(), ValidationError> {
48 if self.name.trim().is_empty() {
49 return Err(ValidationError {
50 field: "name",
51 message: "name must not be empty".to_string(),
52 });
53 }
54 Ok(())
55 }
56}
57
58#[cfg(test)]
59mod tests {
60 use super::*;
61
62 fn make_request(name: &str) -> CreateSoftwareIgnoreRequest {
63 CreateSoftwareIgnoreRequest {
64 name: name.to_string(),
65 host_id: None,
66 }
67 }
68
69 #[test]
70 fn validate_accepts_non_empty_name() {
71 assert!(make_request("FreshRSS").validate().is_ok());
72 }
73
74 #[test]
75 fn validate_rejects_empty_name() {
76 let err = make_request("").validate().unwrap_err();
77 assert_eq!(err.field, "name");
78 }
79
80 #[test]
81 fn validate_rejects_whitespace_only_name() {
82 assert!(make_request(" ").validate().is_err());
83 }
84
85 #[test]
86 fn software_ignore_response_round_trip_tenant_wide() {
87 use time::macros::datetime;
88 let resp = SoftwareIgnoreResponse {
89 id: Uuid::nil(),
90 name: "FreshRSS".to_string(),
91 host_id: None,
92 created_at: datetime!(2025-01-01 0:00:00 UTC),
93 };
94 let json = serde_json::to_string(&resp).expect("serialization should succeed");
95 let deserialized: SoftwareIgnoreResponse =
96 serde_json::from_str(&json).expect("deserialization should succeed");
97 assert_eq!(deserialized.name, "FreshRSS");
98 assert!(deserialized.host_id.is_none());
99 assert!(!json.contains("host_id"));
101 }
102
103 #[test]
104 fn software_ignore_response_round_trip_per_host() {
105 use time::macros::datetime;
106 let host = Uuid::parse_str("a1a2a3a4-b1b2-c1c2-d1d2-e1e2e3e4e5e6").expect("valid uuid");
107 let resp = SoftwareIgnoreResponse {
108 id: Uuid::nil(),
109 name: "FreshRSS".to_string(),
110 host_id: Some(host),
111 created_at: datetime!(2025-01-01 0:00:00 UTC),
112 };
113 let json = serde_json::to_string(&resp).expect("serialization should succeed");
114 let deserialized: SoftwareIgnoreResponse =
115 serde_json::from_str(&json).expect("deserialization should succeed");
116 assert_eq!(deserialized.host_id, Some(host));
117 }
118
119 #[test]
120 fn create_request_with_host_id() {
121 let host = Uuid::parse_str("a1a2a3a4-b1b2-c1c2-d1d2-e1e2e3e4e5e6").expect("valid uuid");
122 let req = CreateSoftwareIgnoreRequest {
123 name: "FreshRSS".to_string(),
124 host_id: Some(host),
125 };
126 assert!(req.validate().is_ok());
127 let json = serde_json::to_string(&req).expect("serialization should succeed");
128 let deserialized: CreateSoftwareIgnoreRequest =
129 serde_json::from_str(&json).expect("deserialization should succeed");
130 assert_eq!(deserialized.host_id, Some(host));
131 }
132}