feat: admin ability to force drive content to always be nsfw

This commit is contained in:
老周部落 2024-03-01 19:26:28 +08:00
parent 999dadfcd7
commit 05e5e92ef3
No known key found for this signature in database
GPG key ID: C72181CD85C6B738
12 changed files with 74 additions and 4 deletions

View file

@ -174,6 +174,9 @@ cacheRemoteFiles: "Cache remote files"
cacheRemoteFilesDescription: "When this setting is disabled, remote files are loaded cacheRemoteFilesDescription: "When this setting is disabled, remote files are loaded
directly from the remote server. Disabling this will decrease storage usage, but directly from the remote server. Disabling this will decrease storage usage, but
increase traffic, as thumbnails will not be generated." increase traffic, as thumbnails will not be generated."
markLocalFilesNsfwByDefault: "Mark all new local file as sensitive by default"
markLocalFilesNsfwByDefaultDescription: "Regardless of this setting, users can remove
the NSFW flag themselves. Existing files are unaffected."
flagAsBot: "Mark this account as automated" flagAsBot: "Mark this account as automated"
flagAsBotDescription: "Enable this option if this account is controlled by a program. flagAsBotDescription: "Enable this option if this account is controlled by a program.
If enabled, it will act as a flag for other developers to prevent endless interaction If enabled, it will act as a flag for other developers to prevent endless interaction

View file

@ -152,6 +152,8 @@ cacheRemoteFilesDescription: "当禁用此设定时远程文件将直接从远
flagAsBot: "标记此账号为自动化账号" flagAsBot: "标记此账号为自动化账号"
flagAsBotDescription: "如果此账号由程序控制,请启用此项。启用后,此标志可以帮助其它开发人员防止自动化账号之间产生无限互动的行为,并让 Firefish flagAsBotDescription: "如果此账号由程序控制,请启用此项。启用后,此标志可以帮助其它开发人员防止自动化账号之间产生无限互动的行为,并让 Firefish
的内部系统将此账号识别为自动化账号。" 的内部系统将此账号识别为自动化账号。"
markLocalFilesNsfwByDefault: "将所有新增本地文件默认标注为敏感内容"
markLocalFilesNsfwByDefaultDescription: "无论此设置如何,用户都可以自行删除内容的敏感内容标志。现有文件也不受影响。"
flagAsCat: "将这个账号设定为一只猫😺" flagAsCat: "将这个账号设定为一只猫😺"
flagAsCatDescription: "您会长出猫耳朵并像猫一样说话!" flagAsCatDescription: "您会长出猫耳朵并像猫一样说话!"
flagShowTimelineReplies: "在时间线上显示帖子的回复" flagShowTimelineReplies: "在时间线上显示帖子的回复"

View file

@ -149,6 +149,8 @@ addEmoji: "加入表情符號"
settingGuide: "推薦設定" settingGuide: "推薦設定"
cacheRemoteFiles: "快取遠端檔案" cacheRemoteFiles: "快取遠端檔案"
cacheRemoteFilesDescription: "禁用此設定會停止遠端檔案的緩存,從而節省儲存空間,但資料會因直接連線從而產生額外數據花費。" cacheRemoteFilesDescription: "禁用此設定會停止遠端檔案的緩存,從而節省儲存空間,但資料會因直接連線從而產生額外數據花費。"
markLocalFilesNsfwByDefault: "將所有新增本地檔案預設標註為敏感內容"
markLocalFilesNsfwByDefaultDescription: "無論此設置如何,使用者都可以自行刪除檔案的敏感內容標誌。現有檔案也不受影響。"
flagAsBot: "標記此帳號為自動化帳號" flagAsBot: "標記此帳號為自動化帳號"
flagAsBotDescription: "如果本帳戶是由程式控制請啟用此選項。此選項將作為一個標示以幫助其他開發者防止自動化帳號之間產生無限互動的行為並會調整Firefish內部系統將此帳號識別為自動化帳號。" flagAsBotDescription: "如果本帳戶是由程式控制請啟用此選項。此選項將作為一個標示以幫助其他開發者防止自動化帳號之間產生無限互動的行為並會調整Firefish內部系統將此帳號識別為自動化帳號。"
flagAsCat: "你是喵咪嗎w😺" flagAsCat: "你是喵咪嗎w😺"

View file

@ -36,6 +36,8 @@ pub struct Model {
pub icon_url: Option<String>, pub icon_url: Option<String>,
#[sea_orm(column_name = "cacheRemoteFiles")] #[sea_orm(column_name = "cacheRemoteFiles")]
pub cache_remote_files: bool, pub cache_remote_files: bool,
#[sea_orm(column_name = "markLocalFilesNsfwByDefault")]
pub always_make_server_file_nsfw: bool,
#[sea_orm(column_name = "enableRecaptcha")] #[sea_orm(column_name = "enableRecaptcha")]
pub enable_recaptcha: bool, pub enable_recaptcha: bool,
#[sea_orm(column_name = "recaptchaSiteKey")] #[sea_orm(column_name = "recaptchaSiteKey")]

View file

@ -0,0 +1,18 @@
import { MigrationInterface, QueryRunner } from "typeorm";
export class markLocalFilesNsfwByDefault1709305200000
implements MigrationInterface
{
async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
`ALTER TABLE "meta" ADD "markLocalFilesNsfwByDefault" boolean NOT NULL DEFAULT false`,
undefined,
);
}
async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
`ALTER TABLE "meta" DROP COLUMN "markLocalFilesNsfwByDefault"`,
undefined,
);
}
}

View file

@ -207,6 +207,11 @@ export class Meta {
}) })
public cacheRemoteFiles: boolean; public cacheRemoteFiles: boolean;
@Column("boolean", {
default: false,
})
public markLocalFilesNsfwByDefault: boolean;
@Column({ @Column({
...id(), ...id(),
nullable: true, nullable: true,

View file

@ -29,6 +29,11 @@ export const meta = {
optional: false, optional: false,
nullable: false, nullable: false,
}, },
markLocalFilesNsfwByDefault: {
type: "boolean",
optional: false,
nullable: false,
},
emailRequiredForSignup: { emailRequiredForSignup: {
type: "boolean", type: "boolean",
optional: false, optional: false,
@ -506,6 +511,7 @@ export default define(meta, paramDef, async () => {
pinnedPages: instance.pinnedPages, pinnedPages: instance.pinnedPages,
pinnedClipId: instance.pinnedClipId, pinnedClipId: instance.pinnedClipId,
cacheRemoteFiles: instance.cacheRemoteFiles, cacheRemoteFiles: instance.cacheRemoteFiles,
markLocalFilesNsfwByDefault: instance.markLocalFilesNsfwByDefault,
defaultReaction: instance.defaultReaction, defaultReaction: instance.defaultReaction,
recommendedInstances: instance.recommendedInstances, recommendedInstances: instance.recommendedInstances,
pinnedUsers: instance.pinnedUsers, pinnedUsers: instance.pinnedUsers,

View file

@ -95,6 +95,7 @@ export const paramDef = {
localDriveCapacityMb: { type: "integer" }, localDriveCapacityMb: { type: "integer" },
remoteDriveCapacityMb: { type: "integer" }, remoteDriveCapacityMb: { type: "integer" },
cacheRemoteFiles: { type: "boolean" }, cacheRemoteFiles: { type: "boolean" },
markLocalFilesNsfwByDefault: { type: "boolean" },
emailRequiredForSignup: { type: "boolean" }, emailRequiredForSignup: { type: "boolean" },
enableHcaptcha: { type: "boolean" }, enableHcaptcha: { type: "boolean" },
hcaptchaSiteKey: { type: "string", nullable: true }, hcaptchaSiteKey: { type: "string", nullable: true },
@ -330,6 +331,10 @@ export default define(meta, paramDef, async (ps, me) => {
set.cacheRemoteFiles = ps.cacheRemoteFiles; set.cacheRemoteFiles = ps.cacheRemoteFiles;
} }
if (ps.markLocalFilesNsfwByDefault !== undefined) {
set.markLocalFilesNsfwByDefault = ps.markLocalFilesNsfwByDefault;
}
if (ps.emailRequiredForSignup !== undefined) { if (ps.emailRequiredForSignup !== undefined) {
set.emailRequiredForSignup = ps.emailRequiredForSignup; set.emailRequiredForSignup = ps.emailRequiredForSignup;
} }

View file

@ -131,6 +131,11 @@ export const meta = {
optional: false, optional: false,
nullable: false, nullable: false,
}, },
markLocalFilesNsfwByDefault: {
type: "boolean",
optional: false,
nullable: false,
},
emailRequiredForSignup: { emailRequiredForSignup: {
type: "boolean", type: "boolean",
optional: false, optional: false,
@ -490,6 +495,7 @@ export default define(meta, paramDef, async (ps, me) => {
pinnedClipId: pinnedClipId:
instance.privateMode && !me ? [] : instance.pinnedClipId, instance.privateMode && !me ? [] : instance.pinnedClipId,
cacheRemoteFiles: instance.cacheRemoteFiles, cacheRemoteFiles: instance.cacheRemoteFiles,
markLocalFilesNsfwByDefault: instance.markLocalFilesNsfwByDefault,
requireSetup: requireSetup:
(await Users.countBy({ (await Users.countBy({
host: IsNull(), host: IsNull(),

View file

@ -567,6 +567,7 @@ export async function addFile({
: null; : null;
const folder = await fetchFolder(); const folder = await fetchFolder();
const instance = await fetchMeta();
let file = new DriveFile(); let file = new DriveFile();
file.id = genId(); file.id = genId();
@ -581,7 +582,8 @@ export async function addFile({
file.requestIp = requestIp; file.requestIp = requestIp;
file.requestHeaders = requestHeaders; file.requestHeaders = requestHeaders;
file.isSensitive = user file.isSensitive = user
? Users.isLocalUser(user) && profile!.alwaysMarkNsfw ? Users.isLocalUser(user) &&
(instance!.markLocalFilesNsfwByDefault || profile!.alwaysMarkNsfw)
? true ? true
: sensitive != null : sensitive != null
? sensitive ? sensitive

View file

@ -305,6 +305,19 @@
}}</template> }}</template>
</FormSwitch> </FormSwitch>
<FormSwitch
v-model="markLocalFilesNsfwByDefault"
class="_formBlock"
>
<template #label>{{
i18n.ts.markLocalFilesNsfwByDefault
}}</template>
<template #caption>{{
i18n.ts
.markLocalFilesNsfwByDefaultDescription
}}</template>
</FormSwitch>
<FormSplit :min-width="280"> <FormSplit :min-width="280">
<FormInput <FormInput
v-model="localDriveCapacityMb" v-model="localDriveCapacityMb"
@ -486,6 +499,7 @@ const customMOTD = ref("");
const recommendedInstances = ref(""); const recommendedInstances = ref("");
const customSplashIcons = ref(""); const customSplashIcons = ref("");
const cacheRemoteFiles = ref(false); const cacheRemoteFiles = ref(false);
const markLocalFilesNsfwByDefault = ref(false);
const localDriveCapacityMb = ref(0); const localDriveCapacityMb = ref(0);
const remoteDriveCapacityMb = ref(0); const remoteDriveCapacityMb = ref(0);
const enableRegistration = ref(false); const enableRegistration = ref(false);
@ -561,6 +575,7 @@ async function init() {
customSplashIcons.value = meta.customSplashIcons.join("\n"); customSplashIcons.value = meta.customSplashIcons.join("\n");
recommendedInstances.value = meta.recommendedInstances.join("\n"); recommendedInstances.value = meta.recommendedInstances.join("\n");
cacheRemoteFiles.value = meta.cacheRemoteFiles; cacheRemoteFiles.value = meta.cacheRemoteFiles;
markLocalFilesNsfwByDefault.value = meta.markLocalFilesNsfwByDefault;
localDriveCapacityMb.value = meta.driveCapacityPerLocalUserMb; localDriveCapacityMb.value = meta.driveCapacityPerLocalUserMb;
remoteDriveCapacityMb.value = meta.driveCapacityPerRemoteUserMb; remoteDriveCapacityMb.value = meta.driveCapacityPerRemoteUserMb;
enableRegistration.value = !meta.disableRegistration; enableRegistration.value = !meta.disableRegistration;
@ -614,6 +629,7 @@ function save() {
customSplashIcons: customSplashIcons.value.split("\n"), customSplashIcons: customSplashIcons.value.split("\n"),
recommendedInstances: recommendedInstances.value.split("\n"), recommendedInstances: recommendedInstances.value.split("\n"),
cacheRemoteFiles: cacheRemoteFiles.value, cacheRemoteFiles: cacheRemoteFiles.value,
markLocalFilesNsfwByDefault: markLocalFilesNsfwByDefault.value,
localDriveCapacityMb: localDriveCapacityMb.value, localDriveCapacityMb: localDriveCapacityMb.value,
remoteDriveCapacityMb: remoteDriveCapacityMb.value, remoteDriveCapacityMb: remoteDriveCapacityMb.value,
disableRegistration: !enableRegistration.value, disableRegistration: !enableRegistration.value,

View file

@ -40,9 +40,11 @@
> >
</div> </div>
<FormSwitch v-model="isSensitive">{{ <FormSwitch
i18n.ts.markAsSensitive v-if="!instance.markLocalFilesNsfwByDefault"
}}</FormSwitch> v-model="isSensitive"
>{{ i18n.ts.markAsSensitive }}</FormSwitch
>
<FormButton v-if="postId" primary @click="save" <FormButton v-if="postId" primary @click="save"
><i :class="icon('ph-floppy-disk-back')"></i> ><i :class="icon('ph-floppy-disk-back')"></i>
@ -73,6 +75,7 @@ import { selectFiles } from "@/scripts/select-file";
import * as os from "@/os"; import * as os from "@/os";
import { useRouter } from "@/router"; import { useRouter } from "@/router";
import { definePageMetadata } from "@/scripts/page-metadata"; import { definePageMetadata } from "@/scripts/page-metadata";
import { instance } from "@/instance";
import { i18n } from "@/i18n"; import { i18n } from "@/i18n";
import icon from "@/scripts/icon"; import icon from "@/scripts/icon";