collie_core/model/
item.rs1use chrono::{DateTime, FixedOffset};
2use core::fmt::{self, Display, Formatter};
3use rusqlite::Row;
4use serde::{Deserialize, Serialize};
5use sha1_smol::Sha1;
6use std::str::FromStr;
7
8use crate::error::Error;
9
10#[derive(Serialize, Deserialize, Debug, Clone)]
11pub enum ItemStatus {
12 Unread,
13 Read,
14}
15
16impl Display for ItemStatus {
17 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
18 match self {
19 Self::Unread => write!(f, "unread"),
20 Self::Read => write!(f, "read"),
21 }
22 }
23}
24
25impl FromStr for ItemStatus {
26 type Err = Error;
27
28 fn from_str(x: &str) -> std::result::Result<Self, Self::Err> {
29 match x {
30 "unread" => Ok(Self::Unread),
31 "read" => Ok(Self::Read),
32 _ => Err(Error::InvalidEnumKey(
33 x.to_string(),
34 "ItemStatus".to_string(),
35 )),
36 }
37 }
38}
39
40#[derive(Serialize, Deserialize, Debug)]
41pub struct ItemFeed {
42 pub id: i32,
43 pub title: String,
44 pub link: String,
45}
46
47#[derive(Serialize, Deserialize, Debug)]
48pub struct Item {
49 pub id: i32,
50 pub fingerprint: String,
51 pub author: Option<String>,
52 pub title: String,
53 pub description: String,
54 pub link: String,
55 pub status: ItemStatus,
56 pub is_saved: bool,
57 pub published_at: DateTime<FixedOffset>,
58 pub feed: ItemFeed,
59}
60
61impl From<&Row<'_>> for Item {
62 fn from(row: &Row) -> Self {
63 Self {
64 id: row.get_unwrap("id"),
65 fingerprint: row.get_unwrap("fingerprint"),
66 author: row.get_unwrap("author"),
67 title: row.get_unwrap("title"),
68 description: row.get_unwrap("description"),
69 link: row.get_unwrap("link"),
70 status: ItemStatus::from_str(&row.get_unwrap::<&str, String>("status")).unwrap(),
71 is_saved: row.get_unwrap("is_saved"),
72 published_at: row.get_unwrap("published_at"),
73 feed: ItemFeed {
74 id: row.get_unwrap("feed_id"),
75 title: row.get_unwrap("feed_title"),
76 link: row.get_unwrap("feed_link"),
77 },
78 }
79 }
80}
81
82#[derive(Serialize, Deserialize, Debug)]
83pub struct ItemToCreate {
84 pub author: Option<String>,
85 pub title: String,
86 pub description: String,
87 pub link: String,
88 pub status: ItemStatus,
89 pub published_at: DateTime<FixedOffset>,
90 pub feed: i32,
91}
92
93impl ItemToCreate {
94 pub fn fingerprint(&self) -> String {
95 Sha1::from(format!("{}:{}", &self.title, &self.link)).hexdigest()
96 }
97}
98
99#[derive(Serialize, Deserialize)]
100pub struct ItemToUpdate {
101 pub id: i32,
102 pub status: Option<ItemStatus>,
103 pub is_saved: Option<bool>,
104}
105
106#[derive(Serialize, Deserialize)]
107pub struct ItemToUpdateAll {
108 pub status: Option<ItemStatus>,
109 pub is_saved: Option<bool>,
110 pub opt: Option<ItemReadOption>,
111}
112
113#[derive(Serialize, Deserialize)]
114pub enum ItemOrder {
115 ReceivedDateDesc,
116 PublishedDateDesc,
117 UnreadFirst,
118}
119
120#[derive(Serialize, Deserialize)]
121pub struct ItemReadOption {
122 pub ids: Option<Vec<i32>>,
123 pub feed: Option<i32>,
124 pub status: Option<ItemStatus>,
125 pub is_saved: Option<bool>,
126 pub order_by: Option<ItemOrder>,
127 pub limit: Option<u64>,
128 pub offset: Option<u64>,
129}