Skip to main content

fishpi_sdk/model/
notice.rs

1use serde::Deserialize;
2use serde_json::Value;
3
4use crate::model::article::ArticleTag;
5use crate::model::bool_from_int;
6use crate::{impl_str_enum, utils::error::Error};
7
8/// 数据类型
9#[derive(Debug, Clone)]
10#[repr(u8)]
11pub enum Notice {
12    /// 文章
13    Article = 0,
14    /// 评论
15    Comment = 1,
16    /// @
17    At = 2,
18    /// 被评论
19    Commented = 3,
20    /// 关注者
21    FollowingUser = 4,
22    /// 积分 - 充值
23    PointCharge = 5,
24    /// 积分 - 转账
25    PointTransfer = 6,
26    /// 积分 - 文章打赏
27    PointArticleReward = 7,
28    /// 积分 - 评论感谢
29    PointCommentThank = 8,
30    /// 同城广播
31    Broadcast = 9,
32    /// 积分 - 交易
33    PointExchange = 10,
34    /// 积分 - 滥用扣除
35    AbusePointDeduct = 11,
36    /// 积分 - 文章被感谢
37    PointArticleThank = 12,
38    /// 回复
39    Reply = 13,
40    /// 使用邀请码
41    InvitecodeUsed = 14,
42    /// 系统公告 - 文章
43    SysAnnounceArticle = 15,
44    /// 系统公告 - 新用户
45    SysAnnounceNewUser = 16,
46    /// 新的关注者
47    NewFollower = 17,
48    /// 邀请链接
49    InvitationLinkUsed = 18,
50    /// 系统通知 - 角色变化
51    SysAnnounceRoleChanged = 19,
52    /// 关注的文章更新
53    FollowingArticleUpdate = 20,
54    /// 关注的文章评论
55    FollowingArticleComment = 21,
56    /// 积分 - 文章优选
57    PointPerfectArticle = 22,
58    /// 文章新的被关注者
59    ArticleNewFollower = 23,
60    /// 文章新的关注者
61    ArticleNewWatcher = 24,
62    /// 评论点赞
63    CommentVoteUp = 25,
64    /// 评论点踩
65    CommentVoteDown = 26,
66    /// 文章被点赞
67    ArticleVoteUp = 27,
68    /// 文章被点踩
69    ArticleVoteDown = 28,
70    /// 积分 - 评论被接受
71    PointCommentAccept = 33,
72    /// 积分 - 举报处理
73    PointReportHandled = 36,
74    /// 聊天室 @
75    ChatRoomAt = 38,
76    /// 专属红包提醒
77    RedPacket = 39,
78}
79
80/// 通知类型
81#[derive(Debug, Clone)]
82pub enum NoticeType {
83    Point,
84    Commented,
85    Reply,
86    At,
87    Following,
88    Broadcast,
89    System,
90}
91
92impl_str_enum!(NoticeType {
93    Point => "point",
94    Commented => "commented",
95    Reply => "reply",
96    At => "at",
97    Following => "following",
98    Broadcast => "broadcast",
99    System => "sys-announce",
100});
101
102#[derive(Clone, Debug, Deserialize)]
103#[allow(non_snake_case)]
104pub struct NoticeCount {
105    /// 用户是否启用 Web 通知
106    #[serde(rename = "userNotifyStatus", deserialize_with = "bool_from_int")]
107    pub notifyStatus: bool,
108    /// 未读通知数
109    #[serde(rename = "unreadNotificationCnt")]
110    pub count: u64,
111    /// 未读回复通知数
112    #[serde(rename = "unreadReplyNotificationCnt")]
113    pub reply: u64,
114    /// 未读积分通知数
115    #[serde(rename = "unreadPointNotificationCnt")]
116    pub point: u64,
117    /// 未读 @ 通知数
118    #[serde(rename = "unreadAtNotificationCnt")]
119    pub at: u64,
120    /// 未读同城通知数
121    #[serde(rename = "unreadBroadcastNotificationCnt")]
122    pub broadcast: u64,
123    /// 未读系统通知数
124    #[serde(rename = "unreadSysAnnounceNotificationCnt")]
125    pub sysAnnounce: u64,
126    /// 未读关注者通知数
127    #[serde(rename = "unreadNewFollowerNotificationCnt")]
128    pub newFollower: u64,
129    /// 未读关注通知数
130    #[serde(rename = "unreadFollowingNotificationCnt")]
131    pub following: u64,
132    /// 未读评论通知数
133    #[serde(rename = "unreadCommentedNotificationCnt")]
134    pub commented: u64,
135}
136
137impl NoticeCount {
138    pub fn from_value(data: &Value) -> Result<Self, Error> {
139        serde_json::from_value(data.clone())
140            .map_err(|e| Error::Parse(format!("Failed to parse NoticeCount: {}", e)))
141    }
142}
143
144/// 积分通知
145#[derive(Clone, Debug, Deserialize)]
146#[allow(non_snake_case)]
147pub struct NoticePoint {
148    /// 通知 ID
149    pub oId: String,
150    /// 数据ID
151    pub dataId: String,
152    /// 用户ID
153    pub userId: String,
154    /// 数据类型
155    pub dataType: u32,
156    /// 通知描述
157    pub description: String,
158    /// 是否已读
159    pub hasRead: bool,
160    /// 创建时间
161    pub createTime: String,
162}
163
164impl NoticePoint {
165    pub fn from_value(data: &Value) -> Result<Self, Error> {
166        serde_json::from_value(data.clone())
167            .map_err(|e| Error::Parse(format!("Failed to parse NoticePoint: {}", e)))
168    }
169}
170
171/// 评论/回帖通知
172#[derive(Clone, Debug, Deserialize)]
173#[allow(non_snake_case)]
174pub struct NoticeComment {
175    /// 通知 id
176    pub oId: String,
177    /// 文章标题
178    #[serde(rename = "commentArticleTitle")]
179    pub title: String,
180    /// 文章作者
181    #[serde(rename = "commentAuthorName")]
182    pub author: String,
183    /// 作者头像
184    #[serde(rename = "commentAuthorThumbnailURL")]
185    pub thumbnailURL: String,
186    /// 文章类型
187    #[serde(rename = "commentArticleType")]
188    pub type_: u32,
189    /// 是否精选
190    #[serde(rename = "commentArticlePerfect", deserialize_with = "bool_from_int")]
191    pub perfect: bool,
192    /// 评论内容
193    #[serde(rename = "commentContent")]
194    pub content: String,
195    /// 评论地址
196    #[serde(rename = "commentSharpURL")]
197    pub sharpURL: String,
198    /// 是否已读
199    pub hasRead: bool,
200    /// 评论时间
201    pub createTime: String,
202}
203
204impl NoticeComment {
205    pub fn from_value(data: &Value) -> Result<Self, Error> {
206        serde_json::from_value(data.clone())
207            .map_err(|e| Error::Parse(format!("Failed to parse NoticeComment: {}", e)))
208    }
209}
210
211/// 提到我通知
212#[derive(Clone, Debug, Deserialize)]
213#[allow(non_snake_case)]
214pub struct NoticeAt {
215    /// 通知 id
216    pub oId: String,
217    /// 数据类型
218    pub dataType: u32,
219    /// 用户名
220    pub userName: String,
221    /// 用户头像
222    #[serde(rename = "userAvatarURL")]
223    pub avatarURL: String,
224    /// 通知内容
225    pub content: String,
226    /// 是否已读
227    pub hasRead: bool,
228    /// 创建时间
229    pub createTime: String,
230}
231
232impl NoticeAt {
233    pub fn from_value(data: &Value) -> Result<Self, Error> {
234        serde_json::from_value(data.clone())
235            .map_err(|e| Error::Parse(format!("Failed to parse NoticeAt: {}", e)))
236    }
237}
238
239/// 关注通知
240#[derive(Clone, Debug, Deserialize)]
241#[allow(non_snake_case)]
242pub struct NoticeFollow {
243    /// 通知 Id
244    pub oId: String,
245    /// 文章地址
246    pub url: String,
247    /// 数据类型
248    pub dataType: u32,
249    /// 文章标题
250    #[serde(rename = "articleTitle")]
251    pub title: String,
252    /// 作者
253    #[serde(rename = "authorName")]
254    pub author: String,
255    /// 通知内容
256    pub content: String,
257    /// 是否评论
258    pub isComment: bool,
259    /// 作者头像
260    pub thumbnailURL: String,
261    /// 文章评论数
262    #[serde(rename = "articleCommentCount")]
263    pub commentCnt: u32,
264    /// 是否精选
265    #[serde(rename = "articlePerfect", deserialize_with = "bool_from_int")]
266    pub perfect: bool,
267    /// 文章标签列表
268    #[serde(rename = "articleTagObjs")]
269    pub tagObjs: Vec<ArticleTag>,
270    /// 文章标签
271    #[serde(rename = "articleTags")]
272    pub tags: String,
273    /// 文章类型
274    #[serde(rename = "articleType")]
275    pub type_: u32,
276    /// 是否已读
277    pub hasRead: bool,
278    /// 通知创建时间
279    pub createTime: String,
280}
281
282impl NoticeFollow {
283    pub fn from_value(data: &Value) -> Result<Self, Error> {
284        serde_json::from_value(data.clone())
285            .map_err(|e| Error::Parse(format!("Failed to parse NoticeFollow: {}", e)))
286    }
287}
288
289/// 系统通知数据
290#[derive(Clone, Debug, Deserialize)]
291#[allow(non_snake_case)]
292pub struct NoticeSystem {
293    /// 消息的 oId
294    pub oId: String,
295    /// 用户 Id
296    pub userId: String,
297    /// 数据 Id
298    pub dataId: String,
299    /// 数据类型
300    pub dataType: u32,
301    /// 消息描述
302    pub description: String,
303    /// 是否已读
304    pub hasRead: bool,
305    /// 创建日期
306    pub createTime: String,
307}
308
309impl NoticeSystem {
310    pub fn from_value(data: &Value) -> Result<Self, Error> {
311        serde_json::from_value(data.clone())
312            .map_err(|e| Error::Parse(format!("Failed to parse NoticeSystem: {}", e)))
313    }
314}
315
316/// 通知消息类型
317#[derive(Debug, Clone)]
318pub enum NoticeMsgType {
319    /// 刷新通知数,需调用 Notice.count 获取明细
320    Refresh,
321    /// 全局公告
322    WarnBroadcast,
323}
324
325impl NoticeMsgType {
326    pub fn values() -> Vec<&'static str> {
327        vec!["refreshNotification", "warnBroadcast"]
328    }
329}
330
331impl_str_enum!(NoticeMsgType {
332    Refresh => "refreshNotification",
333    WarnBroadcast => "warnBroadcast",
334});
335
336/// 通知消息
337#[derive(Clone, Debug, Deserialize)]
338#[allow(non_snake_case)]
339pub struct NoticeMsg {
340    /// 通知类型
341    pub command: String,
342    /// 通知接收者用户Id
343    pub userId: String,
344    /// 全局公告内容,仅 `warnBroadcast` 有信息
345    #[serde(rename = "warnBroadcastText")]
346    pub content: Option<String>,
347    /// 全局公告发布者,仅 `warnBroadcast` 有信息
348    pub who: Option<String>,
349}
350
351impl NoticeMsg {
352    pub fn from_value(data: &Value) -> Result<Self, Error> {
353        serde_json::from_value(data.clone())
354            .map_err(|e| Error::Parse(format!("Failed to parse NoticeMsg: {}", e)))
355    }
356}
357
358/// 通知项联合类型
359#[derive(Clone, Debug)]
360pub enum NoticeItem {
361    /// 积分通知
362    Point(NoticePoint),
363    /// 评论/回帖通知
364    Comment(NoticeComment),
365    /// 提到我通知
366    At(NoticeAt),
367    /// 关注通知
368    Follow(NoticeFollow),
369    /// 系统通知数据
370    System(NoticeSystem),
371}
372
373pub type NoticeList = Vec<NoticeItem>;
374
375impl NoticeItem {
376    pub fn from_value(data: &Value, notice_type: &NoticeType) -> Result<Self, Error> {
377        match notice_type {
378            NoticeType::Point => Ok(NoticeItem::Point(NoticePoint::from_value(data)?)),
379            NoticeType::Commented => Ok(NoticeItem::Comment(NoticeComment::from_value(data)?)),
380            NoticeType::At => Ok(NoticeItem::At(NoticeAt::from_value(data)?)),
381            NoticeType::Following => Ok(NoticeItem::Follow(NoticeFollow::from_value(data)?)),
382            NoticeType::System => Ok(NoticeItem::System(NoticeSystem::from_value(data)?)),
383            _ => Err(Error::Parse("Unsupported notice type".to_string())),
384        }
385    }
386}