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…
	
	Add table
		Add a link
		
	
		Reference in a new issue