1use common::v1::types::Mentions;
2use common::v1::types::{
3 util::Time, Channel, ChannelId, ChannelType, ChannelVerId, Embed, MediaId, MessageId,
4 MessageType, MessageVerId, Permission, Puppet, RoleId, Room, RoomId, RoomMembership, RoomType,
5 Session, SessionStatus, SessionToken, SessionType, ThreadMembership, UserId,
6};
7use serde::{Deserialize, Serialize};
8use std::str::FromStr;
9use time::PrimitiveDateTime;
10use uuid::Uuid;
11
12pub use common::v1::types::ids::*;
13pub use common::v1::types::misc::{SessionIdReq, UserIdReq};
14
15pub struct DbRoom {
16 pub id: Uuid,
17 pub version_id: Uuid,
18 pub owner_id: Option<Uuid>,
19 pub name: String,
20 pub description: Option<String>,
21 pub icon: Option<Uuid>,
22 pub archived_at: Option<PrimitiveDateTime>,
23 pub public: bool,
24 pub ty: DbRoomType,
25 pub welcome_channel_id: Option<Uuid>,
26 pub member_count: i64,
27 pub channel_count: i64,
28 pub quarantined: bool,
29}
30
31pub struct DbRoomCreate {
32 pub id: Option<RoomId>,
33 pub ty: RoomType,
34 pub welcome_channel_id: Option<ChannelId>,
35}
36
37pub struct DbUserCreate {
38 pub id: Option<UserId>,
39 pub parent_id: Option<UserId>,
40 pub name: String,
41 pub description: Option<String>,
42 pub puppet: Option<Puppet>,
43 pub registered_at: Option<Time>,
44 pub system: bool,
45}
46
47#[derive(sqlx::Type, PartialEq)]
48#[sqlx(type_name = "membership")]
49pub enum DbMembership {
50 Join,
51 Leave,
52 Ban, }
54
55impl From<DbRoom> for Room {
56 fn from(row: DbRoom) -> Self {
57 #[allow(deprecated)]
58 Room {
59 id: row.id.into(),
60 version_id: row.version_id,
61 owner_id: row.owner_id.map(Into::into),
62 name: row.name,
63 description: row.description,
64 icon: row.icon.map(|i| i.into()),
65 room_type: row.ty.into(),
66 archived_at: row.archived_at.map(|t| Time::from(t.assume_utc())),
67 public: row.public,
68 welcome_channel_id: row.welcome_channel_id.map(|i| i.into()),
69 quarantined: row.quarantined,
70 member_count: row.member_count as u64,
71 online_count: Default::default(),
72 channel_count: row.channel_count as u64,
73 user_config: None,
74 }
75 }
76}
77
78#[derive(Debug, Deserialize)]
79pub struct DbChannel {
80 pub id: ChannelId,
81 pub room_id: Option<Uuid>,
82 pub creator_id: UserId,
83 pub owner_id: Option<Uuid>,
84 pub version_id: ChannelVerId,
85 pub name: String,
86 pub description: Option<String>,
87 pub icon: Option<Uuid>,
88 pub ty: DbChannelType,
89 pub last_version_id: Option<Uuid>,
90 pub message_count: i64,
91 pub member_count: i64,
92 pub permission_overwrites: serde_json::Value,
93 pub nsfw: bool,
94 pub locked: bool,
95 pub archived_at: Option<PrimitiveDateTime>,
96 pub deleted_at: Option<PrimitiveDateTime>,
97 pub parent_id: Option<Uuid>,
98 pub position: Option<i32>,
99 pub bitrate: Option<i32>,
100 pub user_limit: Option<i32>,
101}
102
103#[derive(Debug, Deserialize, Clone)]
104pub struct DbChannelPrivate {
105 pub id: ChannelId,
106 pub ty: DbChannelType,
107 pub last_read_id: Option<Uuid>,
108 pub is_unread: bool,
109}
110
111pub struct DbChannelCreate {
112 pub room_id: Option<Uuid>,
113 pub creator_id: UserId,
114 pub owner_id: Option<Uuid>,
115 pub name: String,
116 pub description: Option<String>,
117 pub icon: Option<Uuid>,
118 pub ty: DbChannelType,
119 pub nsfw: bool,
120 pub bitrate: Option<i32>,
121 pub user_limit: Option<i32>,
122 pub parent_id: Option<Uuid>,
123}
124
125#[derive(sqlx::Type, Debug, Deserialize, PartialEq, Eq, Clone, Copy)]
126#[sqlx(type_name = "channel_type")]
127pub enum DbChannelType {
128 Text,
129 Forum,
130 Voice,
131 Dm,
132 Gdm,
133 Category,
134 ThreadPublic,
135 ThreadPrivate,
136}
137
138impl From<DbChannelType> for ChannelType {
139 fn from(value: DbChannelType) -> Self {
140 match value {
141 DbChannelType::Text => ChannelType::Text,
142 DbChannelType::Forum => ChannelType::Forum,
143 DbChannelType::Voice => ChannelType::Voice,
144 DbChannelType::Dm => ChannelType::Dm,
145 DbChannelType::Gdm => ChannelType::Gdm,
146 DbChannelType::Category => ChannelType::Category,
147 DbChannelType::ThreadPublic => ChannelType::ThreadPublic,
148 DbChannelType::ThreadPrivate => ChannelType::ThreadPrivate,
149 }
150 }
151}
152
153impl From<DbChannel> for Channel {
154 fn from(row: DbChannel) -> Self {
155 Channel {
156 id: row.id,
157 room_id: row.room_id.map(Into::into),
158 creator_id: row.creator_id,
159 version_id: row.version_id,
160 name: row.name,
161 description: row.description,
162 icon: row.icon.map(|i| i.into()),
163 nsfw: row.nsfw,
164 locked: row.locked,
165 member_count: row.member_count.try_into().expect("count is negative?"),
166 permission_overwrites: serde_json::from_value(row.permission_overwrites).unwrap(),
167 archived_at: row.archived_at.map(|t| t.into()),
168 deleted_at: row.deleted_at.map(|t| t.into()),
169 ty: row.ty.into(),
170 last_version_id: row.last_version_id.map(|i| i.into()),
171 message_count: Some(row.message_count.try_into().expect("count is negative?")),
172 parent_id: row.parent_id.map(|i| i.into()),
173 position: row
174 .position
175 .map(|p| p.try_into().expect("position is negative or overflows?")),
176 bitrate: row.bitrate.map(|i| i as u64),
177 user_limit: row.user_limit.map(|i| i as u64),
178 owner_id: row.owner_id.map(|i| i.into()),
179
180 is_unread: None,
182 last_read_id: None,
183 mention_count: None,
184 recipients: vec![],
185 user_config: None,
186 online_count: 0,
187
188 tags: Default::default(),
190 root_message_count: None,
191 }
192 }
193}
194
195pub struct DbSession {
196 pub id: Uuid,
197 pub user_id: Option<Uuid>,
198 pub token: SessionToken,
199 pub status: DbSessionStatus,
200 pub name: Option<String>,
201 pub expires_at: Option<PrimitiveDateTime>,
202 pub ty: String,
203 pub application_id: Option<Uuid>,
204 pub last_seen_at: PrimitiveDateTime,
205}
206
207pub struct DbSessionCreate {
208 pub token: SessionToken,
209 pub name: Option<String>,
210 pub expires_at: Option<Time>,
211 pub ty: SessionType,
212 pub application_id: Option<ApplicationId>,
213}
214
215#[derive(sqlx::Type)]
216#[sqlx(type_name = "session_status")]
217pub enum DbSessionStatus {
218 Unauthorized,
219 Authorized,
220 Sudo,
221}
222
223impl From<DbSession> for Session {
224 fn from(row: DbSession) -> Self {
225 Session {
226 id: row.id.into(),
227 status: match row.status {
228 DbSessionStatus::Unauthorized => SessionStatus::Unauthorized,
229 DbSessionStatus::Authorized => SessionStatus::Authorized {
230 user_id: row.user_id.expect("invalid data in db!").into(),
231 },
232 DbSessionStatus::Sudo => SessionStatus::Sudo {
233 user_id: row.user_id.expect("invalid data in db!").into(),
234 sudo_expires_at: Time::now_utc(),
235 },
236 },
237 name: row.name,
238 expires_at: row.expires_at.map(|t| t.into()),
239 ty: SessionType::from_str(&row.ty).unwrap_or(SessionType::User),
240 app_id: row.application_id.map(Into::into),
241 last_seen_at: row.last_seen_at.into(),
242 }
243 }
244}
245
246impl From<SessionStatus> for DbSessionStatus {
247 fn from(value: SessionStatus) -> Self {
248 match value {
249 SessionStatus::Unauthorized => DbSessionStatus::Unauthorized,
250 SessionStatus::Authorized { .. } => DbSessionStatus::Authorized,
251 SessionStatus::Sudo { .. } => DbSessionStatus::Sudo,
252 }
253 }
254}
255
256pub struct DbRoleCreate {
257 pub id: RoleId,
258 pub room_id: RoomId,
259 pub name: String,
260 pub description: Option<String>,
261 pub permissions: Vec<Permission>,
262 pub is_self_applicable: bool,
263 pub is_mentionable: bool,
264}
265
266pub struct DbMessageCreate {
267 pub channel_id: ChannelId,
268 pub attachment_ids: Vec<MediaId>,
269 pub author_id: UserId,
270 pub embeds: Vec<Embed>,
271 pub message_type: MessageType,
272 pub edited_at: Option<time::PrimitiveDateTime>,
273 pub created_at: Option<time::PrimitiveDateTime>,
274 pub mentions: Mentions,
275}
276
277impl DbMessageCreate {
279 pub fn content(&self) -> Option<String> {
280 match &self.message_type {
281 MessageType::DefaultMarkdown(msg) => msg.content.clone(),
282 _ => None,
283 }
284 }
285
286 pub fn metadata(&self) -> Option<serde_json::Value> {
287 match &self.message_type {
288 MessageType::DefaultMarkdown(msg) => msg.metadata.clone(),
289 MessageType::ThreadRename(patch) => Some(serde_json::to_value(patch).ok()?),
290 MessageType::MemberAdd(patch) => Some(serde_json::to_value(patch).ok()?),
291 MessageType::MemberRemove(patch) => Some(serde_json::to_value(patch).ok()?),
292 MessageType::MemberJoin => None,
293 MessageType::MessagePinned(pinned) => Some(serde_json::to_value(pinned).ok()?),
294 _ => None,
295 }
296 }
297
298 pub fn reply_id(&self) -> Option<MessageId> {
299 match &self.message_type {
300 MessageType::DefaultMarkdown(msg) => msg.reply_id,
301 _ => None,
302 }
303 }
304
305 pub fn override_name(&self) -> Option<String> {
306 match &self.message_type {
307 MessageType::DefaultMarkdown(msg) => msg.override_name.clone(),
308 _ => None,
309 }
310 }
311}
312
313macro_rules! impl_perms {
314 ($($e:ident,)*) => {
315 #[derive(Debug, sqlx::Type, PartialEq, Eq)]
316 #[sqlx(type_name = "permission")]
317 pub enum DbPermission {
318 $($e,)*
319 }
320
321 impl From<DbPermission> for Permission {
322 fn from(value: DbPermission) -> Self {
323 match value {
324 $(DbPermission::$e => Permission::$e,)*
325 }
326 }
327 }
328
329 impl From<Permission> for DbPermission {
330 fn from(value: Permission) -> Self {
331 match value {
332 $(Permission::$e => DbPermission::$e,)*
333 }
334 }
335 }
336 }
337}
338
339impl_perms!(
341 Admin,
342 IntegrationsManage,
343 EmojiManage,
344 EmojiUseExternal,
345 InviteCreate,
346 InviteManage,
347 MemberBan,
348 MemberBridge,
349 MemberKick,
350 MemberNicknameManage,
351 MemberTimeout,
352 MessageCreate,
353 MessageDelete,
354 MessageRemove,
355 MessageEmbeds,
356 MessageMassMention,
357 MessageAttachments,
358 MessageMove,
359 MessagePin,
360 ReactionAdd,
361 ReactionPurge,
362 MemberNickname,
363 RoleApply,
364 RoleManage,
365 RoomManage,
366 ServerMetrics,
367 ServerOversee,
368 ServerReports,
369 TagApply,
370 TagManage,
371 ThreadCreatePublic,
372 ThreadCreatePrivate,
373 ThreadEdit,
374 ThreadLock,
375 ThreadManage,
376 ViewChannel,
377 ViewAuditLog,
378 VoiceConnect,
379 VoiceDeafen,
380 VoiceDisconnect,
381 VoiceMove,
382 VoiceMute,
383 VoicePriority,
384 VoiceSpeak,
385 VoiceVideo,
386 ChannelManage,
387 ChannelEdit,
388 CalendarEventManage,
389);
390
391impl From<RoomMembership> for DbMembership {
392 fn from(value: RoomMembership) -> Self {
393 match value {
394 RoomMembership::Join => DbMembership::Join,
395 RoomMembership::Leave => DbMembership::Leave,
396 }
397 }
398}
399
400impl From<ThreadMembership> for DbMembership {
401 fn from(value: ThreadMembership) -> Self {
402 match value {
403 ThreadMembership::Join => DbMembership::Join,
404 ThreadMembership::Leave => DbMembership::Leave,
405 }
406 }
407}
408
409pub struct DbInvite {
410 pub code: String,
411 pub target_type: String,
412 pub target_id: Option<Uuid>,
413 pub creator_id: Uuid,
414 pub max_uses: Option<i32>,
415 pub uses: i32,
416 pub created_at: time::PrimitiveDateTime,
417 pub expires_at: Option<time::PrimitiveDateTime>,
418 pub description: Option<String>,
419}
420
421#[derive(Deserialize)]
422pub struct RoleDeleteQuery {
423 #[serde(default)]
424 pub force: bool,
425}
426
427#[derive(sqlx::Type, PartialEq, Eq)]
428#[sqlx(type_name = "media_link_type")]
429pub enum MediaLinkType {
430 Message,
431 MessageVersion,
432 AvatarUser,
433 BannerUser,
434 IconThread,
436 AvatarRoom,
437 Embed,
438 CustomEmoji,
439}
440
441pub struct MediaLink {
443 pub media_id: MediaId,
444 pub target_id: Uuid,
445 pub link_type: MediaLinkType,
446}
447
448#[derive(Debug, sqlx::FromRow)]
449pub struct UrlEmbedQueue {
450 pub id: Uuid,
451 pub message_ref: Option<serde_json::Value>,
452 pub user_id: Uuid,
453 pub url: String,
454 pub created_at: PrimitiveDateTime,
455 pub claimed_at: Option<PrimitiveDateTime>,
456 pub finished_at: Option<PrimitiveDateTime>,
457}
458
459#[derive(Debug, sqlx::FromRow)]
460pub struct DbNotification {
461 pub id: Uuid,
462 pub channel_id: Uuid,
463 pub message_id: Uuid,
464 pub reason: String,
465 pub added_at: PrimitiveDateTime,
466 pub read_at: Option<PrimitiveDateTime>,
467}
468
469#[derive(Debug, Serialize, Deserialize)]
470pub struct MessageRef {
471 pub message_id: MessageId,
472 pub version_id: MessageVerId,
473 pub thread_id: ChannelId,
474}
475
476#[derive(sqlx::FromRow)]
477pub struct DbEmailQueue {
478 pub id: Uuid,
479 pub to_addr: String,
480 pub from_addr: String,
481 pub subject: String,
482 pub plain_text_body: String,
483 pub html_body: Option<String>,
484}
485
486pub enum EmailPurpose {
487 Authn,
489
490 Reset,
492}
493
494#[derive(sqlx::Type)]
495#[sqlx(type_name = "room_type")]
496pub enum DbRoomType {
497 Default,
498 Server,
499}
500
501impl Into<DbRoomType> for RoomType {
502 fn into(self) -> DbRoomType {
503 match self {
504 RoomType::Default => DbRoomType::Default,
505 RoomType::Server => DbRoomType::Server,
506 }
507 }
508}
509
510impl Into<RoomType> for DbRoomType {
511 fn into(self) -> RoomType {
512 match self {
513 DbRoomType::Default => RoomType::Default,
514 DbRoomType::Server => RoomType::Server,
515 }
516 }
517}