diff --git a/locales/en-US.yml b/locales/en-US.yml index edadfca386..4bf1cc08a0 100644 --- a/locales/en-US.yml +++ b/locales/en-US.yml @@ -174,6 +174,9 @@ cacheRemoteFiles: "Cache remote files" cacheRemoteFilesDescription: "When this setting is disabled, remote files are loaded directly from the remote server. Disabling this will decrease storage usage, but 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" 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 diff --git a/locales/zh-CN.yml b/locales/zh-CN.yml index 16a32783af..1deac365fe 100644 --- a/locales/zh-CN.yml +++ b/locales/zh-CN.yml @@ -152,6 +152,8 @@ cacheRemoteFilesDescription: "当禁用此设定时远程文件将直接从远 flagAsBot: "标记此账号为自动化账号" flagAsBotDescription: "如果此账号由程序控制,请启用此项。启用后,此标志可以帮助其它开发人员防止自动化账号之间产生无限互动的行为,并让 Firefish 的内部系统将此账号识别为自动化账号。" +markLocalFilesNsfwByDefault: "将所有新增本地文件默认标注为敏感内容" +markLocalFilesNsfwByDefaultDescription: "无论此设置如何,用户都可以自行删除内容的敏感内容标志。现有文件也不受影响。" flagAsCat: "将这个账号设定为一只猫😺" flagAsCatDescription: "您会长出猫耳朵并像猫一样说话!" flagShowTimelineReplies: "在时间线上显示帖子的回复" diff --git a/locales/zh-TW.yml b/locales/zh-TW.yml index b2c07af664..0e0a674bd2 100644 --- a/locales/zh-TW.yml +++ b/locales/zh-TW.yml @@ -149,6 +149,8 @@ addEmoji: "加入表情符號" settingGuide: "推薦設定" cacheRemoteFiles: "快取遠端檔案" cacheRemoteFilesDescription: "禁用此設定會停止遠端檔案的緩存,從而節省儲存空間,但資料會因直接連線從而產生額外數據花費。" +markLocalFilesNsfwByDefault: "將所有新增本地檔案預設標註為敏感內容" +markLocalFilesNsfwByDefaultDescription: "無論此設置如何,使用者都可以自行刪除檔案的敏感內容標誌。現有檔案也不受影響。" flagAsBot: "標記此帳號為自動化帳號" flagAsBotDescription: "如果本帳戶是由程式控制,請啟用此選項。此選項將作為一個標示以幫助其他開發者防止自動化帳號之間產生無限互動的行為,並會調整Firefish內部系統將此帳號識別為自動化帳號。" flagAsCat: "你是喵咪嗎?w😺" diff --git a/packages/backend-rs/src/model/entity/meta.rs b/packages/backend-rs/src/model/entity/meta.rs index f9f8409364..9f1d16fd1f 100644 --- a/packages/backend-rs/src/model/entity/meta.rs +++ b/packages/backend-rs/src/model/entity/meta.rs @@ -36,6 +36,8 @@ pub struct Model { pub icon_url: Option, #[sea_orm(column_name = "cacheRemoteFiles")] pub cache_remote_files: bool, + #[sea_orm(column_name = "markLocalFilesNsfwByDefault")] + pub always_make_server_file_nsfw: bool, #[sea_orm(column_name = "enableRecaptcha")] pub enable_recaptcha: bool, #[sea_orm(column_name = "recaptchaSiteKey")] diff --git a/packages/backend/src/migration/1709305200000-markLocalFilesNsfwByDefault.ts b/packages/backend/src/migration/1709305200000-markLocalFilesNsfwByDefault.ts new file mode 100644 index 0000000000..c36c15fa41 --- /dev/null +++ b/packages/backend/src/migration/1709305200000-markLocalFilesNsfwByDefault.ts @@ -0,0 +1,18 @@ +import { MigrationInterface, QueryRunner } from "typeorm"; + +export class markLocalFilesNsfwByDefault1709305200000 + implements MigrationInterface +{ + async up(queryRunner: QueryRunner): Promise { + await queryRunner.query( + `ALTER TABLE "meta" ADD "markLocalFilesNsfwByDefault" boolean NOT NULL DEFAULT false`, + undefined, + ); + } + async down(queryRunner: QueryRunner): Promise { + await queryRunner.query( + `ALTER TABLE "meta" DROP COLUMN "markLocalFilesNsfwByDefault"`, + undefined, + ); + } +} diff --git a/packages/backend/src/models/entities/meta.ts b/packages/backend/src/models/entities/meta.ts index 6030a969cc..286aa7f68f 100644 --- a/packages/backend/src/models/entities/meta.ts +++ b/packages/backend/src/models/entities/meta.ts @@ -207,6 +207,11 @@ export class Meta { }) public cacheRemoteFiles: boolean; + @Column("boolean", { + default: false, + }) + public markLocalFilesNsfwByDefault: boolean; + @Column({ ...id(), nullable: true, diff --git a/packages/backend/src/server/api/endpoints/admin/meta.ts b/packages/backend/src/server/api/endpoints/admin/meta.ts index a504055065..a22fbab8f1 100644 --- a/packages/backend/src/server/api/endpoints/admin/meta.ts +++ b/packages/backend/src/server/api/endpoints/admin/meta.ts @@ -29,6 +29,11 @@ export const meta = { optional: false, nullable: false, }, + markLocalFilesNsfwByDefault: { + type: "boolean", + optional: false, + nullable: false, + }, emailRequiredForSignup: { type: "boolean", optional: false, @@ -506,6 +511,7 @@ export default define(meta, paramDef, async () => { pinnedPages: instance.pinnedPages, pinnedClipId: instance.pinnedClipId, cacheRemoteFiles: instance.cacheRemoteFiles, + markLocalFilesNsfwByDefault: instance.markLocalFilesNsfwByDefault, defaultReaction: instance.defaultReaction, recommendedInstances: instance.recommendedInstances, pinnedUsers: instance.pinnedUsers, diff --git a/packages/backend/src/server/api/endpoints/admin/update-meta.ts b/packages/backend/src/server/api/endpoints/admin/update-meta.ts index f0e831924a..604ef3a0fc 100644 --- a/packages/backend/src/server/api/endpoints/admin/update-meta.ts +++ b/packages/backend/src/server/api/endpoints/admin/update-meta.ts @@ -95,6 +95,7 @@ export const paramDef = { localDriveCapacityMb: { type: "integer" }, remoteDriveCapacityMb: { type: "integer" }, cacheRemoteFiles: { type: "boolean" }, + markLocalFilesNsfwByDefault: { type: "boolean" }, emailRequiredForSignup: { type: "boolean" }, enableHcaptcha: { type: "boolean" }, hcaptchaSiteKey: { type: "string", nullable: true }, @@ -330,6 +331,10 @@ export default define(meta, paramDef, async (ps, me) => { set.cacheRemoteFiles = ps.cacheRemoteFiles; } + if (ps.markLocalFilesNsfwByDefault !== undefined) { + set.markLocalFilesNsfwByDefault = ps.markLocalFilesNsfwByDefault; + } + if (ps.emailRequiredForSignup !== undefined) { set.emailRequiredForSignup = ps.emailRequiredForSignup; } diff --git a/packages/backend/src/server/api/endpoints/meta.ts b/packages/backend/src/server/api/endpoints/meta.ts index 68a7008405..72f6c2eeab 100644 --- a/packages/backend/src/server/api/endpoints/meta.ts +++ b/packages/backend/src/server/api/endpoints/meta.ts @@ -131,6 +131,11 @@ export const meta = { optional: false, nullable: false, }, + markLocalFilesNsfwByDefault: { + type: "boolean", + optional: false, + nullable: false, + }, emailRequiredForSignup: { type: "boolean", optional: false, @@ -490,6 +495,7 @@ export default define(meta, paramDef, async (ps, me) => { pinnedClipId: instance.privateMode && !me ? [] : instance.pinnedClipId, cacheRemoteFiles: instance.cacheRemoteFiles, + markLocalFilesNsfwByDefault: instance.markLocalFilesNsfwByDefault, requireSetup: (await Users.countBy({ host: IsNull(), diff --git a/packages/backend/src/services/drive/add-file.ts b/packages/backend/src/services/drive/add-file.ts index 194e4e90f0..b7017f74b1 100644 --- a/packages/backend/src/services/drive/add-file.ts +++ b/packages/backend/src/services/drive/add-file.ts @@ -567,6 +567,7 @@ export async function addFile({ : null; const folder = await fetchFolder(); + const instance = await fetchMeta(); let file = new DriveFile(); file.id = genId(); @@ -581,7 +582,8 @@ export async function addFile({ file.requestIp = requestIp; file.requestHeaders = requestHeaders; file.isSensitive = user - ? Users.isLocalUser(user) && profile!.alwaysMarkNsfw + ? Users.isLocalUser(user) && + (instance!.markLocalFilesNsfwByDefault || profile!.alwaysMarkNsfw) ? true : sensitive != null ? sensitive diff --git a/packages/client/src/pages/admin/settings.vue b/packages/client/src/pages/admin/settings.vue index 32a2dd9688..01ded1f321 100644 --- a/packages/client/src/pages/admin/settings.vue +++ b/packages/client/src/pages/admin/settings.vue @@ -305,6 +305,19 @@ }} + + + + + - {{ - i18n.ts.markAsSensitive - }} + {{ i18n.ts.markAsSensitive }} @@ -73,6 +75,7 @@ import { selectFiles } from "@/scripts/select-file"; import * as os from "@/os"; import { useRouter } from "@/router"; import { definePageMetadata } from "@/scripts/page-metadata"; +import { instance } from "@/instance"; import { i18n } from "@/i18n"; import icon from "@/scripts/icon";