Compare commits

...

14 Commits

Author SHA1 Message Date
trinity-1686a e1777e9071 delete comments properly when deleting users 2023-04-09 12:54:29 +02:00
KitaitiMakoto 613ccbcd94 Merge pull request 'Add user search form to admin panel' (#1143) from moderation-improvement into main
Reviewed-on: https://git.joinplu.me/Plume/Plume/pulls/1143
2023-03-21 10:29:33 +00:00
Kitaiti Makoto b9a09a2511 Follow pagination user list page change 2023-03-21 19:15:22 +09:00
Kitaiti Makoto 213628e400 Don't use LIKE query when username is empty for user search 2023-03-21 19:07:09 +09:00
Kitaiti Makoto d6bb2bfb72 Use unwrap_or_default() instead of unwrap_or("") 2023-03-21 18:49:52 +09:00
Kitaiti Makoto 33bd290679 Use DbConn in model tests 2023-03-20 01:21:39 +09:00
Kitaiti Makoto 85ab5393fd Set style to user search form 2023-03-20 01:03:09 +09:00
Kitaiti Makoto 98c73bb6df Add search form to user list page 2023-03-20 01:00:17 +09:00
Kitaiti Makoto 3e9d9a459f Enable admin_search_user route 2023-03-20 01:00:02 +09:00
Kitaiti Makoto a394c3f210 Define admin_search_user route 2023-03-20 00:59:46 +09:00
Kitaiti Makoto a1a19e091a Define User::search_local_by_name() method 2023-03-20 00:59:16 +09:00
Kitaiti Makoto ec030d500d Exclude instance user when counting local users 2023-03-20 00:19:42 +09:00
Kitaiti Makoto cfa74f84e7 Remove instance users from user list to show 2023-03-06 19:30:18 +09:00
trinity-1686a 97cbe7f446 Merge pull request 'allow timeline manipulation from plm' (#1113) from timeline-cli into main
Reviewed-on: https://git.joinplu.me/Plume/Plume/pulls/1113
Reviewed-by: KitaitiMakoto <kitaitimakoto@noreply@joinplu.me>
2023-02-26 15:56:16 +00:00
8 changed files with 87 additions and 12 deletions
+2
View File
@@ -73,6 +73,7 @@ impl Comment {
}); });
get!(comments); get!(comments);
list_by!(comments, list_by_post, post_id as i32); list_by!(comments, list_by_post, post_id as i32);
list_by!(comments, list_by_author, author_id as i32);
find_by!(comments, find_by_ap_url, ap_url as &str); find_by!(comments, find_by_ap_url, ap_url as &str);
pub fn get_author(&self, conn: &Connection) -> Result<User> { pub fn get_author(&self, conn: &Connection) -> Result<User> {
@@ -422,6 +423,7 @@ impl CommentTree {
mod tests { mod tests {
use super::*; use super::*;
use crate::blogs::Blog; use crate::blogs::Blog;
use crate::db_conn::DbConn;
use crate::inbox::{inbox, tests::fill_database, InboxResult}; use crate::inbox::{inbox, tests::fill_database, InboxResult};
use crate::safe_string::SafeString; use crate::safe_string::SafeString;
use crate::tests::{db, format_datetime}; use crate::tests::{db, format_datetime};
+3 -1
View File
@@ -232,7 +232,9 @@ impl IntoId for Follow {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
use crate::{tests::db, users::tests as user_tests, users::tests::fill_database}; use crate::{
db_conn::DbConn, tests::db, users::tests as user_tests, users::tests::fill_database,
};
use assert_json_diff::assert_json_eq; use assert_json_diff::assert_json_eq;
use diesel::Connection; use diesel::Connection;
use serde_json::{json, to_value}; use serde_json::{json, to_value};
+3 -3
View File
@@ -7,7 +7,7 @@ use crate::{
posts::{Post, PostUpdate}, posts::{Post, PostUpdate},
reshares::Reshare, reshares::Reshare,
users::User, users::User,
Error, CONFIG, Connection, Error, CONFIG,
}; };
use plume_common::activity_pub::inbox::Inbox; use plume_common::activity_pub::inbox::Inbox;
@@ -46,8 +46,8 @@ impl_into_inbox_result! {
Reshare => Reshared Reshare => Reshared
} }
pub fn inbox(conn: &DbConn, act: serde_json::Value) -> Result<InboxResult, Error> { pub fn inbox(conn: &Connection, act: serde_json::Value) -> Result<InboxResult, Error> {
Inbox::handle(&**conn, act) Inbox::handle(conn, act)
.with::<User, Announce, Post>(CONFIG.proxy()) .with::<User, Announce, Post>(CONFIG.proxy())
.with::<User, Create, Comment>(CONFIG.proxy()) .with::<User, Create, Comment>(CONFIG.proxy())
.with::<User, Create, Post>(CONFIG.proxy()) .with::<User, Create, Post>(CONFIG.proxy())
+1
View File
@@ -1027,6 +1027,7 @@ impl From<PostEvent> for Arc<Post> {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
use crate::db_conn::DbConn;
use crate::inbox::{inbox, tests::fill_database, InboxResult}; use crate::inbox::{inbox, tests::fill_database, InboxResult};
use crate::mentions::{Mention, NewMention}; use crate::mentions::{Mention, NewMention};
use crate::safe_string::SafeString; use crate::safe_string::SafeString;
+39 -5
View File
@@ -1,8 +1,8 @@
use crate::{ use crate::{
ap_url, blocklisted_emails::BlocklistedEmail, blogs::Blog, db_conn::DbConn, follows::Follow, ap_url, blocklisted_emails::BlocklistedEmail, blogs::Blog, comments::Comment, db_conn::DbConn,
instance::*, medias::Media, notifications::Notification, post_authors::PostAuthor, posts::Post, follows::Follow, instance::*, medias::Media, notifications::Notification,
safe_string::SafeString, schema::users, timeline::Timeline, Connection, Error, Result, post_authors::PostAuthor, posts::Post, safe_string::SafeString, schema::users,
UserEvent::*, CONFIG, ITEMS_PER_PAGE, USER_CHAN, timeline::Timeline, Connection, Error, Result, UserEvent::*, CONFIG, ITEMS_PER_PAGE, USER_CHAN,
}; };
use activitystreams::{ use activitystreams::{
activity::Delete, activity::Delete,
@@ -15,7 +15,10 @@ use activitystreams::{
prelude::*, prelude::*,
}; };
use chrono::{NaiveDateTime, Utc}; use chrono::{NaiveDateTime, Utc};
use diesel::{self, BelongingToDsl, ExpressionMethods, OptionalExtension, QueryDsl, RunQueryDsl}; use diesel::{
self, BelongingToDsl, BoolExpressionMethods, ExpressionMethods, OptionalExtension, QueryDsl,
RunQueryDsl, TextExpressionMethods,
};
use ldap3::{LdapConn, Scope, SearchEntry}; use ldap3::{LdapConn, Scope, SearchEntry};
use openssl::{ use openssl::{
hash::MessageDigest, hash::MessageDigest,
@@ -165,6 +168,14 @@ impl User {
notif.delete(conn)? notif.delete(conn)?
} }
for comment in Comment::list_by_author(conn, self.id)? {
let delete_activity = comment.build_delete(&conn)?;
crate::inbox::inbox(
conn,
serde_json::to_value(&delete_activity).map_err(Error::from)?,
)?;
}
diesel::delete(self) diesel::delete(self)
.execute(conn) .execute(conn)
.map(|_| ()) .map(|_| ())
@@ -186,6 +197,7 @@ impl User {
pub fn count_local(conn: &Connection) -> Result<i64> { pub fn count_local(conn: &Connection) -> Result<i64> {
users::table users::table
.filter(users::instance_id.eq(Instance::get_local()?.id)) .filter(users::instance_id.eq(Instance::get_local()?.id))
.filter(users::role.ne(Role::Instance as i32))
.count() .count()
.get_result(conn) .get_result(conn)
.map_err(Error::from) .map_err(Error::from)
@@ -203,6 +215,27 @@ impl User {
} }
} }
pub fn search_local_by_name(
conn: &Connection,
name: &str,
(min, max): (i32, i32),
) -> Result<Vec<User>> {
users::table
.filter(users::instance_id.eq(Instance::get_local()?.id))
.filter(users::role.ne(Role::Instance as i32))
// TODO: use `ilike` instead of `like` for PostgreSQL
.filter(
users::username
.like(format!("%{}%", name))
.or(users::display_name.like(format!("%{}%", name))),
)
.order(users::username.asc())
.offset(min.into())
.limit((max - min).into())
.load::<User>(conn)
.map_err(Error::from)
}
/** /**
* TODO: Should create user record with normalized(lowercased) email * TODO: Should create user record with normalized(lowercased) email
*/ */
@@ -431,6 +464,7 @@ impl User {
pub fn get_local_page(conn: &Connection, (min, max): (i32, i32)) -> Result<Vec<User>> { pub fn get_local_page(conn: &Connection, (min, max): (i32, i32)) -> Result<Vec<User>> {
users::table users::table
.filter(users::instance_id.eq(Instance::get_local()?.id)) .filter(users::instance_id.eq(Instance::get_local()?.id))
.filter(users::role.ne(Role::Instance as i32))
.order(users::username.asc()) .order(users::username.asc())
.offset(min.into()) .offset(min.into())
.limit((max - min).into()) .limit((max - min).into())
+1
View File
@@ -157,6 +157,7 @@ Then try to restart Plume.
routes::instance::admin_mod, routes::instance::admin_mod,
routes::instance::admin_instances, routes::instance::admin_instances,
routes::instance::admin_users, routes::instance::admin_users,
routes::instance::admin_search_users,
routes::instance::admin_email_blocklist, routes::instance::admin_email_blocklist,
routes::instance::add_email_blocklist, routes::instance::add_email_blocklist,
routes::instance::delete_email_blocklist, routes::instance::delete_email_blocklist,
+25 -1
View File
@@ -160,7 +160,7 @@ pub fn toggle_block(
)) ))
} }
#[get("/admin/users?<page>")] #[get("/admin/users?<page>", rank = 2)]
pub fn admin_users( pub fn admin_users(
_mod: Moderator, _mod: Moderator,
page: Option<Page>, page: Option<Page>,
@@ -171,6 +171,30 @@ pub fn admin_users(
Ok(render!(instance::users( Ok(render!(instance::users(
&(&conn, &rockets).to_context(), &(&conn, &rockets).to_context(),
User::get_local_page(&conn, page.limits())?, User::get_local_page(&conn, page.limits())?,
None,
page.0,
Page::total(User::count_local(&conn)? as i32)
)))
}
#[get("/admin/users?<user>&<page>", rank = 1)]
pub fn admin_search_users(
_mod: Moderator,
user: String,
page: Option<Page>,
conn: DbConn,
rockets: PlumeRocket,
) -> Result<Ructe, ErrorPage> {
let page = page.unwrap_or_default();
let users = if user.is_empty() {
User::get_local_page(&conn, page.limits())?
} else {
User::search_local_by_name(&conn, &user, page.limits())?
};
Ok(render!(instance::users(
&(&conn, &rockets).to_context(),
users,
Some(user.as_str()),
page.0, page.0,
Page::total(User::count_local(&conn)? as i32) Page::total(User::count_local(&conn)? as i32)
))) )))
+13 -2
View File
@@ -3,7 +3,7 @@
@use crate::template_utils::*; @use crate::template_utils::*;
@use crate::routes::*; @use crate::routes::*;
@(ctx: BaseContext, users: Vec<User>, page: i32, n_pages: i32) @(ctx: BaseContext, users: Vec<User>, user: Option<&str>, page: i32, n_pages: i32)
@:base(ctx, i18n!(ctx.1, "Users"), {}, {}, { @:base(ctx, i18n!(ctx.1, "Users"), {}, {}, {
<h1>@i18n!(ctx.1, "Users")</h1> <h1>@i18n!(ctx.1, "Users")</h1>
@@ -15,6 +15,13 @@
(&uri!(instance::admin_email_blocklist: page=_).to_string(), i18n!(ctx.1, "Email blocklist"), false) (&uri!(instance::admin_email_blocklist: page=_).to_string(), i18n!(ctx.1, "Email blocklist"), false)
]) ])
<form method="get" action="@uri!(instance::admin_search_users: page = _, user = user.unwrap_or_default())">
<header>
<input type="search" name="user" value="@user.unwrap_or_default()">
<input type="submit" value="@i18n!(ctx.1, "Search users")">
</header>
</form>
<form method="post" action="@uri!(instance::edit_users)"> <form method="post" action="@uri!(instance::edit_users)">
<header> <header>
<select name="action"> <select name="action">
@@ -46,5 +53,9 @@
} }
</div> </div>
</form> </form>
@paginate(ctx.1, page, n_pages) @if user.is_some() {
@paginate_param(ctx.1, page, n_pages, Some(format!("user={}", encode_query_param(user.unwrap_or_default()))))
} else {
@paginate(ctx.1, page, n_pages)
}
}) })