mirror of
https://github.com/LemmyNet/lemmy.git
synced 2025-03-13 15:02:44 +00:00
Add new setting to block NSFW content (#5436)
* Block NSFW content on instances with it disabled * Make disallow_nsfw_content a local_site setting * Clippy * Add comma * SQL fmt * Newline * Use func in apub + update js-client * Remove extra db queries, add purge_post_images * Add back local_site to funcs that need it * Fix tests * Add delay to api test * Address comments * Cleanup * Return results from db func * fmt * Remove unneeded result * Sync translations
This commit is contained in:
parent
be91a2f39c
commit
e7ab5256f7
21 changed files with 165 additions and 30 deletions
|
@ -29,7 +29,7 @@
|
|||
"eslint": "^9.20.0",
|
||||
"eslint-plugin-prettier": "^5.2.3",
|
||||
"jest": "^29.5.0",
|
||||
"lemmy-js-client": "0.20.0-api-no-optional-vec.1",
|
||||
"lemmy-js-client": "1.0.0-block-nsfw.1",
|
||||
"prettier": "^3.5.0",
|
||||
"ts-jest": "^29.1.0",
|
||||
"tsoa": "^6.6.0",
|
||||
|
|
|
@ -33,8 +33,8 @@ importers:
|
|||
specifier: ^29.5.0
|
||||
version: 29.7.0(@types/node@22.13.1)
|
||||
lemmy-js-client:
|
||||
specifier: 0.20.0-api-no-optional-vec.1
|
||||
version: 0.20.0-api-no-optional-vec.1
|
||||
specifier: 1.0.0-block-nsfw.1
|
||||
version: 1.0.0-block-nsfw.1
|
||||
prettier:
|
||||
specifier: ^3.5.0
|
||||
version: 3.5.0
|
||||
|
@ -1528,8 +1528,8 @@ packages:
|
|||
resolution: {integrity: sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==}
|
||||
engines: {node: '>=6'}
|
||||
|
||||
lemmy-js-client@0.20.0-api-no-optional-vec.1:
|
||||
resolution: {integrity: sha512-oIlTCiriuZVzTMScix4ubJyIOf3x0FPpnxCfm12EYbiix3Z9D44XMWs3JTV+ipJgmiAqgAiGhI0fF35RNu3FjQ==}
|
||||
lemmy-js-client@1.0.0-block-nsfw.1:
|
||||
resolution: {integrity: sha512-7dIGSflkfl6JZ57tNNwoI4xwHc3uMkj9mp3lMMUh+DkSnvUNEc1BCk4sBGLYJTXGr4XreeJT99bM67RO8fGkmA==}
|
||||
|
||||
leven@3.1.0:
|
||||
resolution: {integrity: sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==}
|
||||
|
@ -4169,7 +4169,7 @@ snapshots:
|
|||
|
||||
kleur@3.0.3: {}
|
||||
|
||||
lemmy-js-client@0.20.0-api-no-optional-vec.1: {}
|
||||
lemmy-js-client@1.0.0-block-nsfw.1: {}
|
||||
|
||||
leven@3.1.0: {}
|
||||
|
||||
|
|
|
@ -46,6 +46,7 @@ import { AdminBlockInstanceParams } from "lemmy-js-client/dist/types/AdminBlockI
|
|||
import {
|
||||
AddModToCommunity,
|
||||
EditSite,
|
||||
EditPost,
|
||||
PersonPostMentionView,
|
||||
PostReport,
|
||||
PostReportView,
|
||||
|
@ -927,6 +928,50 @@ test("Rewrite markdown links", async () => {
|
|||
);
|
||||
});
|
||||
|
||||
test("Don't allow NSFW posts on instances that disable it", async () => {
|
||||
// Disallow NSFW on gamma
|
||||
let editSiteForm: EditSite = {
|
||||
disallow_nsfw_content: true,
|
||||
};
|
||||
await gamma.editSite(editSiteForm);
|
||||
|
||||
// Wait for cache on Gamma's LocalSite
|
||||
await delay(1_000);
|
||||
|
||||
if (!betaCommunity) {
|
||||
throw "Missing beta community";
|
||||
}
|
||||
|
||||
// Make a NSFW post
|
||||
let postRes = await createPost(beta, betaCommunity.community.id);
|
||||
let form: EditPost = {
|
||||
nsfw: true,
|
||||
post_id: postRes.post_view.post.id,
|
||||
};
|
||||
let updatePost = await beta.editPost(form);
|
||||
|
||||
// Gamma reject resolving the post
|
||||
await expect(
|
||||
resolvePost(gamma, updatePost.post_view.post),
|
||||
).rejects.toStrictEqual(Error("not_found"));
|
||||
|
||||
// Local users can't create NSFW post on Gamma
|
||||
let gammaCommunity = (
|
||||
await resolveCommunity(gamma, betaCommunity.community.ap_id)
|
||||
).community?.community;
|
||||
if (!gammaCommunity) {
|
||||
throw "Missing gamma community";
|
||||
}
|
||||
let gammaPost = await createPost(gamma, gammaCommunity.id);
|
||||
let form2: EditPost = {
|
||||
nsfw: true,
|
||||
post_id: gammaPost.post_view.post.id,
|
||||
};
|
||||
await expect(gamma.editPost(form2)).rejects.toStrictEqual(
|
||||
Error("nsfw_not_allowed"),
|
||||
);
|
||||
});
|
||||
|
||||
function checkPostReportName(rcv: ReportCombinedView, report: PostReport) {
|
||||
switch (rcv.type_) {
|
||||
case "Post":
|
||||
|
|
|
@ -2,10 +2,9 @@ use activitypub_federation::config::Data;
|
|||
use actix_web::web::Json;
|
||||
use lemmy_api_common::{
|
||||
context::LemmyContext,
|
||||
request::purge_image_from_pictrs,
|
||||
send_activity::{ActivityChannel, SendActivityData},
|
||||
site::PurgePost,
|
||||
utils::is_admin,
|
||||
utils::{is_admin, purge_post_images},
|
||||
SuccessResponse,
|
||||
};
|
||||
use lemmy_db_schema::{
|
||||
|
@ -38,14 +37,7 @@ pub async fn purge_post(
|
|||
)
|
||||
.await?;
|
||||
|
||||
// Purge image
|
||||
if let Some(url) = &post.url {
|
||||
purge_image_from_pictrs(url, &context).await.ok();
|
||||
}
|
||||
// Purge thumbnail
|
||||
if let Some(thumbnail_url) = &post.thumbnail_url {
|
||||
purge_image_from_pictrs(thumbnail_url, &context).await.ok();
|
||||
}
|
||||
purge_post_images(post.url.clone(), post.thumbnail_url.clone(), &context).await;
|
||||
|
||||
Post::delete(&mut context.pool(), data.post_id).await?;
|
||||
|
||||
|
|
|
@ -254,6 +254,8 @@ pub struct CreateSite {
|
|||
pub comment_downvotes: Option<FederationMode>,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub disable_donation_dialog: Option<bool>,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub disallow_nsfw_content: Option<bool>,
|
||||
}
|
||||
|
||||
#[skip_serializing_none]
|
||||
|
@ -388,6 +390,9 @@ pub struct EditSite {
|
|||
/// donations.
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub disable_donation_dialog: Option<bool>,
|
||||
/// Block NSFW content being created
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub disallow_nsfw_content: Option<bool>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||
|
|
|
@ -659,6 +659,17 @@ pub fn check_private_instance_and_federation_enabled(local_site: &LocalSite) ->
|
|||
}
|
||||
}
|
||||
|
||||
pub fn check_nsfw_allowed(nsfw: Option<bool>, local_site: Option<&LocalSite>) -> LemmyResult<()> {
|
||||
let is_nsfw = nsfw.unwrap_or_default();
|
||||
let nsfw_disallowed = local_site.is_some_and(|s| s.disallow_nsfw_content);
|
||||
|
||||
if nsfw_disallowed && is_nsfw {
|
||||
Err(LemmyErrorType::NsfwNotAllowed)?
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Read the site for an ap_id.
|
||||
///
|
||||
/// Used for GetCommunityResponse and GetPersonDetails
|
||||
|
@ -671,6 +682,19 @@ pub async fn read_site_for_actor(
|
|||
Ok(site)
|
||||
}
|
||||
|
||||
pub async fn purge_post_images(
|
||||
url: Option<DbUrl>,
|
||||
thumbnail_url: Option<DbUrl>,
|
||||
context: &LemmyContext,
|
||||
) {
|
||||
if let Some(url) = url {
|
||||
purge_image_from_pictrs(&url, context).await.ok();
|
||||
}
|
||||
if let Some(thumbnail_url) = thumbnail_url {
|
||||
purge_image_from_pictrs(&thumbnail_url, context).await.ok();
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn purge_image_posts_for_person(
|
||||
banned_person_id: PersonId,
|
||||
context: &LemmyContext,
|
||||
|
@ -678,12 +702,7 @@ pub async fn purge_image_posts_for_person(
|
|||
let pool = &mut context.pool();
|
||||
let posts = Post::fetch_pictrs_posts_for_creator(pool, banned_person_id).await?;
|
||||
for post in posts {
|
||||
if let Some(url) = post.url {
|
||||
purge_image_from_pictrs(&url, context).await.ok();
|
||||
}
|
||||
if let Some(thumbnail_url) = post.thumbnail_url {
|
||||
purge_image_from_pictrs(&thumbnail_url, context).await.ok();
|
||||
}
|
||||
purge_post_images(post.url, post.thumbnail_url, context).await;
|
||||
}
|
||||
|
||||
Post::remove_pictrs_post_images_and_thumbnails_for_creator(pool, banned_person_id).await?;
|
||||
|
@ -715,12 +734,7 @@ pub async fn purge_image_posts_for_community(
|
|||
let pool = &mut context.pool();
|
||||
let posts = Post::fetch_pictrs_posts_for_community(pool, banned_community_id).await?;
|
||||
for post in posts {
|
||||
if let Some(url) = post.url {
|
||||
purge_image_from_pictrs(&url, context).await.ok();
|
||||
}
|
||||
if let Some(thumbnail_url) = post.thumbnail_url {
|
||||
purge_image_from_pictrs(&thumbnail_url, context).await.ok();
|
||||
}
|
||||
purge_post_images(post.url, post.thumbnail_url, context).await;
|
||||
}
|
||||
|
||||
Post::remove_pictrs_post_images_and_thumbnails_for_community(pool, banned_community_id).await?;
|
||||
|
|
|
@ -6,6 +6,7 @@ use lemmy_api_common::{
|
|||
community::{CommunityResponse, CreateCommunity},
|
||||
context::LemmyContext,
|
||||
utils::{
|
||||
check_nsfw_allowed,
|
||||
generate_followers_url,
|
||||
generate_inbox_url,
|
||||
get_url_blocklist,
|
||||
|
@ -54,6 +55,7 @@ pub async fn create_community(
|
|||
Err(LemmyErrorType::OnlyAdminsCanCreateCommunities)?
|
||||
}
|
||||
|
||||
check_nsfw_allowed(data.nsfw, Some(&local_site))?;
|
||||
let slur_regex = slur_regex(&context).await?;
|
||||
let url_blocklist = get_url_blocklist(&context).await?;
|
||||
check_slurs(&data.name, &slur_regex)?;
|
||||
|
|
|
@ -7,12 +7,19 @@ use lemmy_api_common::{
|
|||
community::{CommunityResponse, EditCommunity},
|
||||
context::LemmyContext,
|
||||
send_activity::{ActivityChannel, SendActivityData},
|
||||
utils::{check_community_mod_action, get_url_blocklist, process_markdown_opt, slur_regex},
|
||||
utils::{
|
||||
check_community_mod_action,
|
||||
check_nsfw_allowed,
|
||||
get_url_blocklist,
|
||||
process_markdown_opt,
|
||||
slur_regex,
|
||||
},
|
||||
};
|
||||
use lemmy_db_schema::{
|
||||
source::{
|
||||
actor_language::{CommunityLanguage, SiteLanguage},
|
||||
community::{Community, CommunityUpdateForm},
|
||||
local_site::LocalSite,
|
||||
},
|
||||
traits::Crud,
|
||||
utils::diesel_string_update,
|
||||
|
@ -28,9 +35,12 @@ pub async fn update_community(
|
|||
context: Data<LemmyContext>,
|
||||
local_user_view: LocalUserView,
|
||||
) -> LemmyResult<Json<CommunityResponse>> {
|
||||
let local_site = LocalSite::read(&mut context.pool()).await?;
|
||||
|
||||
let slur_regex = slur_regex(&context).await?;
|
||||
let url_blocklist = get_url_blocklist(&context).await?;
|
||||
check_slurs_opt(&data.title, &slur_regex)?;
|
||||
check_nsfw_allowed(data.nsfw, Some(&local_site))?;
|
||||
|
||||
let sidebar = diesel_string_update(
|
||||
process_markdown_opt(&data.sidebar, &slur_regex, &url_blocklist, &context)
|
||||
|
|
|
@ -9,6 +9,7 @@ use lemmy_api_common::{
|
|||
send_activity::SendActivityData,
|
||||
utils::{
|
||||
check_community_user_action,
|
||||
check_nsfw_allowed,
|
||||
get_url_blocklist,
|
||||
honeypot_check,
|
||||
process_markdown_opt,
|
||||
|
@ -21,6 +22,7 @@ use lemmy_db_schema::{
|
|||
newtypes::PostOrCommentId,
|
||||
source::{
|
||||
community::Community,
|
||||
local_site::LocalSite,
|
||||
post::{Post, PostInsertForm, PostLike, PostLikeForm, PostRead, PostReadForm},
|
||||
},
|
||||
traits::{Crud, Likeable},
|
||||
|
@ -48,6 +50,7 @@ pub async fn create_post(
|
|||
local_user_view: LocalUserView,
|
||||
) -> LemmyResult<Json<PostResponse>> {
|
||||
honeypot_check(&data.honeypot)?;
|
||||
let local_site = LocalSite::read(&mut context.pool()).await?;
|
||||
|
||||
let slur_regex = slur_regex(&context).await?;
|
||||
check_slurs(&data.name, &slur_regex)?;
|
||||
|
@ -56,6 +59,7 @@ pub async fn create_post(
|
|||
let body = process_markdown_opt(&data.body, &slur_regex, &url_blocklist, &context).await?;
|
||||
let url = diesel_url_create(data.url.as_deref())?;
|
||||
let custom_thumbnail = diesel_url_create(data.custom_thumbnail.as_deref())?;
|
||||
check_nsfw_allowed(data.nsfw, Some(&local_site))?;
|
||||
|
||||
is_valid_post_title(&data.name)?;
|
||||
|
||||
|
|
|
@ -10,6 +10,7 @@ use lemmy_api_common::{
|
|||
send_activity::SendActivityData,
|
||||
utils::{
|
||||
check_community_user_action,
|
||||
check_nsfw_allowed,
|
||||
get_url_blocklist,
|
||||
process_markdown_opt,
|
||||
send_webmention,
|
||||
|
@ -21,6 +22,7 @@ use lemmy_db_schema::{
|
|||
newtypes::PostOrCommentId,
|
||||
source::{
|
||||
community::Community,
|
||||
local_site::LocalSite,
|
||||
post::{Post, PostUpdateForm},
|
||||
},
|
||||
traits::Crud,
|
||||
|
@ -48,6 +50,7 @@ pub async fn update_post(
|
|||
context: Data<LemmyContext>,
|
||||
local_user_view: LocalUserView,
|
||||
) -> LemmyResult<Json<PostResponse>> {
|
||||
let local_site = LocalSite::read(&mut context.pool()).await?;
|
||||
let url = diesel_url_update(data.url.as_deref())?;
|
||||
|
||||
let custom_thumbnail = diesel_url_update(data.custom_thumbnail.as_deref())?;
|
||||
|
@ -62,6 +65,8 @@ pub async fn update_post(
|
|||
.as_deref(),
|
||||
);
|
||||
|
||||
check_nsfw_allowed(data.nsfw, Some(&local_site))?;
|
||||
|
||||
let alt_text = diesel_string_update(data.alt_text.as_deref());
|
||||
|
||||
if let Some(name) = &data.name {
|
||||
|
|
|
@ -105,6 +105,7 @@ pub async fn create_site(
|
|||
comment_upvotes: data.comment_upvotes,
|
||||
comment_downvotes: data.comment_downvotes,
|
||||
disable_donation_dialog: data.disable_donation_dialog,
|
||||
disallow_nsfw_content: data.disallow_nsfw_content,
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
|
|
|
@ -114,6 +114,7 @@ pub async fn update_site(
|
|||
comment_upvotes: data.comment_upvotes,
|
||||
comment_downvotes: data.comment_downvotes,
|
||||
disable_donation_dialog: data.disable_donation_dialog,
|
||||
disallow_nsfw_content: data.disallow_nsfw_content,
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
|
|
|
@ -18,6 +18,7 @@ use chrono::{DateTime, Utc};
|
|||
use lemmy_api_common::{
|
||||
context::LemmyContext,
|
||||
utils::{
|
||||
check_nsfw_allowed,
|
||||
generate_featured_url,
|
||||
generate_moderators_url,
|
||||
generate_outbox_url,
|
||||
|
@ -33,6 +34,7 @@ use lemmy_db_schema::{
|
|||
activity::ActorType,
|
||||
actor_language::CommunityLanguage,
|
||||
community::{Community, CommunityInsertForm, CommunityUpdateForm},
|
||||
local_site::LocalSite,
|
||||
},
|
||||
traits::{ApubActor, Crud},
|
||||
CommunityVisibility,
|
||||
|
@ -134,6 +136,7 @@ impl Object for ApubCommunity {
|
|||
|
||||
/// Converts a `Group` to `Community`, inserts it into the database and updates moderators.
|
||||
async fn from_json(group: Group, context: &Data<Self::DataType>) -> LemmyResult<ApubCommunity> {
|
||||
let local_site = LocalSite::read(&mut context.pool()).await.ok();
|
||||
let instance_id = fetch_instance_actor_for_object(&group.id, context).await?;
|
||||
|
||||
let slur_regex = slur_regex(context).await?;
|
||||
|
@ -148,6 +151,12 @@ impl Object for ApubCommunity {
|
|||
} else {
|
||||
CommunityVisibility::Public
|
||||
});
|
||||
|
||||
// If NSFW is not allowed, then remove NSFW communities
|
||||
let removed = check_nsfw_allowed(group.sensitive, local_site.as_ref())
|
||||
.err()
|
||||
.map(|_| true);
|
||||
|
||||
let form = CommunityInsertForm {
|
||||
published: group.published,
|
||||
updated: group.updated,
|
||||
|
@ -159,6 +168,7 @@ impl Object for ApubCommunity {
|
|||
icon,
|
||||
banner,
|
||||
sidebar,
|
||||
removed,
|
||||
description: group.summary,
|
||||
followers_url: group.followers.clone().map(Into::into),
|
||||
inbox_url: Some(
|
||||
|
|
|
@ -27,11 +27,18 @@ use html2text::{from_read_with_decorator, render::TrivialDecorator};
|
|||
use lemmy_api_common::{
|
||||
context::LemmyContext,
|
||||
request::generate_post_link_metadata,
|
||||
utils::{get_url_blocklist, process_markdown_opt, slur_regex},
|
||||
utils::{
|
||||
check_nsfw_allowed,
|
||||
get_url_blocklist,
|
||||
process_markdown_opt,
|
||||
purge_post_images,
|
||||
slur_regex,
|
||||
},
|
||||
};
|
||||
use lemmy_db_schema::{
|
||||
source::{
|
||||
community::Community,
|
||||
local_site::LocalSite,
|
||||
person::Person,
|
||||
post::{Post, PostInsertForm, PostUpdateForm},
|
||||
},
|
||||
|
@ -171,6 +178,7 @@ impl Object for ApubPost {
|
|||
}
|
||||
|
||||
async fn from_json(page: Page, context: &Data<Self::DataType>) -> LemmyResult<ApubPost> {
|
||||
let local_site = LocalSite::read(&mut context.pool()).await.ok();
|
||||
let creator = page.creator()?.dereference(context).await?;
|
||||
let community = page.community(context).await?;
|
||||
|
||||
|
@ -220,6 +228,17 @@ impl Object for ApubPost {
|
|||
None
|
||||
};
|
||||
|
||||
// If NSFW is not allowed, reject NSFW posts and delete existing
|
||||
// posts that get updated to be NSFW
|
||||
let block_for_nsfw = check_nsfw_allowed(page.sensitive, local_site.as_ref());
|
||||
if let Err(e) = block_for_nsfw {
|
||||
let url = url.clone().map(std::convert::Into::into);
|
||||
let thumbnail_url = page.image.map(|i| i.url.into());
|
||||
purge_post_images(url, thumbnail_url, context).await;
|
||||
Post::delete_from_apub_id(&mut context.pool(), page.id.inner().clone()).await?;
|
||||
Err(e)?
|
||||
}
|
||||
|
||||
let url_blocklist = get_url_blocklist(context).await?;
|
||||
|
||||
let url = if let Some(url) = url {
|
||||
|
|
|
@ -55,6 +55,7 @@ diesel = { workspace = true, features = [
|
|||
"postgres",
|
||||
"serde_json",
|
||||
"uuid",
|
||||
"64-column-tables",
|
||||
], optional = true }
|
||||
diesel-derive-newtype = { workspace = true, optional = true }
|
||||
diesel-derive-enum = { workspace = true, optional = true }
|
||||
|
|
|
@ -182,6 +182,19 @@ impl Post {
|
|||
.optional()
|
||||
}
|
||||
|
||||
pub async fn delete_from_apub_id(
|
||||
pool: &mut DbPool<'_>,
|
||||
object_id: Url,
|
||||
) -> Result<Vec<Self>, Error> {
|
||||
let conn = &mut get_conn(pool).await?;
|
||||
let object_id: DbUrl = object_id.into();
|
||||
|
||||
diesel::update(post::table.filter(post::ap_id.eq(object_id)))
|
||||
.set(post::deleted.eq(true))
|
||||
.get_results::<Self>(conn)
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn fetch_pictrs_posts_for_creator(
|
||||
pool: &mut DbPool<'_>,
|
||||
for_creator_id: PersonId,
|
||||
|
|
|
@ -449,6 +449,7 @@ diesel::table! {
|
|||
comment_downvotes -> FederationModeEnum,
|
||||
disable_donation_dialog -> Bool,
|
||||
default_post_time_range_seconds -> Nullable<Int4>,
|
||||
disallow_nsfw_content -> Bool,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -89,6 +89,8 @@ pub struct LocalSite {
|
|||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
/// A default time range limit to apply to post sorts, in seconds.
|
||||
pub default_post_time_range_seconds: Option<i32>,
|
||||
/// Block NSFW content being created
|
||||
pub disallow_nsfw_content: bool,
|
||||
}
|
||||
|
||||
#[derive(Clone, derive_new::new)]
|
||||
|
@ -152,6 +154,8 @@ pub struct LocalSiteInsertForm {
|
|||
pub disable_donation_dialog: Option<bool>,
|
||||
#[new(default)]
|
||||
pub default_post_time_range_seconds: Option<Option<i32>>,
|
||||
#[new(default)]
|
||||
pub disallow_nsfw_content: bool,
|
||||
}
|
||||
|
||||
#[derive(Clone, Default)]
|
||||
|
@ -187,4 +191,5 @@ pub struct LocalSiteUpdateForm {
|
|||
pub comment_downvotes: Option<FederationMode>,
|
||||
pub disable_donation_dialog: Option<bool>,
|
||||
pub default_post_time_range_seconds: Option<Option<i32>>,
|
||||
pub disallow_nsfw_content: Option<bool>,
|
||||
}
|
||||
|
|
|
@ -58,6 +58,7 @@ pub enum LemmyErrorType {
|
|||
LanguageNotAllowed,
|
||||
CouldntUpdatePost,
|
||||
NoPostEditAllowed,
|
||||
NsfwNotAllowed,
|
||||
EditPrivateMessageNotAllowed,
|
||||
SiteAlreadyExists,
|
||||
ApplicationQuestionRequired,
|
||||
|
|
3
migrations/2025-02-18-143408_block_nsfw/down.sql
Normal file
3
migrations/2025-02-18-143408_block_nsfw/down.sql
Normal file
|
@ -0,0 +1,3 @@
|
|||
ALTER TABLE local_site
|
||||
DROP COLUMN disallow_nsfw_content;
|
||||
|
3
migrations/2025-02-18-143408_block_nsfw/up.sql
Normal file
3
migrations/2025-02-18-143408_block_nsfw/up.sql
Normal file
|
@ -0,0 +1,3 @@
|
|||
ALTER TABLE local_site
|
||||
ADD COLUMN disallow_nsfw_content boolean DEFAULT FALSE NOT NULL;
|
||||
|
Loading…
Reference in a new issue