fix: stacks manage page when user deletes profile
add: allow moderators to view deleted posts
This commit is contained in:
parent
4c26879d00
commit
81307752c2
14 changed files with 211 additions and 29 deletions
|
@ -227,6 +227,14 @@ and show_community and community.id != config.town_square or question %}
|
||||||
>
|
>
|
||||||
{{ icon "user-round" }}
|
{{ icon "user-round" }}
|
||||||
</span>
|
</span>
|
||||||
|
{% endif %} {% if post.is_deleted %}
|
||||||
|
<span
|
||||||
|
title="Deleted"
|
||||||
|
class="flex items-center"
|
||||||
|
style="color: var(--color-primary)"
|
||||||
|
>
|
||||||
|
{{ icon "trash-2" }}
|
||||||
|
</span>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
@ -138,7 +138,7 @@ pub async fn update_title_request(
|
||||||
None => return Json(Error::NotAllowed.into()),
|
None => return Json(Error::NotAllowed.into()),
|
||||||
};
|
};
|
||||||
|
|
||||||
match data.update_channel_title(id, user, &req.title).await {
|
match data.update_channel_title(id, &user, &req.title).await {
|
||||||
Ok(_) => Json(ApiReturn {
|
Ok(_) => Json(ApiReturn {
|
||||||
ok: true,
|
ok: true,
|
||||||
message: "Channel updated".to_string(),
|
message: "Channel updated".to_string(),
|
||||||
|
@ -160,7 +160,7 @@ pub async fn update_position_request(
|
||||||
None => return Json(Error::NotAllowed.into()),
|
None => return Json(Error::NotAllowed.into()),
|
||||||
};
|
};
|
||||||
|
|
||||||
match data.update_channel_position(id, user, req.position).await {
|
match data.update_channel_position(id, &user, req.position).await {
|
||||||
Ok(_) => Json(ApiReturn {
|
Ok(_) => Json(ApiReturn {
|
||||||
ok: true,
|
ok: true,
|
||||||
message: "Channel updated".to_string(),
|
message: "Channel updated".to_string(),
|
||||||
|
|
|
@ -117,7 +117,7 @@ pub async fn update_context_request(
|
||||||
None => return Json(Error::NotAllowed.into()),
|
None => return Json(Error::NotAllowed.into()),
|
||||||
};
|
};
|
||||||
|
|
||||||
match data.update_community_context(id, user, req.context).await {
|
match data.update_community_context(id, &user, req.context).await {
|
||||||
Ok(_) => Json(ApiReturn {
|
Ok(_) => Json(ApiReturn {
|
||||||
ok: true,
|
ok: true,
|
||||||
message: "Community updated".to_string(),
|
message: "Community updated".to_string(),
|
||||||
|
@ -140,7 +140,7 @@ pub async fn update_read_access_request(
|
||||||
};
|
};
|
||||||
|
|
||||||
match data
|
match data
|
||||||
.update_community_read_access(id, user, req.access)
|
.update_community_read_access(id, &user, req.access)
|
||||||
.await
|
.await
|
||||||
{
|
{
|
||||||
Ok(_) => Json(ApiReturn {
|
Ok(_) => Json(ApiReturn {
|
||||||
|
@ -165,7 +165,7 @@ pub async fn update_write_access_request(
|
||||||
};
|
};
|
||||||
|
|
||||||
match data
|
match data
|
||||||
.update_community_write_access(id, user, req.access)
|
.update_community_write_access(id, &user, req.access)
|
||||||
.await
|
.await
|
||||||
{
|
{
|
||||||
Ok(_) => Json(ApiReturn {
|
Ok(_) => Json(ApiReturn {
|
||||||
|
@ -190,7 +190,7 @@ pub async fn update_join_access_request(
|
||||||
};
|
};
|
||||||
|
|
||||||
match data
|
match data
|
||||||
.update_community_join_access(id, user, req.access)
|
.update_community_join_access(id, &user, req.access)
|
||||||
.await
|
.await
|
||||||
{
|
{
|
||||||
Ok(_) => Json(ApiReturn {
|
Ok(_) => Json(ApiReturn {
|
||||||
|
|
|
@ -183,7 +183,7 @@ pub async fn update_name_request(
|
||||||
None => return Json(Error::NotAllowed.into()),
|
None => return Json(Error::NotAllowed.into()),
|
||||||
};
|
};
|
||||||
|
|
||||||
match data.update_emoji_name(id, user, &req.name).await {
|
match data.update_emoji_name(id, &user, &req.name).await {
|
||||||
Ok(_) => Json(ApiReturn {
|
Ok(_) => Json(ApiReturn {
|
||||||
ok: true,
|
ok: true,
|
||||||
message: "Emoji updated".to_string(),
|
message: "Emoji updated".to_string(),
|
||||||
|
|
|
@ -173,6 +173,31 @@ pub async fn delete_request(
|
||||||
None => return Json(Error::NotAllowed.into()),
|
None => return Json(Error::NotAllowed.into()),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
match data.fake_delete_post(id, user, true).await {
|
||||||
|
Ok(_) => Json(ApiReturn {
|
||||||
|
ok: true,
|
||||||
|
message: "Post deleted".to_string(),
|
||||||
|
payload: (),
|
||||||
|
}),
|
||||||
|
Err(e) => Json(e.into()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn real_delete_request(
|
||||||
|
jar: CookieJar,
|
||||||
|
Extension(data): Extension<State>,
|
||||||
|
Path(id): Path<usize>,
|
||||||
|
) -> impl IntoResponse {
|
||||||
|
let data = &(data.read().await).0;
|
||||||
|
let user = match get_user_from_token!(jar, data) {
|
||||||
|
Some(ua) => ua,
|
||||||
|
None => return Json(Error::NotAllowed.into()),
|
||||||
|
};
|
||||||
|
|
||||||
|
if !user.permissions.check(FinePermission::MANAGE_POSTS) {
|
||||||
|
return Json(Error::NotAllowed.into());
|
||||||
|
}
|
||||||
|
|
||||||
match data.delete_post(id, user).await {
|
match data.delete_post(id, user).await {
|
||||||
Ok(_) => Json(ApiReturn {
|
Ok(_) => Json(ApiReturn {
|
||||||
ok: true,
|
ok: true,
|
||||||
|
|
|
@ -93,6 +93,10 @@ pub fn routes() -> Router {
|
||||||
// posts
|
// posts
|
||||||
.route("/posts", post(communities::posts::create_request))
|
.route("/posts", post(communities::posts::create_request))
|
||||||
.route("/posts/{id}", delete(communities::posts::delete_request))
|
.route("/posts/{id}", delete(communities::posts::delete_request))
|
||||||
|
.route(
|
||||||
|
"/posts/{id}/real_delete",
|
||||||
|
delete(communities::posts::real_delete_request),
|
||||||
|
)
|
||||||
.route(
|
.route(
|
||||||
"/posts/{id}/repost",
|
"/posts/{id}/repost",
|
||||||
post(communities::posts::create_repost_request),
|
post(communities::posts::create_repost_request),
|
||||||
|
|
|
@ -43,7 +43,7 @@ pub async fn update_name_request(
|
||||||
None => return Json(Error::NotAllowed.into()),
|
None => return Json(Error::NotAllowed.into()),
|
||||||
};
|
};
|
||||||
|
|
||||||
match data.update_stack_name(id, user, &req.name).await {
|
match data.update_stack_name(id, &user, &req.name).await {
|
||||||
Ok(_) => Json(ApiReturn {
|
Ok(_) => Json(ApiReturn {
|
||||||
ok: true,
|
ok: true,
|
||||||
message: "Stack updated".to_string(),
|
message: "Stack updated".to_string(),
|
||||||
|
@ -65,7 +65,7 @@ pub async fn update_privacy_request(
|
||||||
None => return Json(Error::NotAllowed.into()),
|
None => return Json(Error::NotAllowed.into()),
|
||||||
};
|
};
|
||||||
|
|
||||||
match data.update_stack_privacy(id, user, req.privacy).await {
|
match data.update_stack_privacy(id, &user, req.privacy).await {
|
||||||
Ok(_) => Json(ApiReturn {
|
Ok(_) => Json(ApiReturn {
|
||||||
ok: true,
|
ok: true,
|
||||||
message: "Stack updated".to_string(),
|
message: "Stack updated".to_string(),
|
||||||
|
@ -87,7 +87,7 @@ pub async fn update_mode_request(
|
||||||
None => return Json(Error::NotAllowed.into()),
|
None => return Json(Error::NotAllowed.into()),
|
||||||
};
|
};
|
||||||
|
|
||||||
match data.update_stack_mode(id, user, req.mode).await {
|
match data.update_stack_mode(id, &user, req.mode).await {
|
||||||
Ok(_) => Json(ApiReturn {
|
Ok(_) => Json(ApiReturn {
|
||||||
ok: true,
|
ok: true,
|
||||||
message: "Stack updated".to_string(),
|
message: "Stack updated".to_string(),
|
||||||
|
@ -109,7 +109,7 @@ pub async fn update_sort_request(
|
||||||
None => return Json(Error::NotAllowed.into()),
|
None => return Json(Error::NotAllowed.into()),
|
||||||
};
|
};
|
||||||
|
|
||||||
match data.update_stack_sort(id, user, req.sort).await {
|
match data.update_stack_sort(id, &user, req.sort).await {
|
||||||
Ok(_) => Json(ApiReturn {
|
Ok(_) => Json(ApiReturn {
|
||||||
ok: true,
|
ok: true,
|
||||||
message: "Stack updated".to_string(),
|
message: "Stack updated".to_string(),
|
||||||
|
@ -152,7 +152,7 @@ pub async fn add_user_request(
|
||||||
};
|
};
|
||||||
|
|
||||||
stack.users.push(other_user.id);
|
stack.users.push(other_user.id);
|
||||||
match data.update_stack_users(id, user, stack.users).await {
|
match data.update_stack_users(id, &user, stack.users).await {
|
||||||
Ok(_) => Json(ApiReturn {
|
Ok(_) => Json(ApiReturn {
|
||||||
ok: true,
|
ok: true,
|
||||||
message: "User added".to_string(),
|
message: "User added".to_string(),
|
||||||
|
@ -191,7 +191,7 @@ pub async fn remove_user_request(
|
||||||
None => return Json(Error::GeneralNotFound("user".to_string()).into()),
|
None => return Json(Error::GeneralNotFound("user".to_string()).into()),
|
||||||
});
|
});
|
||||||
|
|
||||||
match data.update_stack_users(id, user, stack.users).await {
|
match data.update_stack_users(id, &user, stack.users).await {
|
||||||
Ok(_) => Json(ApiReturn {
|
Ok(_) => Json(ApiReturn {
|
||||||
ok: true,
|
ok: true,
|
||||||
message: "User removed".to_string(),
|
message: "User removed".to_string(),
|
||||||
|
|
|
@ -589,6 +589,33 @@ pub async fn post_request(
|
||||||
Err(e) => return Err(Html(render_error(e, &jar, &data, &user).await)),
|
Err(e) => return Err(Html(render_error(e, &jar, &data, &user).await)),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if post.is_deleted {
|
||||||
|
// act like the post doesn't exist (if missing MANAGE_POSTS)
|
||||||
|
if let Some(ref ua) = user {
|
||||||
|
if !ua.permissions.check(FinePermission::MANAGE_POSTS) {
|
||||||
|
return Err(Html(
|
||||||
|
render_error(
|
||||||
|
Error::GeneralNotFound("post".to_string()),
|
||||||
|
&jar,
|
||||||
|
&data,
|
||||||
|
&user,
|
||||||
|
)
|
||||||
|
.await,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return Err(Html(
|
||||||
|
render_error(
|
||||||
|
Error::GeneralNotFound("post".to_string()),
|
||||||
|
&jar,
|
||||||
|
&data,
|
||||||
|
&user,
|
||||||
|
)
|
||||||
|
.await,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let community = match data.0.get_community_by_id(post.community).await {
|
let community = match data.0.get_community_by_id(post.community).await {
|
||||||
Ok(c) => c,
|
Ok(c) => c,
|
||||||
Err(e) => return Err(Html(render_error(e, &jar, &data, &user).await)),
|
Err(e) => return Err(Html(render_error(e, &jar, &data, &user).await)),
|
||||||
|
|
|
@ -120,15 +120,29 @@ pub async fn manage_request(
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let mut new_users = stack.users.clone();
|
||||||
|
let mut changed_stack_users: bool = false;
|
||||||
|
|
||||||
let mut users: Vec<User> = Vec::new();
|
let mut users: Vec<User> = Vec::new();
|
||||||
|
|
||||||
for uid in &stack.users {
|
for uid in &stack.users {
|
||||||
users.push(match data.0.get_user_by_id(uid.to_owned()).await {
|
users.push(match data.0.get_user_by_id(uid.to_owned()).await {
|
||||||
Ok(ua) => ua,
|
Ok(ua) => ua,
|
||||||
Err(e) => return Err(Html(render_error(e, &jar, &data, &Some(user)).await)),
|
Err(_) => {
|
||||||
|
// user deleted profile, remove from list
|
||||||
|
new_users.remove(stack.users.iter().position(|x| x == uid).unwrap());
|
||||||
|
changed_stack_users = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if changed_stack_users {
|
||||||
|
if let Err(e) = data.0.update_stack_users(stack.id, &user, new_users).await {
|
||||||
|
return Err(Html(render_error(e, &jar, &data, &None).await));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let lang = get_lang!(jar, data.0);
|
let lang = get_lang!(jar, data.0);
|
||||||
let mut context = initial_context(&data.0.0, lang, &Some(user)).await;
|
let mut context = initial_context(&data.0.0, lang, &Some(user)).await;
|
||||||
|
|
||||||
|
|
|
@ -69,7 +69,9 @@ macro_rules! auto_method {
|
||||||
($name:ident()@$select_fn:ident -> $query:literal --name=$name_:literal --returns=$returns_:tt --cache-key-tmpl=$cache_key_tmpl:literal) => {
|
($name:ident()@$select_fn:ident -> $query:literal --name=$name_:literal --returns=$returns_:tt --cache-key-tmpl=$cache_key_tmpl:literal) => {
|
||||||
pub async fn $name(&self, id: usize) -> Result<$returns_> {
|
pub async fn $name(&self, id: usize) -> Result<$returns_> {
|
||||||
if let Some(cached) = self.2.get(format!($cache_key_tmpl, id)).await {
|
if let Some(cached) = self.2.get(format!($cache_key_tmpl, id)).await {
|
||||||
return Ok(serde_json::from_str(&cached).unwrap());
|
if let Ok(c) = serde_json::from_str(&cached) {
|
||||||
|
return Ok(c);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let conn = match self.connect().await {
|
let conn = match self.connect().await {
|
||||||
|
@ -183,7 +185,7 @@ macro_rules! auto_method {
|
||||||
};
|
};
|
||||||
|
|
||||||
($name:ident()@$select_fn:ident:$permission:ident -> $query:literal) => {
|
($name:ident()@$select_fn:ident:$permission:ident -> $query:literal) => {
|
||||||
pub async fn $name(&self, id: usize, user: User) -> Result<()> {
|
pub async fn $name(&self, id: usize, user: &User) -> Result<()> {
|
||||||
let y = self.$select_fn(id).await?;
|
let y = self.$select_fn(id).await?;
|
||||||
|
|
||||||
if user.id != y.owner {
|
if user.id != y.owner {
|
||||||
|
@ -213,7 +215,7 @@ macro_rules! auto_method {
|
||||||
};
|
};
|
||||||
|
|
||||||
($name:ident()@$select_fn:ident:$permission:ident -> $query:literal --cache-key-tmpl=$cache_key_tmpl:literal) => {
|
($name:ident()@$select_fn:ident:$permission:ident -> $query:literal --cache-key-tmpl=$cache_key_tmpl:literal) => {
|
||||||
pub async fn $name(&self, id: usize, user: User) -> Result<()> {
|
pub async fn $name(&self, id: usize, user: &User) -> Result<()> {
|
||||||
let y = self.$select_fn(id).await?;
|
let y = self.$select_fn(id).await?;
|
||||||
|
|
||||||
if user.id != y.owner {
|
if user.id != y.owner {
|
||||||
|
@ -245,7 +247,7 @@ macro_rules! auto_method {
|
||||||
};
|
};
|
||||||
|
|
||||||
($name:ident($x:ty)@$select_fn:ident:$permission:ident -> $query:literal) => {
|
($name:ident($x:ty)@$select_fn:ident:$permission:ident -> $query:literal) => {
|
||||||
pub async fn $name(&self, id: usize, user: User, x: $x) -> Result<()> {
|
pub async fn $name(&self, id: usize, user: &User, x: $x) -> Result<()> {
|
||||||
let y = self.$select_fn(id).await?;
|
let y = self.$select_fn(id).await?;
|
||||||
|
|
||||||
if user.id != y.owner {
|
if user.id != y.owner {
|
||||||
|
@ -276,7 +278,7 @@ macro_rules! auto_method {
|
||||||
};
|
};
|
||||||
|
|
||||||
($name:ident($x:ty)@$select_fn:ident:$permission:ident -> $query:literal --cache-key-tmpl=$cache_key_tmpl:literal) => {
|
($name:ident($x:ty)@$select_fn:ident:$permission:ident -> $query:literal --cache-key-tmpl=$cache_key_tmpl:literal) => {
|
||||||
pub async fn $name(&self, id: usize, user: User, x: $x) -> Result<()> {
|
pub async fn $name(&self, id: usize, user: &User, x: $x) -> Result<()> {
|
||||||
let y = self.$select_fn(id).await?;
|
let y = self.$select_fn(id).await?;
|
||||||
|
|
||||||
if user.id != y.owner {
|
if user.id != y.owner {
|
||||||
|
@ -309,7 +311,7 @@ macro_rules! auto_method {
|
||||||
};
|
};
|
||||||
|
|
||||||
($name:ident($x:ty)@$select_fn:ident:$permission:ident -> $query:literal --serde) => {
|
($name:ident($x:ty)@$select_fn:ident:$permission:ident -> $query:literal --serde) => {
|
||||||
pub async fn $name(&self, id: usize, user: User, x: $x) -> Result<()> {
|
pub async fn $name(&self, id: usize, user: &User, x: $x) -> Result<()> {
|
||||||
let y = self.$select_fn(id).await?;
|
let y = self.$select_fn(id).await?;
|
||||||
|
|
||||||
if user.id != y.owner {
|
if user.id != y.owner {
|
||||||
|
@ -344,7 +346,7 @@ macro_rules! auto_method {
|
||||||
};
|
};
|
||||||
|
|
||||||
($name:ident($x:ty)@$select_fn:ident:$permission:ident -> $query:literal --serde --cache-key-tmpl=$cache_key_tmpl:literal) => {
|
($name:ident($x:ty)@$select_fn:ident:$permission:ident -> $query:literal --serde --cache-key-tmpl=$cache_key_tmpl:literal) => {
|
||||||
pub async fn $name(&self, id: usize, user: User, x: $x) -> Result<()> {
|
pub async fn $name(&self, id: usize, user: &User, x: $x) -> Result<()> {
|
||||||
let y = self.$select_fn(id).await?;
|
let y = self.$select_fn(id).await?;
|
||||||
|
|
||||||
if user.id != y.owner {
|
if user.id != y.owner {
|
||||||
|
@ -499,7 +501,7 @@ macro_rules! auto_method {
|
||||||
};
|
};
|
||||||
|
|
||||||
($name:ident()@$select_fn:ident:$permission:ident -> $query:literal --cache-key-tmpl=$cache_key_tmpl:ident) => {
|
($name:ident()@$select_fn:ident:$permission:ident -> $query:literal --cache-key-tmpl=$cache_key_tmpl:ident) => {
|
||||||
pub async fn $name(&self, id: usize, user: User) -> Result<()> {
|
pub async fn $name(&self, id: usize, user: &User) -> Result<()> {
|
||||||
let y = self.$select_fn(id).await?;
|
let y = self.$select_fn(id).await?;
|
||||||
|
|
||||||
if user.id != y.owner {
|
if user.id != y.owner {
|
||||||
|
@ -532,7 +534,7 @@ macro_rules! auto_method {
|
||||||
};
|
};
|
||||||
|
|
||||||
($name:ident($x:ty)@$select_fn:ident:$permission:ident -> $query:literal --cache-key-tmpl=$cache_key_tmpl:ident) => {
|
($name:ident($x:ty)@$select_fn:ident:$permission:ident -> $query:literal --cache-key-tmpl=$cache_key_tmpl:ident) => {
|
||||||
pub async fn $name(&self, id: usize, user: User, x: $x) -> Result<()> {
|
pub async fn $name(&self, id: usize, user: &User, x: $x) -> Result<()> {
|
||||||
let y = self.$select_fn(id).await?;
|
let y = self.$select_fn(id).await?;
|
||||||
|
|
||||||
if user.id != y.owner {
|
if user.id != y.owner {
|
||||||
|
@ -611,7 +613,7 @@ macro_rules! auto_method {
|
||||||
};
|
};
|
||||||
|
|
||||||
($name:ident($x:ty)@$select_fn:ident:$permission:ident -> $query:literal --serde --cache-key-tmpl=$cache_key_tmpl:ident) => {
|
($name:ident($x:ty)@$select_fn:ident:$permission:ident -> $query:literal --serde --cache-key-tmpl=$cache_key_tmpl:ident) => {
|
||||||
pub async fn $name(&self, id: usize, user: User, x: $x) -> Result<()> {
|
pub async fn $name(&self, id: usize, user: &User, x: $x) -> Result<()> {
|
||||||
let y = self.$select_fn(id).await?;
|
let y = self.$select_fn(id).await?;
|
||||||
|
|
||||||
if user.id != y.owner {
|
if user.id != y.owner {
|
||||||
|
|
|
@ -12,5 +12,6 @@ CREATE TABLE IF NOT EXISTS posts (
|
||||||
-- other counts
|
-- other counts
|
||||||
comment_count INT NOT NULL,
|
comment_count INT NOT NULL,
|
||||||
-- ...
|
-- ...
|
||||||
uploads TEXT NOT NULL
|
uploads TEXT NOT NULL,
|
||||||
|
is_deleted INT NOT NULL
|
||||||
)
|
)
|
||||||
|
|
|
@ -42,6 +42,7 @@ impl DataManager {
|
||||||
comment_count: get!(x->9(i32)) as usize,
|
comment_count: get!(x->9(i32)) as usize,
|
||||||
// ...
|
// ...
|
||||||
uploads: serde_json::from_str(&get!(x->10(String))).unwrap(),
|
uploads: serde_json::from_str(&get!(x->10(String))).unwrap(),
|
||||||
|
is_deleted: get!(x->11(i32)) as i8 == 1,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -195,6 +196,8 @@ impl DataManager {
|
||||||
|
|
||||||
// check relationship
|
// check relationship
|
||||||
if ua.settings.private_profile {
|
if ua.settings.private_profile {
|
||||||
|
// if someone were to look for places to optimize memory usage,
|
||||||
|
// look no further than here
|
||||||
if let Some(ua1) = user {
|
if let Some(ua1) = user {
|
||||||
if ua1.id == 0 {
|
if ua1.id == 0 {
|
||||||
continue;
|
continue;
|
||||||
|
@ -202,7 +205,10 @@ impl DataManager {
|
||||||
|
|
||||||
if let Some(is_following) = seen_user_follow_statuses.get(&(ua.id, ua1.id))
|
if let Some(is_following) = seen_user_follow_statuses.get(&(ua.id, ua1.id))
|
||||||
{
|
{
|
||||||
if !is_following && (ua.id != ua1.id) {
|
if !is_following
|
||||||
|
&& (ua.id != ua1.id)
|
||||||
|
&& !ua1.permissions.check(FinePermission::MANAGE_POSTS)
|
||||||
|
{
|
||||||
// post owner is not following us
|
// post owner is not following us
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -211,6 +217,7 @@ impl DataManager {
|
||||||
.get_userfollow_by_initiator_receiver(ua.id, ua1.id)
|
.get_userfollow_by_initiator_receiver(ua.id, ua1.id)
|
||||||
.await
|
.await
|
||||||
.is_err()
|
.is_err()
|
||||||
|
&& !ua1.permissions.check(FinePermission::MANAGE_POSTS)
|
||||||
{
|
{
|
||||||
// post owner is not following us
|
// post owner is not following us
|
||||||
seen_user_follow_statuses.insert((ua.id, ua1.id), false);
|
seen_user_follow_statuses.insert((ua.id, ua1.id), false);
|
||||||
|
@ -1105,7 +1112,7 @@ impl DataManager {
|
||||||
|
|
||||||
let res = execute!(
|
let res = execute!(
|
||||||
&conn,
|
&conn,
|
||||||
"INSERT INTO posts VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11)",
|
"INSERT INTO posts VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12)",
|
||||||
params![
|
params![
|
||||||
&(data.id as i64),
|
&(data.id as i64),
|
||||||
&(data.created as i64),
|
&(data.created as i64),
|
||||||
|
@ -1121,7 +1128,8 @@ impl DataManager {
|
||||||
&0_i32,
|
&0_i32,
|
||||||
&0_i32,
|
&0_i32,
|
||||||
&0_i32,
|
&0_i32,
|
||||||
&serde_json::to_string(&data.uploads).unwrap()
|
&serde_json::to_string(&data.uploads).unwrap(),
|
||||||
|
&{ if data.is_deleted { 1 } else { 0 } }
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -1212,7 +1220,7 @@ impl DataManager {
|
||||||
let question = self.get_question_by_id(y.context.answering).await?;
|
let question = self.get_question_by_id(y.context.answering).await?;
|
||||||
|
|
||||||
if question.is_global {
|
if question.is_global {
|
||||||
self.incr_question_answer_count(y.context.answering).await?;
|
self.decr_question_answer_count(y.context.answering).await?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1225,6 +1233,94 @@ impl DataManager {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn fake_delete_post(&self, id: usize, user: User, is_deleted: bool) -> Result<()> {
|
||||||
|
let y = self.get_post_by_id(id).await?;
|
||||||
|
|
||||||
|
let user_membership = self
|
||||||
|
.get_membership_by_owner_community(user.id, y.community)
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
if (user.id != y.owner)
|
||||||
|
&& !user_membership
|
||||||
|
.role
|
||||||
|
.check(CommunityPermission::MANAGE_POSTS)
|
||||||
|
{
|
||||||
|
if !user.permissions.check(FinePermission::MANAGE_POSTS) {
|
||||||
|
return Err(Error::NotAllowed);
|
||||||
|
} else {
|
||||||
|
self.create_audit_log_entry(AuditLogEntry::new(
|
||||||
|
user.id,
|
||||||
|
format!("invoked `fake_delete_post` with x value `{id}`"),
|
||||||
|
))
|
||||||
|
.await?
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let conn = match self.connect().await {
|
||||||
|
Ok(c) => c,
|
||||||
|
Err(e) => return Err(Error::DatabaseConnection(e.to_string())),
|
||||||
|
};
|
||||||
|
|
||||||
|
let res = execute!(
|
||||||
|
&conn,
|
||||||
|
"UPDATE posts SET is_deleted = $1 WHERE id = $2",
|
||||||
|
params![if is_deleted { 1 } else { 0 }, &(id as i64)]
|
||||||
|
);
|
||||||
|
|
||||||
|
if let Err(e) = res {
|
||||||
|
return Err(Error::DatabaseError(e.to_string()));
|
||||||
|
}
|
||||||
|
|
||||||
|
self.2.remove(format!("atto.post:{}", id)).await;
|
||||||
|
|
||||||
|
if is_deleted {
|
||||||
|
// decr parent comment count
|
||||||
|
if let Some(replying_to) = y.replying_to {
|
||||||
|
self.decr_post_comments(replying_to).await.unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
// decr user post count
|
||||||
|
let owner = self.get_user_by_id(y.owner).await?;
|
||||||
|
|
||||||
|
if owner.post_count > 0 {
|
||||||
|
self.decr_user_post_count(y.owner).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?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// incr parent comment count
|
||||||
|
if let Some(replying_to) = y.replying_to {
|
||||||
|
self.incr_post_comments(replying_to).await.unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
// incr user post count
|
||||||
|
let owner = self.get_user_by_id(y.owner).await?;
|
||||||
|
|
||||||
|
if owner.post_count > 0 {
|
||||||
|
self.incr_user_post_count(y.owner).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?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// return
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
pub async fn update_post_context(
|
pub async fn update_post_context(
|
||||||
&self,
|
&self,
|
||||||
id: usize,
|
id: usize,
|
||||||
|
|
|
@ -238,6 +238,8 @@ pub struct Post {
|
||||||
pub comment_count: usize,
|
pub comment_count: usize,
|
||||||
/// IDs of all uploads linked to this post.
|
/// IDs of all uploads linked to this post.
|
||||||
pub uploads: Vec<usize>,
|
pub uploads: Vec<usize>,
|
||||||
|
/// If the post was deleted.
|
||||||
|
pub is_deleted: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Post {
|
impl Post {
|
||||||
|
@ -260,6 +262,7 @@ impl Post {
|
||||||
dislikes: 0,
|
dislikes: 0,
|
||||||
comment_count: 0,
|
comment_count: 0,
|
||||||
uploads: Vec::new(),
|
uploads: Vec::new(),
|
||||||
|
is_deleted: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
2
sql_changes/posts_is_deleted.sql
Normal file
2
sql_changes/posts_is_deleted.sql
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
ALTER TABLE posts
|
||||||
|
ADD COLUMN is_deleted INT NOT NULL DEFAULT 0;
|
Loading…
Add table
Add a link
Reference in a new issue