2021-04-09 00:22:17 +00:00
|
|
|
use chrono::{DateTime, Utc};
|
2021-11-19 17:32:51 +00:00
|
|
|
use postgres_types::FromSql;
|
2021-04-09 00:22:17 +00:00
|
|
|
use tokio_postgres::Row;
|
|
|
|
use uuid::Uuid;
|
|
|
|
|
2023-03-30 20:27:17 +00:00
|
|
|
use crate::attachments::types::DbMediaAttachment;
|
2022-12-03 22:09:42 +00:00
|
|
|
use crate::database::{
|
|
|
|
int_enum::{int_enum_from_sql, int_enum_to_sql},
|
2023-04-24 15:35:32 +00:00
|
|
|
DatabaseError, DatabaseTypeError,
|
2022-12-03 22:09:42 +00:00
|
|
|
};
|
2023-03-30 20:27:17 +00:00
|
|
|
use crate::emojis::types::DbEmoji;
|
|
|
|
use crate::profiles::types::DbActorProfile;
|
2021-04-09 00:22:17 +00:00
|
|
|
|
2022-01-08 18:49:39 +00:00
|
|
|
#[derive(Clone, Debug, PartialEq)]
|
2021-11-18 21:48:49 +00:00
|
|
|
pub enum Visibility {
|
|
|
|
Public,
|
|
|
|
Direct,
|
2022-01-05 18:47:02 +00:00
|
|
|
Followers,
|
2022-01-15 23:21:13 +00:00
|
|
|
Subscribers,
|
2021-11-18 21:48:49 +00:00
|
|
|
}
|
|
|
|
|
2021-11-24 16:39:30 +00:00
|
|
|
impl Default for Visibility {
|
2023-04-24 15:35:32 +00:00
|
|
|
fn default() -> Self {
|
|
|
|
Self::Public
|
|
|
|
}
|
2021-11-24 16:39:30 +00:00
|
|
|
}
|
|
|
|
|
2021-11-18 21:48:49 +00:00
|
|
|
impl From<&Visibility> for i16 {
|
|
|
|
fn from(value: &Visibility) -> i16 {
|
|
|
|
match value {
|
|
|
|
Visibility::Public => 1,
|
|
|
|
Visibility::Direct => 2,
|
2022-01-05 18:47:02 +00:00
|
|
|
Visibility::Followers => 3,
|
2022-01-15 23:21:13 +00:00
|
|
|
Visibility::Subscribers => 4,
|
2021-11-18 21:48:49 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl TryFrom<i16> for Visibility {
|
2022-12-03 22:09:42 +00:00
|
|
|
type Error = DatabaseTypeError;
|
2021-11-18 21:48:49 +00:00
|
|
|
|
|
|
|
fn try_from(value: i16) -> Result<Self, Self::Error> {
|
|
|
|
let visibility = match value {
|
|
|
|
1 => Self::Public,
|
|
|
|
2 => Self::Direct,
|
2022-01-05 18:47:02 +00:00
|
|
|
3 => Self::Followers,
|
2022-01-15 23:21:13 +00:00
|
|
|
4 => Self::Subscribers,
|
2022-12-03 22:09:42 +00:00
|
|
|
_ => return Err(DatabaseTypeError),
|
2021-11-18 21:48:49 +00:00
|
|
|
};
|
|
|
|
Ok(visibility)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-11-19 17:32:51 +00:00
|
|
|
int_enum_from_sql!(Visibility);
|
|
|
|
int_enum_to_sql!(Visibility);
|
2021-11-18 21:48:49 +00:00
|
|
|
|
2021-04-09 00:22:17 +00:00
|
|
|
#[derive(FromSql)]
|
|
|
|
#[postgres(name = "post")]
|
|
|
|
pub struct DbPost {
|
|
|
|
pub id: Uuid,
|
|
|
|
pub author_id: Uuid,
|
|
|
|
pub content: String,
|
2021-09-22 16:32:44 +00:00
|
|
|
pub in_reply_to_id: Option<Uuid>,
|
2021-11-24 16:39:30 +00:00
|
|
|
pub repost_of_id: Option<Uuid>,
|
2021-11-18 21:48:49 +00:00
|
|
|
pub visibility: Visibility,
|
2023-04-15 23:43:19 +00:00
|
|
|
pub is_sensitive: bool,
|
2021-09-24 14:02:56 +00:00
|
|
|
pub reply_count: i32,
|
2021-10-17 16:55:33 +00:00
|
|
|
pub reaction_count: i32,
|
2021-11-24 16:39:30 +00:00
|
|
|
pub repost_count: i32,
|
2021-10-08 22:39:40 +00:00
|
|
|
pub object_id: Option<String>,
|
2021-04-09 00:22:17 +00:00
|
|
|
pub ipfs_cid: Option<String>,
|
|
|
|
pub token_id: Option<i32>,
|
|
|
|
pub token_tx_id: Option<String>,
|
|
|
|
pub created_at: DateTime<Utc>,
|
2022-07-08 19:54:12 +00:00
|
|
|
pub updated_at: Option<DateTime<Utc>>, // edited at
|
2021-04-09 00:22:17 +00:00
|
|
|
}
|
|
|
|
|
2021-10-18 22:35:52 +00:00
|
|
|
// List of user's actions
|
2021-12-09 14:50:01 +00:00
|
|
|
#[derive(Clone)]
|
2021-10-18 22:35:52 +00:00
|
|
|
pub struct PostActions {
|
|
|
|
pub favourited: bool,
|
2021-11-24 16:39:30 +00:00
|
|
|
pub reposted: bool,
|
2021-10-18 22:35:52 +00:00
|
|
|
}
|
|
|
|
|
2021-12-09 14:50:01 +00:00
|
|
|
#[derive(Clone)]
|
2021-04-09 00:22:17 +00:00
|
|
|
pub struct Post {
|
|
|
|
pub id: Uuid,
|
|
|
|
pub author: DbActorProfile,
|
|
|
|
pub content: String,
|
2021-09-22 16:32:44 +00:00
|
|
|
pub in_reply_to_id: Option<Uuid>,
|
2021-11-24 16:39:30 +00:00
|
|
|
pub repost_of_id: Option<Uuid>,
|
2021-11-18 21:48:49 +00:00
|
|
|
pub visibility: Visibility,
|
2023-04-15 23:43:19 +00:00
|
|
|
pub is_sensitive: bool,
|
2021-09-24 14:02:56 +00:00
|
|
|
pub reply_count: i32,
|
2021-10-17 16:55:33 +00:00
|
|
|
pub reaction_count: i32,
|
2021-11-24 16:39:30 +00:00
|
|
|
pub repost_count: i32,
|
2021-04-09 00:22:17 +00:00
|
|
|
pub attachments: Vec<DbMediaAttachment>,
|
2021-11-11 19:10:28 +00:00
|
|
|
pub mentions: Vec<DbActorProfile>,
|
2021-12-07 23:28:58 +00:00
|
|
|
pub tags: Vec<String>,
|
2022-08-21 21:15:30 +00:00
|
|
|
pub links: Vec<Uuid>,
|
2023-01-07 19:28:26 +00:00
|
|
|
pub emojis: Vec<DbEmoji>,
|
2021-10-08 22:39:40 +00:00
|
|
|
pub object_id: Option<String>,
|
2021-04-09 00:22:17 +00:00
|
|
|
pub ipfs_cid: Option<String>,
|
|
|
|
pub token_id: Option<i32>,
|
|
|
|
pub token_tx_id: Option<String>,
|
|
|
|
pub created_at: DateTime<Utc>,
|
2022-05-11 12:50:36 +00:00
|
|
|
pub updated_at: Option<DateTime<Utc>>,
|
2021-11-24 16:39:30 +00:00
|
|
|
|
2021-12-31 17:15:00 +00:00
|
|
|
// These fields are not populated automatically
|
|
|
|
// by functions in posts::queries module
|
2021-10-18 22:35:52 +00:00
|
|
|
pub actions: Option<PostActions>,
|
2021-12-31 17:15:00 +00:00
|
|
|
pub in_reply_to: Option<Box<Post>>,
|
2021-11-24 16:39:30 +00:00
|
|
|
pub repost_of: Option<Box<Post>>,
|
2022-10-01 14:54:19 +00:00
|
|
|
pub linked: Vec<Post>,
|
2021-04-09 00:22:17 +00:00
|
|
|
}
|
|
|
|
|
2021-10-14 20:25:00 +00:00
|
|
|
impl Post {
|
|
|
|
pub fn new(
|
|
|
|
db_post: DbPost,
|
|
|
|
db_author: DbActorProfile,
|
|
|
|
db_attachments: Vec<DbMediaAttachment>,
|
2021-11-11 19:10:28 +00:00
|
|
|
db_mentions: Vec<DbActorProfile>,
|
2021-12-07 23:28:58 +00:00
|
|
|
db_tags: Vec<String>,
|
2022-08-21 21:15:30 +00:00
|
|
|
db_links: Vec<Uuid>,
|
2023-01-07 19:28:26 +00:00
|
|
|
db_emojis: Vec<DbEmoji>,
|
2022-12-03 22:09:42 +00:00
|
|
|
) -> Result<Self, DatabaseTypeError> {
|
2021-11-21 15:19:50 +00:00
|
|
|
// Consistency checks
|
2021-11-25 16:13:47 +00:00
|
|
|
if db_post.author_id != db_author.id {
|
2022-12-03 22:09:42 +00:00
|
|
|
return Err(DatabaseTypeError);
|
2021-11-21 15:19:50 +00:00
|
|
|
};
|
|
|
|
if db_author.is_local() != db_post.object_id.is_none() {
|
2022-12-03 22:09:42 +00:00
|
|
|
return Err(DatabaseTypeError);
|
2021-11-21 15:19:50 +00:00
|
|
|
};
|
2023-04-24 15:35:32 +00:00
|
|
|
if db_post.repost_of_id.is_some()
|
|
|
|
&& (db_post.content.len() != 0
|
|
|
|
|| db_post.is_sensitive
|
|
|
|
|| db_post.in_reply_to_id.is_some()
|
|
|
|
|| db_post.ipfs_cid.is_some()
|
|
|
|
|| db_post.token_id.is_some()
|
|
|
|
|| db_post.token_tx_id.is_some()
|
|
|
|
|| !db_attachments.is_empty()
|
|
|
|
|| !db_mentions.is_empty()
|
|
|
|
|| !db_tags.is_empty()
|
|
|
|
|| !db_links.is_empty()
|
|
|
|
|| !db_emojis.is_empty())
|
|
|
|
{
|
2022-12-03 22:09:42 +00:00
|
|
|
return Err(DatabaseTypeError);
|
2022-08-21 18:11:45 +00:00
|
|
|
};
|
2021-11-21 15:19:50 +00:00
|
|
|
let post = Self {
|
2021-10-14 20:25:00 +00:00
|
|
|
id: db_post.id,
|
|
|
|
author: db_author,
|
|
|
|
content: db_post.content,
|
|
|
|
in_reply_to_id: db_post.in_reply_to_id,
|
2021-11-24 16:39:30 +00:00
|
|
|
repost_of_id: db_post.repost_of_id,
|
2021-11-18 21:48:49 +00:00
|
|
|
visibility: db_post.visibility,
|
2023-04-15 23:43:19 +00:00
|
|
|
is_sensitive: db_post.is_sensitive,
|
2021-10-14 20:25:00 +00:00
|
|
|
reply_count: db_post.reply_count,
|
2021-10-17 16:55:33 +00:00
|
|
|
reaction_count: db_post.reaction_count,
|
2021-11-24 16:39:30 +00:00
|
|
|
repost_count: db_post.repost_count,
|
2021-10-14 20:25:00 +00:00
|
|
|
attachments: db_attachments,
|
2021-11-11 19:10:28 +00:00
|
|
|
mentions: db_mentions,
|
2021-12-07 23:28:58 +00:00
|
|
|
tags: db_tags,
|
2022-08-21 21:15:30 +00:00
|
|
|
links: db_links,
|
2023-01-07 19:28:26 +00:00
|
|
|
emojis: db_emojis,
|
2021-10-14 20:25:00 +00:00
|
|
|
object_id: db_post.object_id,
|
|
|
|
ipfs_cid: db_post.ipfs_cid,
|
|
|
|
token_id: db_post.token_id,
|
|
|
|
token_tx_id: db_post.token_tx_id,
|
|
|
|
created_at: db_post.created_at,
|
2022-05-11 12:50:36 +00:00
|
|
|
updated_at: db_post.updated_at,
|
2021-10-18 22:35:52 +00:00
|
|
|
actions: None,
|
2021-12-31 17:15:00 +00:00
|
|
|
in_reply_to: None,
|
2021-11-24 16:39:30 +00:00
|
|
|
repost_of: None,
|
2022-10-01 14:54:19 +00:00
|
|
|
linked: vec![],
|
2021-11-21 15:19:50 +00:00
|
|
|
};
|
|
|
|
Ok(post)
|
2021-10-14 20:25:00 +00:00
|
|
|
}
|
2021-11-20 01:10:56 +00:00
|
|
|
|
2022-11-21 18:55:06 +00:00
|
|
|
pub fn is_local(&self) -> bool {
|
|
|
|
self.author.is_local()
|
|
|
|
}
|
|
|
|
|
2021-11-20 01:10:56 +00:00
|
|
|
pub fn is_public(&self) -> bool {
|
|
|
|
matches!(self.visibility, Visibility::Public)
|
|
|
|
}
|
2021-10-14 20:25:00 +00:00
|
|
|
}
|
|
|
|
|
2023-03-30 20:27:17 +00:00
|
|
|
#[cfg(feature = "test-utils")]
|
2021-10-09 12:53:53 +00:00
|
|
|
impl Default for Post {
|
|
|
|
fn default() -> Self {
|
|
|
|
Self {
|
|
|
|
id: Uuid::new_v4(),
|
|
|
|
author: Default::default(),
|
|
|
|
content: "".to_string(),
|
|
|
|
in_reply_to_id: None,
|
2021-11-24 16:39:30 +00:00
|
|
|
repost_of_id: None,
|
2021-11-18 21:48:49 +00:00
|
|
|
visibility: Visibility::Public,
|
2023-04-15 23:43:19 +00:00
|
|
|
is_sensitive: false,
|
2021-10-09 12:53:53 +00:00
|
|
|
reply_count: 0,
|
2021-10-17 16:55:33 +00:00
|
|
|
reaction_count: 0,
|
2021-11-24 16:39:30 +00:00
|
|
|
repost_count: 0,
|
2021-10-09 12:53:53 +00:00
|
|
|
attachments: vec![],
|
2021-11-11 19:10:28 +00:00
|
|
|
mentions: vec![],
|
2021-12-07 23:28:58 +00:00
|
|
|
tags: vec![],
|
2022-08-21 21:15:30 +00:00
|
|
|
links: vec![],
|
2023-01-07 19:28:26 +00:00
|
|
|
emojis: vec![],
|
2021-10-09 12:53:53 +00:00
|
|
|
object_id: None,
|
|
|
|
ipfs_cid: None,
|
|
|
|
token_id: None,
|
|
|
|
token_tx_id: None,
|
|
|
|
created_at: Utc::now(),
|
2022-05-11 12:50:36 +00:00
|
|
|
updated_at: None,
|
2021-10-18 22:35:52 +00:00
|
|
|
actions: None,
|
2021-12-31 17:15:00 +00:00
|
|
|
in_reply_to: None,
|
2021-11-24 16:39:30 +00:00
|
|
|
repost_of: None,
|
2022-10-01 14:54:19 +00:00
|
|
|
linked: vec![],
|
2021-10-09 12:53:53 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-04-09 00:22:17 +00:00
|
|
|
impl TryFrom<&Row> for Post {
|
2021-11-21 15:19:50 +00:00
|
|
|
type Error = DatabaseError;
|
2021-04-09 00:22:17 +00:00
|
|
|
|
|
|
|
fn try_from(row: &Row) -> Result<Self, Self::Error> {
|
|
|
|
let db_post: DbPost = row.try_get("post")?;
|
|
|
|
let db_profile: DbActorProfile = row.try_get("actor_profile")?;
|
|
|
|
let db_attachments: Vec<DbMediaAttachment> = row.try_get("attachments")?;
|
2021-11-11 19:10:28 +00:00
|
|
|
let db_mentions: Vec<DbActorProfile> = row.try_get("mentions")?;
|
2021-12-07 23:28:58 +00:00
|
|
|
let db_tags: Vec<String> = row.try_get("tags")?;
|
2022-08-21 21:15:30 +00:00
|
|
|
let db_links: Vec<Uuid> = row.try_get("links")?;
|
2023-01-07 19:28:26 +00:00
|
|
|
let db_emojis: Vec<DbEmoji> = row.try_get("emojis")?;
|
2022-08-21 21:15:30 +00:00
|
|
|
let post = Self::new(
|
|
|
|
db_post,
|
|
|
|
db_profile,
|
|
|
|
db_attachments,
|
|
|
|
db_mentions,
|
|
|
|
db_tags,
|
|
|
|
db_links,
|
2023-01-07 19:28:26 +00:00
|
|
|
db_emojis,
|
2022-08-21 21:15:30 +00:00
|
|
|
)?;
|
2021-04-09 00:22:17 +00:00
|
|
|
Ok(post)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-11-24 16:39:30 +00:00
|
|
|
#[derive(Default)]
|
2021-04-09 00:22:17 +00:00
|
|
|
pub struct PostCreateData {
|
|
|
|
pub content: String,
|
2021-09-22 16:32:44 +00:00
|
|
|
pub in_reply_to_id: Option<Uuid>,
|
2021-11-24 16:39:30 +00:00
|
|
|
pub repost_of_id: Option<Uuid>,
|
2021-11-18 21:48:49 +00:00
|
|
|
pub visibility: Visibility,
|
2023-04-15 23:43:19 +00:00
|
|
|
pub is_sensitive: bool,
|
2021-04-09 00:22:17 +00:00
|
|
|
pub attachments: Vec<Uuid>,
|
2021-11-11 19:10:28 +00:00
|
|
|
pub mentions: Vec<Uuid>,
|
2021-12-07 23:28:58 +00:00
|
|
|
pub tags: Vec<String>,
|
2022-08-21 21:15:30 +00:00
|
|
|
pub links: Vec<Uuid>,
|
2023-01-07 19:28:26 +00:00
|
|
|
pub emojis: Vec<Uuid>,
|
2021-10-08 22:39:40 +00:00
|
|
|
pub object_id: Option<String>,
|
2022-09-29 15:26:12 +00:00
|
|
|
pub created_at: DateTime<Utc>,
|
2021-04-09 00:22:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl PostCreateData {
|
2023-04-24 15:35:32 +00:00
|
|
|
pub fn repost(repost_of_id: Uuid, object_id: Option<String>) -> Self {
|
2022-10-04 23:18:01 +00:00
|
|
|
Self {
|
|
|
|
repost_of_id: Some(repost_of_id),
|
2023-04-25 11:19:04 +00:00
|
|
|
object_id,
|
2022-10-04 23:18:01 +00:00
|
|
|
created_at: Utc::now(),
|
|
|
|
..Default::default()
|
|
|
|
}
|
|
|
|
}
|
2021-04-09 00:22:17 +00:00
|
|
|
}
|
|
|
|
|
2023-01-30 03:10:07 +00:00
|
|
|
#[cfg_attr(test, derive(Default))]
|
2022-05-11 12:50:36 +00:00
|
|
|
pub struct PostUpdateData {
|
|
|
|
pub content: String,
|
2023-04-15 23:43:19 +00:00
|
|
|
pub is_sensitive: bool,
|
2023-01-30 03:10:07 +00:00
|
|
|
pub attachments: Vec<Uuid>,
|
|
|
|
pub mentions: Vec<Uuid>,
|
|
|
|
pub tags: Vec<String>,
|
|
|
|
pub links: Vec<Uuid>,
|
|
|
|
pub emojis: Vec<Uuid>,
|
2022-05-11 12:50:36 +00:00
|
|
|
pub updated_at: DateTime<Utc>,
|
|
|
|
}
|