mirror of
https://github.com/LemmyNet/lemmy.git
synced 2024-12-22 10:51:29 +00:00
Merge branch 'combined_modlog' into combined_inbox
This commit is contained in:
commit
17d2de8691
21 changed files with 78 additions and 129 deletions
|
@ -74,6 +74,9 @@ test("Set some user settings, check that they are federated", async () => {
|
|||
|
||||
test("Delete user", async () => {
|
||||
let user = await registerUser(alpha, alphaUrl);
|
||||
let user_profile = await getMyUser(user);
|
||||
let person_id = user_profile.local_user_view.person.id;
|
||||
let actor_id = user_profile.local_user_view.person.actor_id;
|
||||
|
||||
// make a local post and comment
|
||||
let alphaCommunity = (await resolveCommunity(user, "main@lemmy-alpha:8541"))
|
||||
|
@ -101,6 +104,10 @@ test("Delete user", async () => {
|
|||
expect(remoteComment).toBeDefined();
|
||||
|
||||
await deleteUser(user);
|
||||
await expect(getMyUser(user)).rejects.toStrictEqual(Error("incorrect_login"));
|
||||
await expect(getPersonDetails(user, person_id)).rejects.toStrictEqual(
|
||||
Error("not_found"),
|
||||
);
|
||||
|
||||
// check that posts and comments are marked as deleted on other instances.
|
||||
// use get methods to avoid refetching from origin instance
|
||||
|
@ -118,6 +125,9 @@ test("Delete user", async () => {
|
|||
(await getComments(alpha, remoteComment.post_id)).comments[0].comment
|
||||
.deleted,
|
||||
).toBe(true);
|
||||
await expect(
|
||||
getPersonDetails(user, remoteComment.creator_id),
|
||||
).rejects.toStrictEqual(Error("not_found"));
|
||||
});
|
||||
|
||||
test("Requests with invalid auth should be treated as unauthenticated", async () => {
|
||||
|
|
|
@ -1,11 +1,7 @@
|
|||
{
|
||||
# settings related to the postgresql database
|
||||
database: {
|
||||
# Configure the database by specifying a URI
|
||||
#
|
||||
# This is the preferred method to specify database connection details since
|
||||
# it is the most flexible.
|
||||
# Connection URI pointing to a postgres instance
|
||||
# Configure the database by specifying URI pointing to a postgres instance
|
||||
#
|
||||
# This example uses peer authentication to obviate the need for creating,
|
||||
# configuring, and managing passwords.
|
||||
|
@ -14,25 +10,7 @@
|
|||
# PostgreSQL's documentation.
|
||||
#
|
||||
# [0]: https://www.postgresql.org/docs/current/libpq-connect.html#id-1.7.3.8.3.6
|
||||
uri: "postgresql:///lemmy?user=lemmy&host=/var/run/postgresql"
|
||||
|
||||
# or
|
||||
|
||||
# Configure the database by specifying parts of a URI
|
||||
#
|
||||
# Note that specifying the `uri` field should be preferred since it provides
|
||||
# greater control over how the connection is made. This merely exists for
|
||||
# backwards-compatibility.
|
||||
# Username to connect to postgres
|
||||
user: "string"
|
||||
# Password to connect to postgres
|
||||
password: "string"
|
||||
# Host where postgres is running
|
||||
host: "string"
|
||||
# Port where postgres can be accessed
|
||||
port: 123
|
||||
# Name of the postgres database for lemmy
|
||||
database: "string"
|
||||
connection: "postgres://lemmy:password@localhost:5432/lemmy"
|
||||
# Maximum number of active sql connections
|
||||
pool_size: 30
|
||||
}
|
||||
|
|
|
@ -110,7 +110,7 @@ pub async fn ban_from_community(
|
|||
|
||||
ModBanFromCommunity::create(&mut context.pool(), &form).await?;
|
||||
|
||||
let person_view = PersonView::read(&mut context.pool(), data.person_id).await?;
|
||||
let person_view = PersonView::read(&mut context.pool(), data.person_id, false).await?;
|
||||
|
||||
ActivityChannel::submit_activity(
|
||||
SendActivityData::BanFromCommunity {
|
||||
|
|
|
@ -88,7 +88,7 @@ pub async fn ban_from_site(
|
|||
|
||||
ModBan::create(&mut context.pool(), &form).await?;
|
||||
|
||||
let person_view = PersonView::read(&mut context.pool(), person.id).await?;
|
||||
let person_view = PersonView::read(&mut context.pool(), person.id, false).await?;
|
||||
|
||||
ban_nonlocal_user_from_local_communities(
|
||||
&local_user_view,
|
||||
|
|
|
@ -48,7 +48,7 @@ pub async fn user_block_person(
|
|||
.with_lemmy_type(LemmyErrorType::PersonBlockAlreadyExists)?;
|
||||
}
|
||||
|
||||
let person_view = PersonView::read(&mut context.pool(), target_id).await?;
|
||||
let person_view = PersonView::read(&mut context.pool(), target_id, false).await?;
|
||||
Ok(Json(BlockPersonResponse {
|
||||
person_view,
|
||||
blocked: data.block,
|
||||
|
|
|
@ -123,8 +123,6 @@ pub fn is_admin(local_user_view: &LocalUserView) -> LemmyResult<()> {
|
|||
check_user_valid(&local_user_view.person)?;
|
||||
if !local_user_view.local_user.admin {
|
||||
Err(LemmyErrorType::NotAnAdmin)?
|
||||
} else if local_user_view.person.banned {
|
||||
Err(LemmyErrorType::Banned)?
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use actix_web::web::{Data, Json};
|
||||
use lemmy_api_common::{context::LemmyContext, site::MyUserInfo};
|
||||
use lemmy_api_common::{context::LemmyContext, site::MyUserInfo, utils::check_user_valid};
|
||||
use lemmy_db_schema::source::{
|
||||
actor_language::LocalUserLanguage,
|
||||
community_block::CommunityBlock,
|
||||
|
@ -15,6 +15,8 @@ pub async fn get_my_user(
|
|||
local_user_view: LocalUserView,
|
||||
context: Data<LemmyContext>,
|
||||
) -> LemmyResult<Json<MyUserInfo>> {
|
||||
check_user_valid(&local_user_view.person)?;
|
||||
|
||||
// Build the local user with parallel queries and add it to site response
|
||||
let person_id = local_user_view.person.id;
|
||||
let local_user_id = local_user_view.local_user.id;
|
||||
|
|
|
@ -4,7 +4,7 @@ use actix_web::web::{Json, Query};
|
|||
use lemmy_api_common::{
|
||||
context::LemmyContext,
|
||||
person::{GetPersonDetails, GetPersonDetailsResponse},
|
||||
utils::{check_private_instance, read_site_for_actor},
|
||||
utils::{check_private_instance, is_admin, read_site_for_actor},
|
||||
};
|
||||
use lemmy_db_views::structs::{LocalUserView, SiteView};
|
||||
use lemmy_db_views_actor::structs::{CommunityModeratorView, PersonView};
|
||||
|
@ -30,7 +30,12 @@ pub async fn read_person(
|
|||
|
||||
// You don't need to return settings for the user, since this comes back with GetSite
|
||||
// `my_user`
|
||||
let person_view = PersonView::read(&mut context.pool(), person_details_id).await?;
|
||||
let is_admin = local_user_view
|
||||
.as_ref()
|
||||
.map(|l| is_admin(l).is_ok())
|
||||
.unwrap_or_default();
|
||||
let person_view = PersonView::read(&mut context.pool(), person_details_id, is_admin).await?;
|
||||
|
||||
let moderates = CommunityModeratorView::for_person(
|
||||
&mut context.pool(),
|
||||
person_details_id,
|
||||
|
|
|
@ -60,7 +60,7 @@ async fn convert_response(
|
|||
}
|
||||
},
|
||||
SearchableObjects::PersonOrCommunity(pc) => match *pc {
|
||||
UserOrCommunity::User(u) => res.person = Some(PersonView::read(pool, u.id).await?),
|
||||
UserOrCommunity::User(u) => res.person = Some(PersonView::read(pool, u.id, is_admin).await?),
|
||||
UserOrCommunity::Community(c) => {
|
||||
res.community = Some(CommunityView::read(pool, c.id, local_user.as_ref(), is_admin).await?)
|
||||
}
|
||||
|
|
|
@ -188,7 +188,7 @@ impl CommunityView {
|
|||
let is_mod =
|
||||
CommunityModeratorView::check_is_community_moderator(pool, community_id, person_id).await;
|
||||
if is_mod.is_ok()
|
||||
|| PersonView::read(pool, person_id)
|
||||
|| PersonView::read(pool, person_id, false)
|
||||
.await
|
||||
.is_ok_and(|t| t.is_admin)
|
||||
{
|
||||
|
@ -206,7 +206,7 @@ impl CommunityView {
|
|||
let is_mod_of_any =
|
||||
CommunityModeratorView::is_community_moderator_of_any(pool, person_id).await;
|
||||
if is_mod_of_any.is_ok()
|
||||
|| PersonView::read(pool, person_id)
|
||||
|| PersonView::read(pool, person_id, false)
|
||||
.await
|
||||
.is_ok_and(|t| t.is_admin)
|
||||
{
|
||||
|
|
|
@ -58,12 +58,11 @@ fn post_to_person_sort_type(sort: PostSortType) -> PersonSortType {
|
|||
}
|
||||
|
||||
fn queries<'a>(
|
||||
) -> Queries<impl ReadFn<'a, PersonView, PersonId>, impl ListFn<'a, PersonView, ListMode>> {
|
||||
) -> Queries<impl ReadFn<'a, PersonView, (PersonId, bool)>, impl ListFn<'a, PersonView, ListMode>> {
|
||||
let all_joins = move |query: person::BoxedQuery<'a, Pg>| {
|
||||
query
|
||||
.inner_join(person_aggregates::table)
|
||||
.left_join(local_user::table)
|
||||
.filter(person::deleted.eq(false))
|
||||
.select((
|
||||
person::all_columns,
|
||||
person_aggregates::all_columns,
|
||||
|
@ -71,14 +70,17 @@ fn queries<'a>(
|
|||
))
|
||||
};
|
||||
|
||||
let read = move |mut conn: DbConn<'a>, person_id: PersonId| async move {
|
||||
all_joins(person::table.find(person_id).into_boxed())
|
||||
.first(&mut conn)
|
||||
.await
|
||||
let read = move |mut conn: DbConn<'a>, params: (PersonId, bool)| async move {
|
||||
let (person_id, is_admin) = params;
|
||||
let mut query = all_joins(person::table.find(person_id).into_boxed());
|
||||
if !is_admin {
|
||||
query = query.filter(person::deleted.eq(false));
|
||||
}
|
||||
query.first(&mut conn).await
|
||||
};
|
||||
|
||||
let list = move |mut conn: DbConn<'a>, mode: ListMode| async move {
|
||||
let mut query = all_joins(person::table.into_boxed());
|
||||
let mut query = all_joins(person::table.into_boxed()).filter(person::deleted.eq(false));
|
||||
match mode {
|
||||
ListMode::Admins => {
|
||||
query = query
|
||||
|
@ -135,8 +137,12 @@ fn queries<'a>(
|
|||
}
|
||||
|
||||
impl PersonView {
|
||||
pub async fn read(pool: &mut DbPool<'_>, person_id: PersonId) -> Result<Self, Error> {
|
||||
queries().read(pool, person_id).await
|
||||
pub async fn read(
|
||||
pool: &mut DbPool<'_>,
|
||||
person_id: PersonId,
|
||||
is_admin: bool,
|
||||
) -> Result<Self, Error> {
|
||||
queries().read(pool, (person_id, is_admin)).await
|
||||
}
|
||||
|
||||
pub async fn admins(pool: &mut DbPool<'_>) -> Result<Vec<Self>, Error> {
|
||||
|
@ -243,9 +249,13 @@ mod tests {
|
|||
)
|
||||
.await?;
|
||||
|
||||
let read = PersonView::read(pool, data.alice.id).await;
|
||||
let read = PersonView::read(pool, data.alice.id, false).await;
|
||||
assert!(read.is_err());
|
||||
|
||||
// only admin can view deleted users
|
||||
let read = PersonView::read(pool, data.alice.id, true).await;
|
||||
assert!(read.is_ok());
|
||||
|
||||
let list = PersonQuery {
|
||||
sort: Some(PostSortType::New),
|
||||
..Default::default()
|
||||
|
@ -303,10 +313,10 @@ mod tests {
|
|||
assert_length!(1, list);
|
||||
assert_eq!(list[0].person.id, data.alice.id);
|
||||
|
||||
let is_admin = PersonView::read(pool, data.alice.id).await?.is_admin;
|
||||
let is_admin = PersonView::read(pool, data.alice.id, false).await?.is_admin;
|
||||
assert!(is_admin);
|
||||
|
||||
let is_admin = PersonView::read(pool, data.bob.id).await?.is_admin;
|
||||
let is_admin = PersonView::read(pool, data.bob.id, false).await?.is_admin;
|
||||
assert!(!is_admin);
|
||||
|
||||
cleanup(data, pool).await
|
||||
|
|
|
@ -113,7 +113,6 @@ pub enum LemmyErrorType {
|
|||
SystemErrLogin,
|
||||
CouldntSetAllRegistrationsAccepted,
|
||||
CouldntSetAllEmailVerified,
|
||||
Banned,
|
||||
BlockedUrl,
|
||||
CouldntGetComments,
|
||||
CouldntGetPosts,
|
||||
|
@ -328,9 +327,9 @@ cfg_if! {
|
|||
|
||||
#[test]
|
||||
fn deserializes_no_message() -> LemmyResult<()> {
|
||||
let err = LemmyError::from(LemmyErrorType::Banned).error_response();
|
||||
let err = LemmyError::from(LemmyErrorType::BlockedUrl).error_response();
|
||||
let json = String::from_utf8(err.into_body().try_into_bytes().unwrap_or_default().to_vec())?;
|
||||
assert_eq!(&json, "{\"error\":\"banned\"}");
|
||||
assert_eq!(&json, "{\"error\":\"blocked_url\"}");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -3,13 +3,11 @@ use anyhow::{anyhow, Context};
|
|||
use deser_hjson::from_str;
|
||||
use regex::Regex;
|
||||
use std::{env, fs, io::Error, sync::LazyLock};
|
||||
use structs::{PictrsConfig, PictrsImageMode, Settings};
|
||||
use url::Url;
|
||||
use urlencoding::encode;
|
||||
|
||||
pub mod structs;
|
||||
|
||||
use structs::{DatabaseConnection, PictrsConfig, PictrsImageMode, Settings};
|
||||
|
||||
const DEFAULT_CONFIG_FILE: &str = "config/config.hjson";
|
||||
|
||||
#[allow(clippy::expect_used)]
|
||||
|
@ -51,20 +49,9 @@ impl Settings {
|
|||
|
||||
pub fn get_database_url(&self) -> String {
|
||||
if let Ok(url) = env::var("LEMMY_DATABASE_URL") {
|
||||
return url;
|
||||
}
|
||||
match &self.database.connection {
|
||||
DatabaseConnection::Uri { uri } => uri.clone(),
|
||||
DatabaseConnection::Parts(parts) => {
|
||||
format!(
|
||||
"postgres://{}:{}@{}:{}/{}",
|
||||
encode(&parts.user),
|
||||
encode(&parts.password),
|
||||
parts.host,
|
||||
parts.port,
|
||||
encode(&parts.database),
|
||||
)
|
||||
}
|
||||
url
|
||||
} else {
|
||||
self.database.connection.clone()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -132,64 +132,24 @@ pub enum PictrsImageMode {
|
|||
#[derive(Debug, Deserialize, Serialize, Clone, SmartDefault, Document)]
|
||||
#[serde(default)]
|
||||
pub struct DatabaseConfig {
|
||||
#[serde(flatten, default)]
|
||||
pub(crate) connection: DatabaseConnection,
|
||||
/// Configure the database by specifying URI pointing to a postgres instance
|
||||
///
|
||||
/// This example uses peer authentication to obviate the need for creating,
|
||||
/// configuring, and managing passwords.
|
||||
///
|
||||
/// For an explanation of how to use connection URIs, see [here][0] in
|
||||
/// PostgreSQL's documentation.
|
||||
///
|
||||
/// [0]: https://www.postgresql.org/docs/current/libpq-connect.html#id-1.7.3.8.3.6
|
||||
#[default("postgres://lemmy:password@localhost:5432/lemmy")]
|
||||
#[doku(example = "postgresql:///lemmy?user=lemmy&host=/var/run/postgresql")]
|
||||
pub(crate) connection: String,
|
||||
|
||||
/// Maximum number of active sql connections
|
||||
#[default(30)]
|
||||
pub pool_size: usize,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, Serialize, Clone, SmartDefault, Document)]
|
||||
#[serde(untagged)]
|
||||
pub enum DatabaseConnection {
|
||||
/// Configure the database by specifying a URI
|
||||
///
|
||||
/// This is the preferred method to specify database connection details since
|
||||
/// it is the most flexible.
|
||||
Uri {
|
||||
/// Connection URI pointing to a postgres instance
|
||||
///
|
||||
/// This example uses peer authentication to obviate the need for creating,
|
||||
/// configuring, and managing passwords.
|
||||
///
|
||||
/// For an explanation of how to use connection URIs, see [here][0] in
|
||||
/// PostgreSQL's documentation.
|
||||
///
|
||||
/// [0]: https://www.postgresql.org/docs/current/libpq-connect.html#id-1.7.3.8.3.6
|
||||
#[doku(example = "postgresql:///lemmy?user=lemmy&host=/var/run/postgresql")]
|
||||
uri: String,
|
||||
},
|
||||
|
||||
/// Configure the database by specifying parts of a URI
|
||||
///
|
||||
/// Note that specifying the `uri` field should be preferred since it provides
|
||||
/// greater control over how the connection is made. This merely exists for
|
||||
/// backwards-compatibility.
|
||||
#[default]
|
||||
Parts(DatabaseConnectionParts),
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, Serialize, Clone, SmartDefault, Document)]
|
||||
#[serde(default)]
|
||||
pub struct DatabaseConnectionParts {
|
||||
/// Username to connect to postgres
|
||||
#[default("lemmy")]
|
||||
pub(super) user: String,
|
||||
/// Password to connect to postgres
|
||||
#[default("password")]
|
||||
pub(super) password: String,
|
||||
#[default("localhost")]
|
||||
/// Host where postgres is running
|
||||
pub(super) host: String,
|
||||
/// Port where postgres can be accessed
|
||||
#[default(5432)]
|
||||
pub(super) port: i32,
|
||||
/// Name of the postgres database for lemmy
|
||||
#[default("lemmy")]
|
||||
pub(super) database: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, Serialize, Clone, Document, SmartDefault)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct EmailConfig {
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
site_name: lemmy-alpha
|
||||
}
|
||||
database: {
|
||||
host: postgres_alpha
|
||||
connection: "postgres://lemmy:password@postgres_alpha:5432/lemmy"
|
||||
}
|
||||
pictrs: {
|
||||
api_key: "my-pictrs-key"
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
site_name: lemmy-beta
|
||||
}
|
||||
database: {
|
||||
host: postgres_beta
|
||||
connection: "postgres://lemmy:password@postgres_beta:5432/lemmy"
|
||||
}
|
||||
pictrs: {
|
||||
api_key: "my-pictrs-key"
|
||||
|
|
|
@ -8,6 +8,6 @@
|
|||
site_name: lemmy-delta
|
||||
}
|
||||
database: {
|
||||
host: postgres_delta
|
||||
connection: "postgres://lemmy:password@postgres_delta:5432/lemmy"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
site_name: lemmy-epsilon
|
||||
}
|
||||
database: {
|
||||
host: postgres_epsilon
|
||||
connection: "postgres://lemmy:password@postgres_epsilon:5432/lemmy"
|
||||
}
|
||||
pictrs: {
|
||||
api_key: "my-pictrs-key"
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
site_name: lemmy-gamma
|
||||
}
|
||||
database: {
|
||||
host: postgres_gamma
|
||||
connection: "postgres://lemmy:password@postgres_gamma:5432/lemmy"
|
||||
}
|
||||
pictrs: {
|
||||
api_key: "my-pictrs-key"
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
site_name: "lemmy-dev"
|
||||
}
|
||||
database: {
|
||||
host: postgres
|
||||
connection: "postgres://lemmy:password@postgres:5432/lemmy"
|
||||
}
|
||||
|
||||
hostname: "localhost"
|
||||
|
|
|
@ -579,13 +579,13 @@ async fn build_update_instance_form(
|
|||
// This is the only kind of error that means the instance is dead
|
||||
return None;
|
||||
};
|
||||
let status = res.status();
|
||||
if status.is_client_error() || status.is_server_error() {
|
||||
return None;
|
||||
}
|
||||
|
||||
// In this block, returning `None` is ignored, and only means not writing nodeinfo to db
|
||||
async {
|
||||
if res.status().is_client_error() {
|
||||
return None;
|
||||
}
|
||||
|
||||
let node_info_url = res
|
||||
.json::<NodeInfoWellKnown>()
|
||||
.await
|
||||
|
|
Loading…
Reference in a new issue