add: custom emojis
fix: don't show reposts of posts from blocked users fix: don't show questions when they're from users you've blocked
This commit is contained in:
parent
9f187039e6
commit
275dd0a1eb
25 changed files with 697 additions and 61 deletions
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "tetratto-core"
|
||||
version = "2.3.0"
|
||||
version = "3.0.0"
|
||||
edition = "2024"
|
||||
|
||||
[features]
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
use std::collections::HashMap;
|
||||
|
||||
use super::*;
|
||||
use crate::cache::Cache;
|
||||
use crate::model::{
|
||||
|
@ -55,6 +57,29 @@ impl DataManager {
|
|||
Ok(res.unwrap())
|
||||
}
|
||||
|
||||
/// Get all emojis by their community for the communities the given user is in.
|
||||
pub async fn get_user_emojis(
|
||||
&self,
|
||||
id: usize,
|
||||
) -> Result<HashMap<usize, (String, Vec<CustomEmoji>)>> {
|
||||
let memberships = self.get_memberships_by_owner(id).await?;
|
||||
let mut out = HashMap::new();
|
||||
|
||||
for membership in memberships {
|
||||
let community = self.get_community_by_id(membership.community).await?;
|
||||
|
||||
out.insert(
|
||||
community.id,
|
||||
(
|
||||
community.title.clone(),
|
||||
self.get_emojis_by_community(community.id).await?,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Ok(out)
|
||||
}
|
||||
|
||||
/// Get an emoji by community and name.
|
||||
///
|
||||
/// # Arguments
|
||||
|
@ -134,8 +159,8 @@ impl DataManager {
|
|||
"INSERT INTO emojis VALUES ($1, $2, $3, $4, $5, $6, $7)",
|
||||
params![
|
||||
&(data.id as i64),
|
||||
&(data.owner as i64),
|
||||
&(data.created as i64),
|
||||
&(data.owner as i64),
|
||||
&(data.community as i64),
|
||||
&(data.upload_id as i64),
|
||||
&data.name,
|
||||
|
@ -176,7 +201,7 @@ impl DataManager {
|
|||
return Err(Error::DatabaseError(e.to_string()));
|
||||
}
|
||||
|
||||
// delete uploads
|
||||
// delete upload
|
||||
self.delete_upload(emoji.upload_id).await?;
|
||||
|
||||
// ...
|
||||
|
@ -184,5 +209,5 @@ impl DataManager {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
auto_method!(update_emoji_name(&str)@get_emoji_by_id:MANAGE_EMOJIS -> "UPDATE emojis SET title = $1 WHERE id = $2" --cache-key-tmpl="atto.emoji:{}");
|
||||
auto_method!(update_emoji_name(&str)@get_emoji_by_id:MANAGE_EMOJIS -> "UPDATE emojis SET name = $1 WHERE id = $2" --cache-key-tmpl="atto.emoji:{}");
|
||||
}
|
||||
|
|
|
@ -78,7 +78,11 @@ impl DataManager {
|
|||
}
|
||||
|
||||
/// Get the post the given post is reposting (if some).
|
||||
pub async fn get_post_reposting(&self, post: &Post) -> Option<(User, Post)> {
|
||||
pub async fn get_post_reposting(
|
||||
&self,
|
||||
post: &Post,
|
||||
ignore_users: &[usize],
|
||||
) -> Option<(User, Post)> {
|
||||
if let Some(ref repost) = post.context.repost {
|
||||
if let Some(reposting) = repost.reposting {
|
||||
let mut x = match self.get_post_by_id(reposting).await {
|
||||
|
@ -86,6 +90,10 @@ impl DataManager {
|
|||
Err(_) => return None,
|
||||
};
|
||||
|
||||
if ignore_users.contains(&x.owner) {
|
||||
return None;
|
||||
}
|
||||
|
||||
x.mark_as_repost();
|
||||
Some((
|
||||
match self.get_user_by_id(x.owner).await {
|
||||
|
@ -103,9 +111,18 @@ impl DataManager {
|
|||
}
|
||||
|
||||
/// Get the question of a given post.
|
||||
pub async fn get_post_question(&self, post: &Post) -> Result<Option<(Question, User)>> {
|
||||
pub async fn get_post_question(
|
||||
&self,
|
||||
post: &Post,
|
||||
ignore_users: &[usize],
|
||||
) -> Result<Option<(Question, User)>> {
|
||||
if post.context.answering != 0 {
|
||||
let question = self.get_question_by_id(post.context.answering).await?;
|
||||
|
||||
if ignore_users.contains(&question.owner) {
|
||||
return Ok(None);
|
||||
}
|
||||
|
||||
let user = if question.owner == 0 {
|
||||
User::anonymous()
|
||||
} else {
|
||||
|
@ -138,8 +155,8 @@ impl DataManager {
|
|||
out.push((
|
||||
post.clone(),
|
||||
user.clone(),
|
||||
self.get_post_reposting(&post).await,
|
||||
self.get_post_question(&post).await?,
|
||||
self.get_post_reposting(&post, ignore_users).await,
|
||||
self.get_post_question(&post, ignore_users).await?,
|
||||
));
|
||||
} else {
|
||||
let user = self.get_user_by_id(owner).await?;
|
||||
|
@ -147,8 +164,8 @@ impl DataManager {
|
|||
out.push((
|
||||
post.clone(),
|
||||
user,
|
||||
self.get_post_reposting(&post).await,
|
||||
self.get_post_question(&post).await?,
|
||||
self.get_post_reposting(&post, ignore_users).await,
|
||||
self.get_post_question(&post, ignore_users).await?,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
@ -196,8 +213,8 @@ impl DataManager {
|
|||
post.clone(),
|
||||
user.clone(),
|
||||
community.to_owned(),
|
||||
self.get_post_reposting(&post).await,
|
||||
self.get_post_question(&post).await?,
|
||||
self.get_post_reposting(&post, ignore_users).await,
|
||||
self.get_post_question(&post, ignore_users).await?,
|
||||
));
|
||||
} else {
|
||||
let user = self.get_user_by_id(owner).await?;
|
||||
|
@ -235,8 +252,8 @@ impl DataManager {
|
|||
post.clone(),
|
||||
user,
|
||||
community,
|
||||
self.get_post_reposting(&post).await,
|
||||
self.get_post_question(&post).await?,
|
||||
self.get_post_reposting(&post, ignore_users).await,
|
||||
self.get_post_question(&post, ignore_users).await?,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,10 +1,8 @@
|
|||
use std::fs::{exists, remove_file};
|
||||
use super::*;
|
||||
use crate::cache::Cache;
|
||||
use crate::model::{Error, Result, uploads::MediaUpload};
|
||||
use crate::{auto_method, execute, get, query_row, query_rows, params};
|
||||
|
||||
use pathbufd::PathBufD;
|
||||
#[cfg(feature = "sqlite")]
|
||||
use rusqlite::Row;
|
||||
|
||||
|
@ -56,7 +54,7 @@ impl DataManager {
|
|||
///
|
||||
/// # Arguments
|
||||
/// * `data` - a mock [`MediaUpload`] object to insert
|
||||
pub async fn create_upload(&self, data: MediaUpload) -> Result<()> {
|
||||
pub async fn create_upload(&self, data: MediaUpload) -> Result<MediaUpload> {
|
||||
let conn = match self.connect().await {
|
||||
Ok(c) => c,
|
||||
Err(e) => return Err(Error::DatabaseConnection(e.to_string())),
|
||||
|
@ -78,7 +76,7 @@ impl DataManager {
|
|||
}
|
||||
|
||||
// return
|
||||
Ok(())
|
||||
Ok(data)
|
||||
}
|
||||
|
||||
pub async fn delete_upload(&self, id: usize) -> Result<()> {
|
||||
|
@ -91,16 +89,8 @@ impl DataManager {
|
|||
// if there's an issue in the database
|
||||
//
|
||||
// the actual file takes up much more space than the database entry.
|
||||
let path = PathBufD::current().extend(&[self.0.dirs.media.as_str(), "uploads"]);
|
||||
if let Ok(exists) = exists(&path) {
|
||||
if exists {
|
||||
if let Err(e) = remove_file(&path) {
|
||||
return Err(Error::MiscError(e.to_string()));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return Err(Error::GeneralNotFound("file".to_string()));
|
||||
}
|
||||
let upload = self.get_upload_by_id(id).await?;
|
||||
upload.remove(&self.0)?;
|
||||
|
||||
// delete from database
|
||||
let conn = match self.connect().await {
|
||||
|
|
|
@ -1,5 +1,9 @@
|
|||
use pathbufd::PathBufD;
|
||||
use serde::{Serialize, Deserialize};
|
||||
use tetratto_shared::{snow::Snowflake, unix_epoch_timestamp};
|
||||
use crate::config::Config;
|
||||
use std::fs::{write, exists, remove_file};
|
||||
use super::{Error, Result};
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub enum MediaType {
|
||||
|
@ -15,6 +19,22 @@ pub enum MediaType {
|
|||
Gif,
|
||||
}
|
||||
|
||||
impl MediaType {
|
||||
pub fn extension(&self) -> &str {
|
||||
match self {
|
||||
Self::Webp => "webp",
|
||||
Self::Avif => "avif",
|
||||
Self::Png => "png",
|
||||
Self::Jpg => "jpg",
|
||||
Self::Gif => "gif",
|
||||
}
|
||||
}
|
||||
|
||||
pub fn mime(&self) -> String {
|
||||
format!("image/{}", self.extension())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct MediaUpload {
|
||||
pub id: usize,
|
||||
|
@ -33,6 +53,35 @@ impl MediaUpload {
|
|||
what,
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the path to the fs file for this upload.
|
||||
pub fn path(&self, config: &Config) -> PathBufD {
|
||||
PathBufD::current()
|
||||
.extend(&[config.dirs.media.as_str(), "uploads"])
|
||||
.join(format!("{}.{}", self.id, self.what.extension()))
|
||||
}
|
||||
|
||||
/// Write to this upload in the file system.
|
||||
pub fn write(&self, config: &Config, bytes: &[u8]) -> Result<()> {
|
||||
match write(self.path(config), bytes) {
|
||||
Ok(_) => Ok(()),
|
||||
Err(e) => Err(Error::MiscError(e.to_string())),
|
||||
}
|
||||
}
|
||||
|
||||
/// Delete this upload in the file system.
|
||||
pub fn remove(&self, config: &Config) -> Result<()> {
|
||||
let path = self.path(config);
|
||||
|
||||
if !exists(&path).unwrap() {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
match remove_file(path) {
|
||||
Ok(_) => Ok(()),
|
||||
Err(e) => Err(Error::MiscError(e.to_string())),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
|
@ -86,7 +135,7 @@ impl CustomEmoji {
|
|||
out = out.replace(
|
||||
&emoji.0,
|
||||
&format!(
|
||||
"<img class=\"emoji\" src=\"/api/v1/communities/{}/emoji/{}\" />",
|
||||
"<img class=\"emoji\" src=\"/api/v1/communities/{}/emojis/{}\" />",
|
||||
emoji.1, emoji.2
|
||||
),
|
||||
);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue