Skip to main content

wechat_minapp/minapp_security/
mod.rs

1//! 微信小程序内容安全检测模块
2//!
3//! - [`msg_sec_check`][]: 文本内容安全检测。
4//!
5
6pub mod msg_sec_check;
7
8use serde::{Deserialize, Serialize};
9use serde_repr::Deserialize_repr;
10use strum::Display;
11
12pub use msg_sec_check::{Args, MsgSecCheckResult, Scene};
13
14use crate::client::WechatMinappSDK;
15
16#[derive(Debug, Deserialize_repr, Display, Serialize, PartialEq, Clone)]
17#[repr(i32)]
18pub enum Label {
19    #[strum(serialize = "正常")]
20    Normal = 100,
21
22    #[strum(serialize = "广告")]
23    Ad = 10001,
24
25    #[strum(serialize = "时政")]
26    Politics = 20001,
27
28    #[strum(serialize = "色情")]
29    Porn = 20002,
30
31    #[strum(serialize = "辱骂")]
32    Abuse = 20003,
33
34    #[strum(serialize = "违法犯罪")]
35    Illegal = 20006,
36
37    #[strum(serialize = "欺诈")]
38    Fraud = 20008,
39
40    #[strum(serialize = "低俗")]
41    Vulgar = 20012,
42
43    #[strum(serialize = "版权")]
44    Copyright = 20013,
45
46    #[strum(serialize = "其他")]
47    Other = 21000,
48}
49
50// 可选:为方便使用,可以添加一些辅助方法
51impl Label {
52    /// 根据数值获取对应的标签枚举
53    pub fn from_value(value: i32) -> Option<Self> {
54        match value {
55            100 => Some(Label::Normal),
56            10001 => Some(Label::Ad),
57            20001 => Some(Label::Politics),
58            20002 => Some(Label::Porn),
59            20003 => Some(Label::Abuse),
60            20006 => Some(Label::Illegal),
61            20008 => Some(Label::Fraud),
62            20012 => Some(Label::Vulgar),
63            20013 => Some(Label::Copyright),
64            21000 => Some(Label::Other),
65            _ => None,
66        }
67    }
68
69    /// 检查是否为正常内容
70    pub fn is_normal(&self) -> bool {
71        matches!(self, Label::Normal)
72    }
73
74    /// 检查是否为违规内容
75    pub fn is_violation(&self) -> bool {
76        !self.is_normal()
77    }
78}
79
80/// 内容安全检测建议
81#[derive(Debug, Deserialize, Serialize, Display, PartialEq, Clone)]
82pub enum Suggest {
83    #[strum(serialize = "risky")]
84    #[serde(rename = "risky")]
85    Risky,
86
87    #[strum(serialize = "pass")]
88    #[serde(rename = "pass")]
89    Pass,
90
91    #[strum(serialize = "review")]
92    #[serde(rename = "review")]
93    Review,
94}
95
96// 可选:为方便使用,可以添加一些辅助方法
97impl Suggest {
98    /// 检查是否通过
99    pub fn is_pass(&self) -> bool {
100        matches!(self, Suggest::Pass)
101    }
102
103    /// 检查是否有风险
104    pub fn is_risky(&self) -> bool {
105        matches!(self, Suggest::Risky)
106    }
107
108    /// 检查是否需要人工审核
109    pub fn needs_review(&self) -> bool {
110        matches!(self, Suggest::Review)
111    }
112
113    /// 获取建议的优先级(数值越小优先级越高)
114    pub fn priority(&self) -> u8 {
115        match self {
116            Suggest::Risky => 1,  // 最高优先级:有风险
117            Suggest::Review => 2, // 中等优先级:需要审核
118            Suggest::Pass => 3,   // 最低优先级:通过
119        }
120    }
121}
122
123impl From<&str> for Suggest {
124    fn from(s: &str) -> Self {
125        match s.to_lowercase().as_str() {
126            "risky" => Suggest::Risky,
127            "pass" => Suggest::Pass,
128            "review" => Suggest::Review,
129            _ => Suggest::Review,
130        }
131    }
132}
133
134pub struct MinappSecurity {
135    pub client: WechatMinappSDK,
136}
137
138impl MinappSecurity {
139    pub fn new(client: WechatMinappSDK) -> Self {
140        MinappSecurity { client }
141    }
142}
143
144#[cfg(test)]
145mod tests {
146    use super::*;
147
148    #[test]
149    fn test_suggest_enum() {
150        // 测试显示功能
151        assert_eq!(Suggest::Risky.to_string(), "risky");
152        assert_eq!(Suggest::Pass.to_string(), "pass");
153        assert_eq!(Suggest::Review.to_string(), "review");
154
155        // 测试从字符串创建
156        assert_eq!(Suggest::from("risky"), Suggest::Risky);
157        assert_eq!(Suggest::from("PASS"), Suggest::Pass);
158        assert_eq!(Suggest::from("ReViEw"), Suggest::Review);
159        assert_eq!(Suggest::from("invalid"), Suggest::Review);
160
161        // 测试辅助方法
162        assert!(Suggest::Pass.is_pass());
163        assert!(Suggest::Risky.is_risky());
164        assert!(Suggest::Review.needs_review());
165
166        // 测试优先级
167        assert_eq!(Suggest::Risky.priority(), 1);
168        assert_eq!(Suggest::Review.priority(), 2);
169        assert_eq!(Suggest::Pass.priority(), 3);
170    }
171
172    #[test]
173    fn test_serialization() {
174        // 测试序列化
175        let risky_json = serde_json::to_string(&Suggest::Risky).unwrap();
176        assert_eq!(risky_json, "\"risky\"");
177
178        let pass_json = serde_json::to_string(&Suggest::Pass).unwrap();
179        assert_eq!(pass_json, "\"pass\"");
180
181        // 测试反序列化
182        let review: Suggest = serde_json::from_str("\"review\"").unwrap();
183        assert_eq!(review, Suggest::Review);
184    }
185}