Skip to main content

longbridge/content/
types.rs

1use serde::{Deserialize, Serialize};
2use time::OffsetDateTime;
3
4use crate::serde_utils;
5
6/// Topic author
7#[derive(Debug, Clone, Serialize, Deserialize)]
8pub struct TopicAuthor {
9    /// Member ID
10    #[serde(default)]
11    pub member_id: String,
12    /// Display name
13    #[serde(default)]
14    pub name: String,
15    /// Avatar URL
16    #[serde(default)]
17    pub avatar: String,
18}
19
20/// Topic image
21#[derive(Debug, Clone, Serialize, Deserialize)]
22pub struct TopicImage {
23    /// Original image URL
24    #[serde(default)]
25    pub url: String,
26    /// Small thumbnail URL
27    #[serde(default)]
28    pub sm: String,
29    /// Large image URL
30    #[serde(default)]
31    pub lg: String,
32}
33
34/// My topic item (topic created by the current authenticated user)
35#[derive(Debug, Clone, Serialize, Deserialize)]
36pub struct OwnedTopic {
37    /// Topic ID
38    pub id: String,
39    /// Title
40    #[serde(default)]
41    pub title: String,
42    /// Plain text excerpt
43    #[serde(default)]
44    pub description: String,
45    /// Markdown body
46    #[serde(default)]
47    pub body: String,
48    /// Author
49    pub author: TopicAuthor,
50    /// Related stock tickers, format: {symbol}.{market}
51    #[serde(default)]
52    pub tickers: Vec<String>,
53    /// Hashtag names
54    #[serde(default)]
55    pub hashtags: Vec<String>,
56    /// Images
57    #[serde(default)]
58    pub images: Vec<TopicImage>,
59    /// Likes count
60    #[serde(default)]
61    pub likes_count: i32,
62    /// Comments count
63    #[serde(default)]
64    pub comments_count: i32,
65    /// Views count
66    #[serde(default)]
67    pub views_count: i32,
68    /// Shares count
69    #[serde(default)]
70    pub shares_count: i32,
71    /// Content type: "article" or "post"
72    #[serde(default)]
73    pub topic_type: String,
74    /// URL to the full topic page
75    #[serde(default)]
76    pub detail_url: String,
77    /// Created time
78    #[serde(
79        serialize_with = "time::serde::rfc3339::serialize",
80        deserialize_with = "serde_utils::timestamp::deserialize"
81    )]
82    pub created_at: OffsetDateTime,
83    /// Updated time
84    #[serde(
85        serialize_with = "time::serde::rfc3339::serialize",
86        deserialize_with = "serde_utils::timestamp::deserialize"
87    )]
88    pub updated_at: OffsetDateTime,
89}
90
91/// Options for listing topics created by the current authenticated user
92#[derive(Debug, Default, Clone, Serialize)]
93pub struct MyTopicsOptions {
94    /// Page number (default 1)
95    #[serde(skip_serializing_if = "Option::is_none")]
96    pub page: Option<i32>,
97    /// Records per page, range 1~500 (default 50)
98    #[serde(skip_serializing_if = "Option::is_none")]
99    pub size: Option<i32>,
100    /// Filter by topic type: "article" or "post"; empty returns all
101    #[serde(skip_serializing_if = "Option::is_none")]
102    pub topic_type: Option<String>,
103}
104
105/// Options for creating a topic
106#[derive(Debug, Clone, Serialize)]
107pub struct CreateTopicOptions {
108    /// Topic title (required)
109    pub title: String,
110    /// Topic body in Markdown format (required)
111    pub body: String,
112    /// Content type: "article" (long-form) or "post" (short post, default)
113    #[serde(skip_serializing_if = "Option::is_none")]
114    pub topic_type: Option<String>,
115    /// Related stock tickers, format: {symbol}.{market}, max 10
116    #[serde(skip_serializing_if = "Option::is_none")]
117    pub tickers: Option<Vec<String>>,
118    /// Hashtag names, max 5
119    #[serde(skip_serializing_if = "Option::is_none")]
120    pub hashtags: Option<Vec<String>>,
121}
122
123/// Topic item
124#[derive(Debug, Clone, Serialize, Deserialize)]
125pub struct TopicItem {
126    /// Topic ID
127    pub id: String,
128    /// Title
129    #[serde(default)]
130    pub title: String,
131    /// Description
132    #[serde(default)]
133    pub description: String,
134    /// URL
135    pub url: String,
136    /// Published time
137    #[serde(
138        serialize_with = "time::serde::rfc3339::serialize",
139        deserialize_with = "serde_utils::timestamp::deserialize"
140    )]
141    pub published_at: OffsetDateTime,
142    /// Comments count
143    pub comments_count: i32,
144    /// Likes count
145    pub likes_count: i32,
146    /// Shares count
147    pub shares_count: i32,
148}
149
150/// Options for listing replies on a topic
151#[derive(Debug, Default, Clone, Serialize)]
152pub struct ListTopicRepliesOptions {
153    /// Page number (default 1)
154    #[serde(skip_serializing_if = "Option::is_none")]
155    pub page: Option<i32>,
156    /// Records per page, range 1~50 (default 20)
157    #[serde(skip_serializing_if = "Option::is_none")]
158    pub size: Option<i32>,
159}
160
161/// Options for posting a reply to a topic
162#[derive(Debug, Clone, Serialize)]
163pub struct CreateReplyOptions {
164    /// Reply body. Plain text only — Markdown is not rendered.
165    ///
166    /// Stock symbols mentioned in the body (e.g. `700.HK`, `TSLA.US`) are
167    /// automatically recognized and linked as related stocks by the platform.
168    /// Use `tickers` in the parent topic to associate additional stocks not
169    /// mentioned in the body.
170    pub body: String,
171    /// ID of the reply to. Set to `None` to post a top-level reply.
172    #[serde(skip_serializing_if = "Option::is_none")]
173    pub reply_to_id: Option<String>,
174}
175
176/// A reply on a topic
177#[derive(Debug, Clone, Serialize, Deserialize)]
178pub struct TopicReply {
179    /// Reply ID
180    pub id: String,
181    /// Topic ID this reply belongs to
182    pub topic_id: String,
183    /// Reply body (plain text)
184    #[serde(default)]
185    pub body: String,
186    /// ID of the parent reply (`"0"` means top-level)
187    #[serde(default)]
188    pub reply_to_id: String,
189    /// Author info
190    pub author: TopicAuthor,
191    /// Attached images
192    #[serde(default)]
193    pub images: Vec<TopicImage>,
194    /// Likes count
195    #[serde(default)]
196    pub likes_count: i32,
197    /// Nested replies count
198    #[serde(default)]
199    pub comments_count: i32,
200    /// Created time
201    #[serde(
202        serialize_with = "time::serde::rfc3339::serialize",
203        deserialize_with = "serde_utils::timestamp::deserialize"
204    )]
205    pub created_at: OffsetDateTime,
206}
207
208/// News item
209#[derive(Debug, Clone, Serialize, Deserialize)]
210pub struct NewsItem {
211    /// News ID
212    pub id: String,
213    /// Title
214    #[serde(default)]
215    pub title: String,
216    /// Description
217    #[serde(default)]
218    pub description: String,
219    /// URL
220    pub url: String,
221    /// Published time
222    #[serde(
223        serialize_with = "time::serde::rfc3339::serialize",
224        deserialize_with = "serde_utils::timestamp::deserialize"
225    )]
226    pub published_at: OffsetDateTime,
227    /// Comments count
228    pub comments_count: i32,
229    /// Likes count
230    pub likes_count: i32,
231    /// Shares count
232    pub shares_count: i32,
233}