upd: Note Length customization
note length is now configurable through the config file Closes #281 falls back to 3000 (misskey default) if not used/included in config
This commit is contained in:
parent
031d748d0c
commit
b1c26201ca
8 changed files with 43 additions and 12 deletions
|
@ -167,6 +167,9 @@ id: 'aidx'
|
||||||
# IP address family used for outgoing request (ipv4, ipv6 or dual)
|
# IP address family used for outgoing request (ipv4, ipv6 or dual)
|
||||||
#outgoingAddressFamily: ipv4
|
#outgoingAddressFamily: ipv4
|
||||||
|
|
||||||
|
# Amount of characters that can be used when writing notes (maximum: 8192, minimum: 1)
|
||||||
|
maxNoteLength: 3000
|
||||||
|
|
||||||
# Proxy for HTTP/HTTPS
|
# Proxy for HTTP/HTTPS
|
||||||
#proxy: http://127.0.0.1:3128
|
#proxy: http://127.0.0.1:3128
|
||||||
|
|
||||||
|
@ -197,6 +200,8 @@ proxyRemoteFiles: true
|
||||||
|
|
||||||
# Sign to ActivityPub GET request (default: true)
|
# Sign to ActivityPub GET request (default: true)
|
||||||
signToActivityPubGet: true
|
signToActivityPubGet: true
|
||||||
|
# check that inbound ActivityPub GET requests are signed ("authorized fetch")
|
||||||
|
checkActivityPubGetSignature: false
|
||||||
|
|
||||||
# For security reasons, uploading attachments from the intranet is prohibited,
|
# For security reasons, uploading attachments from the intranet is prohibited,
|
||||||
# but exceptions can be made from the following settings. Default value is "undefined".
|
# but exceptions can be made from the following settings. Default value is "undefined".
|
||||||
|
|
|
@ -179,6 +179,9 @@ id: 'aidx'
|
||||||
# IP address family used for outgoing request (ipv4, ipv6 or dual)
|
# IP address family used for outgoing request (ipv4, ipv6 or dual)
|
||||||
#outgoingAddressFamily: ipv4
|
#outgoingAddressFamily: ipv4
|
||||||
|
|
||||||
|
# Amount of characters that can be used when writing notes (maximum: 8192, minimum: 1)
|
||||||
|
maxNoteLength: 3000
|
||||||
|
|
||||||
# Proxy for HTTP/HTTPS
|
# Proxy for HTTP/HTTPS
|
||||||
#proxy: http://127.0.0.1:3128
|
#proxy: http://127.0.0.1:3128
|
||||||
|
|
||||||
|
|
|
@ -7,8 +7,8 @@ import * as fs from 'node:fs';
|
||||||
import { fileURLToPath } from 'node:url';
|
import { fileURLToPath } from 'node:url';
|
||||||
import { dirname, resolve } from 'node:path';
|
import { dirname, resolve } from 'node:path';
|
||||||
import * as yaml from 'js-yaml';
|
import * as yaml from 'js-yaml';
|
||||||
import type { RedisOptions } from 'ioredis';
|
|
||||||
import { globSync } from 'glob';
|
import { globSync } from 'glob';
|
||||||
|
import type { RedisOptions } from 'ioredis';
|
||||||
|
|
||||||
type RedisOptionsSource = Partial<RedisOptions> & {
|
type RedisOptionsSource = Partial<RedisOptions> & {
|
||||||
host: string;
|
host: string;
|
||||||
|
@ -65,6 +65,7 @@ type Source = {
|
||||||
allowedPrivateNetworks?: string[];
|
allowedPrivateNetworks?: string[];
|
||||||
|
|
||||||
maxFileSize?: number;
|
maxFileSize?: number;
|
||||||
|
maxNoteLength?: number;
|
||||||
|
|
||||||
clusterLimit?: number;
|
clusterLimit?: number;
|
||||||
|
|
||||||
|
@ -133,6 +134,7 @@ export type Config = {
|
||||||
proxyBypassHosts: string[] | undefined;
|
proxyBypassHosts: string[] | undefined;
|
||||||
allowedPrivateNetworks: string[] | undefined;
|
allowedPrivateNetworks: string[] | undefined;
|
||||||
maxFileSize: number | undefined;
|
maxFileSize: number | undefined;
|
||||||
|
maxNoteLength: number;
|
||||||
clusterLimit: number | undefined;
|
clusterLimit: number | undefined;
|
||||||
id: string;
|
id: string;
|
||||||
outgoingAddress: string | undefined;
|
outgoingAddress: string | undefined;
|
||||||
|
@ -249,6 +251,7 @@ export function loadConfig(): Config {
|
||||||
proxyBypassHosts: config.proxyBypassHosts,
|
proxyBypassHosts: config.proxyBypassHosts,
|
||||||
allowedPrivateNetworks: config.allowedPrivateNetworks,
|
allowedPrivateNetworks: config.allowedPrivateNetworks,
|
||||||
maxFileSize: config.maxFileSize,
|
maxFileSize: config.maxFileSize,
|
||||||
|
maxNoteLength: config.maxNoteLength ?? 3000,
|
||||||
clusterLimit: config.clusterLimit,
|
clusterLimit: config.clusterLimit,
|
||||||
outgoingAddress: config.outgoingAddress,
|
outgoingAddress: config.outgoingAddress,
|
||||||
outgoingAddressFamily: config.outgoingAddressFamily,
|
outgoingAddressFamily: config.outgoingAddressFamily,
|
||||||
|
|
|
@ -7,7 +7,6 @@ import { Inject, Injectable } from '@nestjs/common';
|
||||||
import { DI } from '@/di-symbols.js';
|
import { DI } from '@/di-symbols.js';
|
||||||
import type { Config } from '@/config.js';
|
import type { Config } from '@/config.js';
|
||||||
import { MetaService } from '@/core/MetaService.js';
|
import { MetaService } from '@/core/MetaService.js';
|
||||||
import { MAX_NOTE_TEXT_LENGTH } from '@/const.js';
|
|
||||||
import { MemorySingleCache } from '@/misc/cache.js';
|
import { MemorySingleCache } from '@/misc/cache.js';
|
||||||
import { UserEntityService } from '@/core/entities/UserEntityService.js';
|
import { UserEntityService } from '@/core/entities/UserEntityService.js';
|
||||||
import { bindThis } from '@/decorators.js';
|
import { bindThis } from '@/decorators.js';
|
||||||
|
@ -118,7 +117,7 @@ export class NodeinfoServerService {
|
||||||
emailRequiredForSignup: meta.emailRequiredForSignup,
|
emailRequiredForSignup: meta.emailRequiredForSignup,
|
||||||
enableHcaptcha: meta.enableHcaptcha,
|
enableHcaptcha: meta.enableHcaptcha,
|
||||||
enableRecaptcha: meta.enableRecaptcha,
|
enableRecaptcha: meta.enableRecaptcha,
|
||||||
maxNoteTextLength: MAX_NOTE_TEXT_LENGTH,
|
maxNoteTextLength: this.config.maxNoteLength,
|
||||||
enableEmail: meta.enableEmail,
|
enableEmail: meta.enableEmail,
|
||||||
enableServiceWorker: meta.enableServiceWorker,
|
enableServiceWorker: meta.enableServiceWorker,
|
||||||
proxyAccountName: proxyAccount ? proxyAccount.username : null,
|
proxyAccountName: proxyAccount ? proxyAccount.username : null,
|
||||||
|
|
|
@ -7,7 +7,6 @@ import { IsNull, LessThanOrEqual, MoreThan, Brackets } from 'typeorm';
|
||||||
import { Inject, Injectable } from '@nestjs/common';
|
import { Inject, Injectable } from '@nestjs/common';
|
||||||
import JSON5 from 'json5';
|
import JSON5 from 'json5';
|
||||||
import type { AdsRepository, UsersRepository } from '@/models/_.js';
|
import type { AdsRepository, UsersRepository } from '@/models/_.js';
|
||||||
import { MAX_NOTE_TEXT_LENGTH } from '@/const.js';
|
|
||||||
import { Endpoint } from '@/server/api/endpoint-base.js';
|
import { Endpoint } from '@/server/api/endpoint-base.js';
|
||||||
import { UserEntityService } from '@/core/entities/UserEntityService.js';
|
import { UserEntityService } from '@/core/entities/UserEntityService.js';
|
||||||
import { MetaService } from '@/core/MetaService.js';
|
import { MetaService } from '@/core/MetaService.js';
|
||||||
|
@ -375,7 +374,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||||
iconUrl: instance.iconUrl,
|
iconUrl: instance.iconUrl,
|
||||||
backgroundImageUrl: instance.backgroundImageUrl,
|
backgroundImageUrl: instance.backgroundImageUrl,
|
||||||
logoImageUrl: instance.logoImageUrl,
|
logoImageUrl: instance.logoImageUrl,
|
||||||
maxNoteTextLength: MAX_NOTE_TEXT_LENGTH,
|
maxNoteTextLength: this.config.maxNoteLength,
|
||||||
// クライアントの手間を減らすためあらかじめJSONに変換しておく
|
// クライアントの手間を減らすためあらかじめJSONに変換しておく
|
||||||
defaultLightTheme: instance.defaultLightTheme ? JSON.stringify(JSON5.parse(instance.defaultLightTheme)) : null,
|
defaultLightTheme: instance.defaultLightTheme ? JSON.stringify(JSON5.parse(instance.defaultLightTheme)) : null,
|
||||||
defaultDarkTheme: instance.defaultDarkTheme ? JSON.stringify(JSON5.parse(instance.defaultDarkTheme)) : null,
|
defaultDarkTheme: instance.defaultDarkTheme ? JSON.stringify(JSON5.parse(instance.defaultDarkTheme)) : null,
|
||||||
|
|
|
@ -11,7 +11,7 @@ import type { UsersRepository, NotesRepository, BlockingsRepository, DriveFilesR
|
||||||
import type { MiDriveFile } from '@/models/DriveFile.js';
|
import type { MiDriveFile } from '@/models/DriveFile.js';
|
||||||
import type { MiNote } from '@/models/Note.js';
|
import type { MiNote } from '@/models/Note.js';
|
||||||
import type { MiChannel } from '@/models/Channel.js';
|
import type { MiChannel } from '@/models/Channel.js';
|
||||||
import { MAX_NOTE_TEXT_LENGTH } from '@/const.js';
|
import type { Config } from '@/config.js';
|
||||||
import { Endpoint } from '@/server/api/endpoint-base.js';
|
import { Endpoint } from '@/server/api/endpoint-base.js';
|
||||||
import { NoteEntityService } from '@/core/entities/NoteEntityService.js';
|
import { NoteEntityService } from '@/core/entities/NoteEntityService.js';
|
||||||
import { NoteCreateService } from '@/core/NoteCreateService.js';
|
import { NoteCreateService } from '@/core/NoteCreateService.js';
|
||||||
|
@ -82,6 +82,12 @@ export const meta = {
|
||||||
id: '3ac74a84-8fd5-4bb0-870f-01804f82ce15',
|
id: '3ac74a84-8fd5-4bb0-870f-01804f82ce15',
|
||||||
},
|
},
|
||||||
|
|
||||||
|
maxLength: {
|
||||||
|
message: 'You tried posting a note which is too long.',
|
||||||
|
code: 'MAX_LENGTH',
|
||||||
|
id: '3ac74a84-8fd5-4bb0-870f-01804f82ce16',
|
||||||
|
},
|
||||||
|
|
||||||
cannotCreateAlreadyExpiredPoll: {
|
cannotCreateAlreadyExpiredPoll: {
|
||||||
message: 'Poll is already expired.',
|
message: 'Poll is already expired.',
|
||||||
code: 'CANNOT_CREATE_ALREADY_EXPIRED_POLL',
|
code: 'CANNOT_CREATE_ALREADY_EXPIRED_POLL',
|
||||||
|
@ -136,7 +142,6 @@ export const paramDef = {
|
||||||
text: {
|
text: {
|
||||||
type: 'string',
|
type: 'string',
|
||||||
minLength: 1,
|
minLength: 1,
|
||||||
maxLength: MAX_NOTE_TEXT_LENGTH,
|
|
||||||
nullable: true,
|
nullable: true,
|
||||||
},
|
},
|
||||||
fileIds: {
|
fileIds: {
|
||||||
|
@ -184,6 +189,9 @@ export const paramDef = {
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-disable-line import/no-default-export
|
export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-disable-line import/no-default-export
|
||||||
constructor(
|
constructor(
|
||||||
|
@Inject(DI.config)
|
||||||
|
private config: Config,
|
||||||
|
|
||||||
@Inject(DI.usersRepository)
|
@Inject(DI.usersRepository)
|
||||||
private usersRepository: UsersRepository,
|
private usersRepository: UsersRepository,
|
||||||
|
|
||||||
|
@ -203,6 +211,10 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||||
private noteCreateService: NoteCreateService,
|
private noteCreateService: NoteCreateService,
|
||||||
) {
|
) {
|
||||||
super(meta, paramDef, async (ps, me) => {
|
super(meta, paramDef, async (ps, me) => {
|
||||||
|
if (ps.text && (ps.text.length > this.config.maxNoteLength)) {
|
||||||
|
throw new ApiError(meta.errors.maxLength);
|
||||||
|
}
|
||||||
|
|
||||||
let visibleUsers: MiUser[] = [];
|
let visibleUsers: MiUser[] = [];
|
||||||
if (ps.visibleUserIds) {
|
if (ps.visibleUserIds) {
|
||||||
visibleUsers = await this.usersRepository.findBy({
|
visibleUsers = await this.usersRepository.findBy({
|
||||||
|
|
|
@ -6,7 +6,7 @@ import type { UsersRepository, NotesRepository, BlockingsRepository, DriveFilesR
|
||||||
import type { MiDriveFile } from '@/models/DriveFile.js';
|
import type { MiDriveFile } from '@/models/DriveFile.js';
|
||||||
import type { MiNote } from '@/models/Note.js';
|
import type { MiNote } from '@/models/Note.js';
|
||||||
import type { MiChannel } from '@/models/Channel.js';
|
import type { MiChannel } from '@/models/Channel.js';
|
||||||
import { MAX_NOTE_TEXT_LENGTH } from '@/const.js';
|
import type { Config } from '@/config.js';
|
||||||
import { Endpoint } from '@/server/api/endpoint-base.js';
|
import { Endpoint } from '@/server/api/endpoint-base.js';
|
||||||
import { NoteEntityService } from '@/core/entities/NoteEntityService.js';
|
import { NoteEntityService } from '@/core/entities/NoteEntityService.js';
|
||||||
import { NoteEditService } from '@/core/NoteEditService.js';
|
import { NoteEditService } from '@/core/NoteEditService.js';
|
||||||
|
@ -135,6 +135,12 @@ export const meta = {
|
||||||
code: 'CANNOT_QUOTE_THE_CURRENT_NOTE',
|
code: 'CANNOT_QUOTE_THE_CURRENT_NOTE',
|
||||||
id: '33510210-8452-094c-6227-4a6c05d99f02',
|
id: '33510210-8452-094c-6227-4a6c05d99f02',
|
||||||
},
|
},
|
||||||
|
|
||||||
|
maxLength: {
|
||||||
|
message: 'You tried posting a note which is too long.',
|
||||||
|
code: 'MAX_LENGTH',
|
||||||
|
id: '3ac74a84-8fd5-4bb0-870f-01804f82ce16',
|
||||||
|
},
|
||||||
},
|
},
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
|
@ -163,7 +169,6 @@ export const paramDef = {
|
||||||
text: {
|
text: {
|
||||||
type: 'string',
|
type: 'string',
|
||||||
minLength: 1,
|
minLength: 1,
|
||||||
maxLength: MAX_NOTE_TEXT_LENGTH,
|
|
||||||
nullable: true,
|
nullable: true,
|
||||||
},
|
},
|
||||||
fileIds: {
|
fileIds: {
|
||||||
|
@ -205,7 +210,6 @@ export const paramDef = {
|
||||||
text: {
|
text: {
|
||||||
type: 'string',
|
type: 'string',
|
||||||
minLength: 1,
|
minLength: 1,
|
||||||
maxLength: MAX_NOTE_TEXT_LENGTH,
|
|
||||||
nullable: false,
|
nullable: false,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -236,6 +240,9 @@ export const paramDef = {
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-disable-line import/no-default-export
|
export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-disable-line import/no-default-export
|
||||||
constructor(
|
constructor(
|
||||||
|
@Inject(DI.config)
|
||||||
|
private config: Config,
|
||||||
|
|
||||||
@Inject(DI.usersRepository)
|
@Inject(DI.usersRepository)
|
||||||
private usersRepository: UsersRepository,
|
private usersRepository: UsersRepository,
|
||||||
|
|
||||||
|
@ -255,6 +262,9 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||||
private noteEditService: NoteEditService,
|
private noteEditService: NoteEditService,
|
||||||
) {
|
) {
|
||||||
super(meta, paramDef, async (ps, me) => {
|
super(meta, paramDef, async (ps, me) => {
|
||||||
|
if (ps.text && (ps.text.length > this.config.maxNoteLength)) {
|
||||||
|
throw new ApiError(meta.errors.maxLength);
|
||||||
|
}
|
||||||
let visibleUsers: MiUser[] = [];
|
let visibleUsers: MiUser[] = [];
|
||||||
if (ps.visibleUserIds) {
|
if (ps.visibleUserIds) {
|
||||||
visibleUsers = await this.usersRepository.findBy({
|
visibleUsers = await this.usersRepository.findBy({
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { Entity } from 'megalodon';
|
import { Entity } from 'megalodon';
|
||||||
import { MAX_NOTE_TEXT_LENGTH, FILE_TYPE_BROWSERSAFE } from '@/const.js';
|
import { FILE_TYPE_BROWSERSAFE } from '@/const.js';
|
||||||
import type { Config } from '@/config.js';
|
import type { Config } from '@/config.js';
|
||||||
import type { MiMeta } from '@/models/Meta.js';
|
import type { MiMeta } from '@/models/Meta.js';
|
||||||
|
|
||||||
|
@ -35,7 +35,7 @@ export async function getInstance(
|
||||||
max_featured_tags: 20,
|
max_featured_tags: 20,
|
||||||
},
|
},
|
||||||
statuses: {
|
statuses: {
|
||||||
max_characters: MAX_NOTE_TEXT_LENGTH,
|
max_characters: config.maxNoteLength,
|
||||||
max_media_attachments: 16,
|
max_media_attachments: 16,
|
||||||
characters_reserved_per_url: response.uri.length,
|
characters_reserved_per_url: response.uri.length,
|
||||||
},
|
},
|
||||||
|
|
Loading…
Reference in a new issue