add: forges ui

TODO: forges tickets feed, posts open/closed state
This commit is contained in:
trisua 2025-06-09 16:45:36 -04:00
parent 5b1db42c51
commit a6140f7c8c
40 changed files with 1664 additions and 1270 deletions

View file

@ -10,7 +10,10 @@ use crate::model::{
};
use pathbufd::PathBufD;
use std::fs::{exists, remove_file};
use tetratto_shared::hash::{hash_salted, salt};
use tetratto_shared::{
hash::{hash_salted, salt},
unix_epoch_timestamp,
};
use crate::{auto_method, DataManager};
#[cfg(feature = "sqlite")]
@ -18,8 +21,6 @@ use oiseau::SqliteRow;
#[cfg(feature = "postgres")]
use oiseau::PostgresRow;
#[cfg(feature = "postgres")]
use tetratto_shared::unix_epoch_timestamp;
use oiseau::{execute, get, query_row, params};

View file

@ -40,8 +40,10 @@ impl DataManager {
// likes
likes: get!(x->8(i32)) as isize,
dislikes: get!(x->9(i32)) as isize,
// counts
// ...
member_count: get!(x->10(i32)) as usize,
is_forge: get!(x->11(i32)) as i8 == 1,
post_count: get!(x->12(i32)) as usize,
}
}
@ -51,7 +53,10 @@ impl DataManager {
}
if let Some(cached) = self.0.1.get(format!("atto.community:{}", id)).await {
return Ok(serde_json::from_str(&cached).unwrap());
match serde_json::from_str(&cached) {
Ok(c) => return Ok(c),
Err(_) => self.0.1.remove(format!("atto.community:{}", id)).await,
};
}
let conn = match self.0.connect().await {
@ -89,7 +94,10 @@ impl DataManager {
}
if let Some(cached) = self.0.1.get(format!("atto.community:{}", id)).await {
return Ok(serde_json::from_str(&cached).unwrap());
match serde_json::from_str(&cached) {
Ok(c) => return Ok(c),
Err(_) => self.0.1.remove(format!("atto.community:{}", id)).await,
};
}
let conn = match self.0.connect().await {
@ -218,7 +226,7 @@ impl DataManager {
return Err(Error::MiscError("This title cannot be used".to_string()));
}
let regex = regex::RegexBuilder::new(r"[^\w_\-\.!]+")
let regex = regex::RegexBuilder::new(NAME_REGEX)
.multi_line(true)
.build()
.unwrap();
@ -259,6 +267,12 @@ impl DataManager {
}
}
// check is_forge
// only supporters can CREATE forge communities... anybody can contribute to them
if data.is_forge && !owner.permissions.check(FinePermission::SUPPORTER) {
return Err(Error::RequiresSupporter);
}
// make sure community doesn't already exist with title
if self
.get_community_by_title_no_void(&data.title.to_lowercase())
@ -276,7 +290,7 @@ impl DataManager {
let res = execute!(
&conn,
"INSERT INTO communities VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11)",
"INSERT INTO communities VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13)",
params![
&(data.id as i64),
&(data.created as i64),
@ -288,7 +302,9 @@ impl DataManager {
&serde_json::to_string(&data.join_access).unwrap().as_str(),
&0_i32,
&0_i32,
&1_i32
&1_i32,
&{ if data.is_forge { 1 } else { 0 } },
&0_i32,
]
);
@ -532,4 +548,7 @@ impl DataManager {
auto_method!(incr_community_member_count()@get_community_by_id_no_void -> "UPDATE communities SET member_count = member_count + 1 WHERE id = $1" --cache-key-tmpl=cache_clear_community --incr);
auto_method!(decr_community_member_count()@get_community_by_id_no_void -> "UPDATE communities SET member_count = member_count - 1 WHERE id = $1" --cache-key-tmpl=cache_clear_community --decr=member_count);
auto_method!(incr_community_post_count()@get_community_by_id_no_void -> "UPDATE communities SET post_count = post_count + 1 WHERE id = $1" --cache-key-tmpl=cache_clear_community --incr);
auto_method!(decr_community_post_count()@get_community_by_id_no_void -> "UPDATE communities SET post_count = post_count - 1 WHERE id = $1" --cache-key-tmpl=cache_clear_community --decr=post_count);
}

View file

@ -8,6 +8,7 @@ use crate::model::{
communities_permissions::CommunityPermission, channels::Message,
};
use serde::Serialize;
use tetratto_shared::unix_epoch_timestamp;
use crate::{auto_method, DataManager};
#[cfg(feature = "redis")]
@ -18,8 +19,6 @@ use oiseau::SqliteRow;
#[cfg(feature = "postgres")]
use oiseau::PostgresRow;
#[cfg(feature = "postgres")]
use tetratto_shared::unix_epoch_timestamp;
use oiseau::{execute, get, query_rows, params};

View file

@ -872,7 +872,7 @@ impl DataManager {
let res = query_row!(
&conn,
"SELECT * FROM posts WHERE context LIKE $1 AND owner = $2 LIMIT 1",
"SELECT * FROM posts WHERE context LIKE $1 AND owner = $2 AND is_deleted = 0 LIMIT 1",
params![&format!("%\"answering\":{question}%"), &(owner as i64),],
|x| { Ok(Self::get_post_from_row(x)) }
);
@ -1494,6 +1494,9 @@ impl DataManager {
// increase user post count
self.incr_user_post_count(data.owner).await?;
// increase community post count
self.incr_community_post_count(data.community).await?;
// return
Ok(data.id)
}
@ -1546,6 +1549,13 @@ impl DataManager {
self.decr_user_post_count(y.owner).await?;
}
// decr community post count
let community = self.get_community_by_id_no_void(y.community).await?;
if community.post_count > 0 {
self.decr_community_post_count(y.community).await?;
}
// decr question answer count
if y.context.answering != 0 {
let question = self.get_question_by_id(y.context.answering).await?;
@ -1622,12 +1632,19 @@ impl DataManager {
self.decr_user_post_count(y.owner).await?;
}
// decr community post count
let community = self.get_community_by_id_no_void(y.community).await?;
if community.post_count > 0 {
self.decr_community_post_count(y.community).await?;
}
// decr question answer count
if y.context.answering != 0 {
let question = self.get_question_by_id(y.context.answering).await?;
if question.is_global {
self.incr_question_answer_count(y.context.answering).await?;
self.decr_question_answer_count(y.context.answering).await?;
}
}
@ -1644,12 +1661,15 @@ impl DataManager {
// incr user post count
self.incr_user_post_count(y.owner).await?;
// incr community post count
self.incr_community_post_count(y.community).await?;
// incr question answer count
if y.context.answering != 0 {
let question = self.get_question_by_id(y.context.answering).await?;
if question.is_global {
self.decr_question_answer_count(y.context.answering).await?;
self.incr_question_answer_count(y.context.answering).await?;
}
}