diff --git a/plume-models/src/comments.rs b/plume-models/src/comments.rs index 2f06dada..91e7c6c2 100644 --- a/plume-models/src/comments.rs +++ b/plume-models/src/comments.rs @@ -422,6 +422,7 @@ impl CommentTree { mod tests { use super::*; use crate::blogs::Blog; + use crate::db_conn::DbConn; use crate::inbox::{inbox, tests::fill_database, InboxResult}; use crate::safe_string::SafeString; use crate::tests::{db, format_datetime}; diff --git a/plume-models/src/follows.rs b/plume-models/src/follows.rs index 8f79430b..f20bdd79 100644 --- a/plume-models/src/follows.rs +++ b/plume-models/src/follows.rs @@ -232,7 +232,9 @@ impl IntoId for Follow { #[cfg(test)] mod tests { 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 diesel::Connection; use serde_json::{json, to_value}; diff --git a/plume-models/src/posts.rs b/plume-models/src/posts.rs index d9a63c3b..80fdba32 100644 --- a/plume-models/src/posts.rs +++ b/plume-models/src/posts.rs @@ -1027,6 +1027,7 @@ impl From for Arc { #[cfg(test)] mod tests { use super::*; + use crate::db_conn::DbConn; use crate::inbox::{inbox, tests::fill_database, InboxResult}; use crate::mentions::{Mention, NewMention}; use crate::safe_string::SafeString; diff --git a/plume-models/src/users.rs b/plume-models/src/users.rs index b3dd0368..82b7ab19 100644 --- a/plume-models/src/users.rs +++ b/plume-models/src/users.rs @@ -15,7 +15,10 @@ use activitystreams::{ prelude::*, }; 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 openssl::{ hash::MessageDigest, @@ -186,6 +189,7 @@ impl User { pub fn count_local(conn: &Connection) -> Result { users::table .filter(users::instance_id.eq(Instance::get_local()?.id)) + .filter(users::role.ne(Role::Instance as i32)) .count() .get_result(conn) .map_err(Error::from) @@ -203,6 +207,27 @@ impl User { } } + pub fn search_local_by_name( + conn: &Connection, + name: &str, + (min, max): (i32, i32), + ) -> Result> { + 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::(conn) + .map_err(Error::from) + } + /** * TODO: Should create user record with normalized(lowercased) email */ @@ -431,6 +456,7 @@ impl User { pub fn get_local_page(conn: &Connection, (min, max): (i32, i32)) -> Result> { users::table .filter(users::instance_id.eq(Instance::get_local()?.id)) + .filter(users::role.ne(Role::Instance as i32)) .order(users::username.asc()) .offset(min.into()) .limit((max - min).into()) diff --git a/src/main.rs b/src/main.rs index 5e3c0e78..cd5fb96a 100755 --- a/src/main.rs +++ b/src/main.rs @@ -157,6 +157,7 @@ Then try to restart Plume. routes::instance::admin_mod, routes::instance::admin_instances, routes::instance::admin_users, + routes::instance::admin_search_users, routes::instance::admin_email_blocklist, routes::instance::add_email_blocklist, routes::instance::delete_email_blocklist, diff --git a/src/routes/instance.rs b/src/routes/instance.rs index b4ac399b..9de9fee0 100644 --- a/src/routes/instance.rs +++ b/src/routes/instance.rs @@ -160,7 +160,7 @@ pub fn toggle_block( )) } -#[get("/admin/users?")] +#[get("/admin/users?", rank = 2)] pub fn admin_users( _mod: Moderator, page: Option, @@ -171,6 +171,30 @@ pub fn admin_users( Ok(render!(instance::users( &(&conn, &rockets).to_context(), User::get_local_page(&conn, page.limits())?, + None, + page.0, + Page::total(User::count_local(&conn)? as i32) + ))) +} +#[get("/admin/users?&", rank = 1)] +pub fn admin_search_users( + _mod: Moderator, + user: String, + page: Option, + conn: DbConn, + rockets: PlumeRocket, +) -> Result { + 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::total(User::count_local(&conn)? as i32) ))) diff --git a/templates/instance/users.rs.html b/templates/instance/users.rs.html index 8bcf48e7..1499fb52 100644 --- a/templates/instance/users.rs.html +++ b/templates/instance/users.rs.html @@ -3,7 +3,7 @@ @use crate::template_utils::*; @use crate::routes::*; -@(ctx: BaseContext, users: Vec, page: i32, n_pages: i32) +@(ctx: BaseContext, users: Vec, user: Option<&str>, page: i32, n_pages: i32) @:base(ctx, i18n!(ctx.1, "Users"), {}, {}, {

@i18n!(ctx.1, "Users")

@@ -15,6 +15,13 @@ (&uri!(instance::admin_email_blocklist: page=_).to_string(), i18n!(ctx.1, "Email blocklist"), false) ]) +
+
+ + +
+
+