iceshrimp-legacy/packages/backend/native-utils/src/model/schema/antenna.rs

218 lines
6.3 KiB
Rust
Raw Normal View History

2023-06-02 17:55:14 +02:00
use cfg_if::cfg_if;
2023-05-25 08:34:48 +02:00
use jsonschema::JSONSchema;
use once_cell::sync::Lazy;
2023-05-25 14:55:20 +02:00
use parse_display::FromStr;
2023-05-25 08:34:48 +02:00
use schemars::JsonSchema;
use utoipa::ToSchema;
2023-05-31 18:09:30 +02:00
use super::Schema;
2023-06-02 14:48:12 +02:00
use crate::model;
use crate::model::entity::sea_orm_active_enums::AntennaSrcEnum;
2023-05-25 08:34:48 +02:00
2023-05-27 11:50:07 +02:00
#[derive(Clone, Debug, PartialEq, Eq, JsonSchema, ToSchema)]
2023-05-25 08:34:48 +02:00
#[serde(rename_all = "camelCase")]
pub struct Antenna {
pub id: String,
pub created_at: chrono::DateTime<chrono::Utc>,
pub name: String,
2023-06-01 00:12:59 +02:00
pub keywords: Vec<Vec<String>>,
pub exclude_keywords: Vec<Vec<String>>,
2023-05-25 08:34:48 +02:00
#[schema(inline)]
2023-05-25 14:55:20 +02:00
pub src: AntennaSrc,
2023-05-25 08:34:48 +02:00
pub user_list_id: Option<String>,
pub user_group_id: Option<String>,
2023-05-31 18:24:02 +02:00
pub users: Vec<String>,
2023-06-01 00:12:59 +02:00
pub instances: Vec<String>,
2023-05-25 08:34:48 +02:00
#[serde(default)]
pub case_sensitive: bool,
#[serde(default)]
pub notify: bool,
#[serde(default)]
pub with_replies: bool,
#[serde(default)]
pub with_file: bool,
#[serde(default)]
pub has_unread_note: bool,
}
2023-05-27 11:50:07 +02:00
#[derive(Clone, Debug, FromStr, PartialEq, Eq, JsonSchema, ToSchema)]
#[serde(rename_all = "camelCase")]
#[display(style = "camelCase")]
#[display("'{}'")]
2023-05-25 14:55:20 +02:00
pub enum AntennaSrc {
2023-05-25 08:34:48 +02:00
Home,
All,
Users,
List,
Group,
Instances,
}
2023-06-02 13:08:58 +02:00
impl TryFrom<AntennaSrcEnum> for super::AntennaSrc {
2023-06-02 14:48:12 +02:00
type Error = model::error::Error;
2023-05-25 14:55:20 +02:00
fn try_from(value: AntennaSrcEnum) -> Result<Self, Self::Error> {
2023-06-02 14:48:12 +02:00
value.to_string().parse().map_err(model::error::Error::from)
2023-05-25 14:55:20 +02:00
}
}
2023-05-25 08:34:48 +02:00
2023-05-25 14:55:20 +02:00
// ---- TODO: could be macro
2023-06-02 13:08:58 +02:00
impl Schema<Self> for super::Antenna {}
2023-07-17 00:32:32 +02:00
pub static VALIDATOR: Lazy<JSONSchema> = Lazy::new(super::Antenna::validator);
2023-05-25 14:55:20 +02:00
// ----
2023-05-25 08:34:48 +02:00
2023-06-02 17:55:14 +02:00
cfg_if! {
if #[cfg(feature = "napi")] {
use napi::bindgen_prelude::{FromNapiValue, ToNapiValue};
use napi_derive::napi;
2023-06-02 15:29:52 +02:00
2023-06-02 17:55:14 +02:00
use crate::model::entity::antenna;
use crate::model::repository::Repository;
/// For NAPI because [chrono] is not supported.
2023-06-02 21:50:40 +02:00
#[napi(object)]
2023-06-02 17:55:14 +02:00
#[derive(Clone, Debug, PartialEq, Eq, JsonSchema, ToSchema)]
#[serde(rename_all = "camelCase")]
pub struct NativeAntennaSchema {
pub id: String,
pub created_at: String,
pub name: String,
pub keywords: Vec<Vec<String>>,
pub exclude_keywords: Vec<Vec<String>>,
#[schema(inline)]
pub src: NativeAntennaSrc,
pub user_list_id: Option<String>,
pub user_group_id: Option<String>,
pub users: Vec<String>,
pub instances: Vec<String>,
#[serde(default)]
pub case_sensitive: bool,
#[serde(default)]
pub notify: bool,
#[serde(default)]
pub with_replies: bool,
#[serde(default)]
pub with_file: bool,
#[serde(default)]
pub has_unread_note: bool,
}
2023-06-02 21:50:40 +02:00
#[napi(string_enum)]
2023-06-02 17:55:14 +02:00
#[derive(Debug, FromStr, PartialEq, Eq, JsonSchema, ToSchema)]
#[display("'{}'")]
2023-06-02 21:50:40 +02:00
#[allow(non_camel_case_types)]
2023-06-02 17:55:14 +02:00
pub enum NativeAntennaSrc {
2023-06-02 21:50:40 +02:00
home,
all,
users,
list,
group,
instances,
2023-06-02 17:55:14 +02:00
}
2023-06-02 15:29:52 +02:00
#[napi]
2023-06-02 21:50:40 +02:00
pub async fn native_pack_antenna_by_id(id: String) -> napi::Result<NativeAntennaSchema> {
antenna::Model::pack_by_id(id).await.map_err(Into::into)
2023-06-02 15:29:52 +02:00
}
}
}
2023-05-25 08:34:48 +02:00
#[cfg(test)]
2023-05-27 12:52:15 +02:00
mod unit_test {
2023-06-02 22:34:45 +02:00
use cfg_if::cfg_if;
2023-06-02 13:08:58 +02:00
use pretty_assertions::assert_eq;
2023-05-25 08:34:48 +02:00
use serde_json::json;
2023-06-02 14:48:12 +02:00
use crate::model::{entity::sea_orm_active_enums::AntennaSrcEnum, schema::AntennaSrc};
2023-05-27 11:50:07 +02:00
2023-05-25 08:34:48 +02:00
use super::VALIDATOR;
#[test]
2023-05-27 12:52:15 +02:00
fn src_from_active_enum() {
2023-05-27 11:50:07 +02:00
let src = AntennaSrc::try_from(AntennaSrcEnum::All).unwrap();
2023-06-02 22:34:45 +02:00
cfg_if! {
if #[cfg(feature = "napi")] {
assert_eq!(src, AntennaSrc::all);
} else {
assert_eq!(src, AntennaSrc::All);
}
}
2023-05-27 11:50:07 +02:00
}
#[test]
2023-05-27 12:52:15 +02:00
fn antenna_valid() {
2023-05-25 08:34:48 +02:00
let instance = json!({
2023-06-03 05:01:53 +02:00
"id": "9fil64s6g7cskdrb",
2023-05-25 08:34:48 +02:00
"createdAt": "2023-05-24T06:56:14.323Z",
"name": "Valid Antenna",
"keywords": [["first", "keyword"], ["second"]],
"excludeKeywords": [["excluding", "keywrods"], ["from", "antenna"]],
"src": "users",
// "userListId" and "userGroupId" can be null or be omitted
"userListId": null,
2023-06-03 05:01:53 +02:00
"users": ["9fil64s6g7cskdrb", "9fil66brl1udxau2"],
2023-05-25 08:34:48 +02:00
"instances": [],
// "caseSensitive", "notify", "withReplies", "withFile", and
// "hasUnreadNote" are false if ommited
"notify": false,
"withReplies": false,
"withFile": false,
"hasUnreadNote": false,
});
assert!(VALIDATOR.is_valid(&instance));
}
#[test]
2023-05-27 12:52:15 +02:00
fn antenna_invalid() {
2023-05-25 08:34:48 +02:00
let instance = json!({
// "id" is required
"id": null,
// trailing "Z" is missing
"createdAt": "2023-05-24T07:36:34.389",
// "name" is required
// "keywords" must be an array
"keywords": "invalid keyword",
// "excludeKeywords" is required
"excludeKeywords": null,
2023-06-03 05:01:53 +02:00
// "src" must be one of "home", "all", "users", "list", "group", and
2023-05-25 08:34:48 +02:00
// "instances"
"src": "invalid_src",
// "userListId" is string
"userListId": ["9f4ziiqfxw"],
// "users" must be an array of strings
2023-06-03 05:01:53 +02:00
"users": [1, "9fil64s6g7cskdrb"],
"instances": ["9fil65jzhtjpi3xn"],
2023-05-25 08:34:48 +02:00
// "caseSensitive" is boolean
"caseSensitive": 0,
"notify": true,
"withReplies": true,
"withFile": true,
"hasUnreadNote": true,
});
let result = VALIDATOR
.validate(&instance)
.expect_err("validation must fail");
2023-06-02 13:08:58 +02:00
let mut paths: Vec<String> = result
.map(|e| e.instance_path.to_string())
.filter(|e| !e.is_empty())
.collect();
2023-05-25 08:34:48 +02:00
paths.sort();
assert_eq!(
paths,
vec![
2023-06-02 13:08:58 +02:00
"/caseSensitive",
#[cfg(not(feature = "napi"))]
"/createdAt",
"/excludeKeywords",
"/id",
"/keywords",
"/src",
"/userListId",
"/users/0"
2023-05-25 08:34:48 +02:00
]
);
}
}