mirror of https://github.com/LemmyNet/lemmy
* User can block instances (fixes #2397) * update comments * review comments * use route * update * add api test * update tests * fix * fix test * ci --------- Co-authored-by: Dessalines <dessalines@users.noreply.github.com>pull/3968/head^2
parent
89b7c981f5
commit
50f81cf157
@ -0,0 +1,41 @@
|
||||
use activitypub_federation::config::Data;
|
||||
use actix_web::web::Json;
|
||||
use lemmy_api_common::{
|
||||
context::LemmyContext,
|
||||
site::{BlockInstance, BlockInstanceResponse},
|
||||
utils::local_user_view_from_jwt,
|
||||
};
|
||||
use lemmy_db_schema::{
|
||||
source::instance_block::{InstanceBlock, InstanceBlockForm},
|
||||
traits::Blockable,
|
||||
};
|
||||
use lemmy_utils::error::{LemmyError, LemmyErrorExt, LemmyErrorType};
|
||||
|
||||
#[tracing::instrument(skip(context))]
|
||||
pub async fn block_instance(
|
||||
data: Json<BlockInstance>,
|
||||
context: Data<LemmyContext>,
|
||||
) -> Result<Json<BlockInstanceResponse>, LemmyError> {
|
||||
let local_user_view = local_user_view_from_jwt(&data.auth, &context).await?;
|
||||
|
||||
let instance_id = data.instance_id;
|
||||
let person_id = local_user_view.person.id;
|
||||
let instance_block_form = InstanceBlockForm {
|
||||
person_id,
|
||||
instance_id,
|
||||
};
|
||||
|
||||
if data.block {
|
||||
InstanceBlock::block(&mut context.pool(), &instance_block_form)
|
||||
.await
|
||||
.with_lemmy_type(LemmyErrorType::InstanceBlockAlreadyExists)?;
|
||||
} else {
|
||||
InstanceBlock::unblock(&mut context.pool(), &instance_block_form)
|
||||
.await
|
||||
.with_lemmy_type(LemmyErrorType::InstanceBlockAlreadyExists)?;
|
||||
}
|
||||
|
||||
Ok(Json(BlockInstanceResponse {
|
||||
blocked: data.block,
|
||||
}))
|
||||
}
|
@ -0,0 +1,36 @@
|
||||
use crate::{
|
||||
schema::instance_block::dsl::{instance_block, instance_id, person_id},
|
||||
source::instance_block::{InstanceBlock, InstanceBlockForm},
|
||||
traits::Blockable,
|
||||
utils::{get_conn, DbPool},
|
||||
};
|
||||
use diesel::{dsl::insert_into, result::Error, ExpressionMethods, QueryDsl};
|
||||
use diesel_async::RunQueryDsl;
|
||||
|
||||
#[async_trait]
|
||||
impl Blockable for InstanceBlock {
|
||||
type Form = InstanceBlockForm;
|
||||
async fn block(pool: &mut DbPool<'_>, instance_block_form: &Self::Form) -> Result<Self, Error> {
|
||||
let conn = &mut get_conn(pool).await?;
|
||||
insert_into(instance_block)
|
||||
.values(instance_block_form)
|
||||
.on_conflict((person_id, instance_id))
|
||||
.do_update()
|
||||
.set(instance_block_form)
|
||||
.get_result::<Self>(conn)
|
||||
.await
|
||||
}
|
||||
async fn unblock(
|
||||
pool: &mut DbPool<'_>,
|
||||
instance_block_form: &Self::Form,
|
||||
) -> Result<usize, Error> {
|
||||
let conn = &mut get_conn(pool).await?;
|
||||
diesel::delete(
|
||||
instance_block
|
||||
.filter(person_id.eq(instance_block_form.person_id))
|
||||
.filter(instance_id.eq(instance_block_form.instance_id)),
|
||||
)
|
||||
.execute(conn)
|
||||
.await
|
||||
}
|
||||
}
|
@ -0,0 +1,26 @@
|
||||
use crate::newtypes::{InstanceId, PersonId};
|
||||
#[cfg(feature = "full")]
|
||||
use crate::schema::instance_block;
|
||||
use chrono::{DateTime, Utc};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, Debug, Serialize, Deserialize)]
|
||||
#[cfg_attr(feature = "full", derive(Queryable, Associations, Identifiable))]
|
||||
#[cfg_attr(
|
||||
feature = "full",
|
||||
diesel(belongs_to(crate::source::instance::Instance))
|
||||
)]
|
||||
#[cfg_attr(feature = "full", diesel(table_name = instance_block))]
|
||||
pub struct InstanceBlock {
|
||||
pub id: i32,
|
||||
pub person_id: PersonId,
|
||||
pub instance_id: InstanceId,
|
||||
pub published: DateTime<Utc>,
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "full", derive(Insertable, AsChangeset))]
|
||||
#[cfg_attr(feature = "full", diesel(table_name = instance_block))]
|
||||
pub struct InstanceBlockForm {
|
||||
pub person_id: PersonId,
|
||||
pub instance_id: InstanceId,
|
||||
}
|
@ -0,0 +1,27 @@
|
||||
use crate::structs::InstanceBlockView;
|
||||
use diesel::{result::Error, ExpressionMethods, JoinOnDsl, NullableExpressionMethods, QueryDsl};
|
||||
use diesel_async::RunQueryDsl;
|
||||
use lemmy_db_schema::{
|
||||
newtypes::PersonId,
|
||||
schema::{instance, instance_block, person, site},
|
||||
utils::{get_conn, DbPool},
|
||||
};
|
||||
|
||||
impl InstanceBlockView {
|
||||
pub async fn for_person(pool: &mut DbPool<'_>, person_id: PersonId) -> Result<Vec<Self>, Error> {
|
||||
let conn = &mut get_conn(pool).await?;
|
||||
instance_block::table
|
||||
.inner_join(person::table)
|
||||
.inner_join(instance::table)
|
||||
.left_join(site::table.on(site::instance_id.eq(instance::id)))
|
||||
.select((
|
||||
person::all_columns,
|
||||
instance::all_columns,
|
||||
site::all_columns.nullable(),
|
||||
))
|
||||
.filter(instance_block::person_id.eq(person_id))
|
||||
.order_by(instance_block::published)
|
||||
.load::<InstanceBlockView>(conn)
|
||||
.await
|
||||
}
|
||||
}
|
@ -0,0 +1,21 @@
|
||||
DROP TABLE instance_block;
|
||||
|
||||
ALTER TABLE post_aggregates
|
||||
DROP COLUMN instance_id;
|
||||
|
||||
CREATE OR REPLACE FUNCTION post_aggregates_post ()
|
||||
RETURNS TRIGGER
|
||||
LANGUAGE plpgsql
|
||||
AS $$
|
||||
BEGIN
|
||||
IF (TG_OP = 'INSERT') THEN
|
||||
INSERT INTO post_aggregates (post_id, published, newest_comment_time, newest_comment_time_necro, community_id, creator_id)
|
||||
VALUES (NEW.id, NEW.published, NEW.published, NEW.published, NEW.community_id, NEW.creator_id);
|
||||
ELSIF (TG_OP = 'DELETE') THEN
|
||||
DELETE FROM post_aggregates
|
||||
WHERE post_id = OLD.id;
|
||||
END IF;
|
||||
RETURN NULL;
|
||||
END
|
||||
$$;
|
||||
|
@ -0,0 +1,51 @@
|
||||
CREATE TABLE instance_block (
|
||||
id serial PRIMARY KEY,
|
||||
person_id int REFERENCES person ON UPDATE CASCADE ON DELETE CASCADE NOT NULL,
|
||||
instance_id int REFERENCES instance ON UPDATE CASCADE ON DELETE CASCADE NOT NULL,
|
||||
published timestamptz NOT NULL DEFAULT now(),
|
||||
UNIQUE (person_id, instance_id)
|
||||
);
|
||||
|
||||
ALTER TABLE post_aggregates
|
||||
ADD COLUMN instance_id integer REFERENCES instance ON UPDATE CASCADE ON DELETE CASCADE;
|
||||
|
||||
CREATE OR REPLACE FUNCTION post_aggregates_post ()
|
||||
RETURNS TRIGGER
|
||||
LANGUAGE plpgsql
|
||||
AS $$
|
||||
BEGIN
|
||||
IF (TG_OP = 'INSERT') THEN
|
||||
INSERT INTO post_aggregates (post_id, published, newest_comment_time, newest_comment_time_necro, community_id, creator_id, instance_id)
|
||||
SELECT
|
||||
NEW.id,
|
||||
NEW.published,
|
||||
NEW.published,
|
||||
NEW.published,
|
||||
NEW.community_id,
|
||||
NEW.creator_id,
|
||||
community.instance_id
|
||||
FROM
|
||||
community
|
||||
WHERE
|
||||
NEW.community_id = community.id;
|
||||
ELSIF (TG_OP = 'DELETE') THEN
|
||||
DELETE FROM post_aggregates
|
||||
WHERE post_id = OLD.id;
|
||||
END IF;
|
||||
RETURN NULL;
|
||||
END
|
||||
$$;
|
||||
|
||||
UPDATE
|
||||
post_aggregates
|
||||
SET
|
||||
instance_id = community.instance_id
|
||||
FROM
|
||||
post
|
||||
JOIN community ON post.community_id = community.id
|
||||
WHERE
|
||||
post.id = post_aggregates.post_id;
|
||||
|
||||
ALTER TABLE post_aggregates
|
||||
ALTER COLUMN instance_id SET NOT NULL;
|
||||
|
Loading…
Reference in New Issue