2023.10.0-beta.15-prismisskey.3
This commit is contained in:
		
							parent
							
								
									1dcc649152
								
							
						
					
					
						commit
						8358ace249
					
				|  | @ -17,7 +17,6 @@ import { isUserRelated } from '@/misc/is-user-related.js'; | |||
| import { CacheService } from '@/core/CacheService.js'; | ||||
| import { RedisTimelineService } from '@/core/RedisTimelineService.js'; | ||||
| import { ApiError } from '../../error.js'; | ||||
| import {QueryService} from "@/core/QueryService.js"; | ||||
| 
 | ||||
| export const meta = { | ||||
| 	tags: ['notes'], | ||||
|  | @ -69,11 +68,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint- | |||
| 		@Inject(DI.notesRepository) | ||||
| 		private notesRepository: NotesRepository, | ||||
| 
 | ||||
| 		@Inject(DI.followingsRepository) | ||||
| 		private followingsRepository: FollowingsRepository, | ||||
| 
 | ||||
| 		private noteEntityService: NoteEntityService, | ||||
| 		private queryService: QueryService, | ||||
| 		private roleService: RoleService, | ||||
| 		private activeUsersChart: ActiveUsersChart, | ||||
| 		private idService: IdService, | ||||
|  | @ -81,8 +76,8 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint- | |||
| 		private redisTimelineService: RedisTimelineService, | ||||
| 	) { | ||||
| 		super(meta, paramDef, async (ps, me) => { | ||||
| 			const untilId = ps.untilId ?? ps.untilDate ? this.idService.genId(new Date(ps.untilDate!)) : null; | ||||
| 			const sinceId = ps.sinceId ?? ps.sinceDate ? this.idService.genId(new Date(ps.sinceDate!)) : null; | ||||
| 			const untilId = ps.untilId ?? (ps.untilDate ? this.idService.genId(new Date(ps.untilDate!)) : null); | ||||
| 			const sinceId = ps.sinceId ?? (ps.sinceDate ? this.idService.genId(new Date(ps.sinceDate!)) : null); | ||||
| 
 | ||||
| 			const policies = await this.roleService.getUserPolicies(me.id); | ||||
| 			if (!policies.ltlAvailable) { | ||||
|  | @ -107,68 +102,6 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint- | |||
| 			let noteIds = Array.from(new Set([...htlNoteIds, ...ltlNoteIds])); | ||||
| 			noteIds.sort((a, b) => a > b ? -1 : 1); | ||||
| 			noteIds = noteIds.slice(0, ps.limit); | ||||
| 			if (noteIds.length < ps.limit) { | ||||
| 				const followingQuery = this.followingsRepository.createQueryBuilder('following') | ||||
| 					.select('following.followeeId') | ||||
| 					.where('following.followerId = :followerId', { followerId: me.id }); | ||||
| 				const query = this.queryService.makePaginationQuery(this.notesRepository.createQueryBuilder('note'), | ||||
| 					ps.sinceId, ps.untilId, ps.sinceDate, ps.untilDate) | ||||
| 					.andWhere('note.id > :minId', { minId: this.idService.genId(new Date(Date.now() - (1000 * 60 * 60 * 24 * 10))) }) // 10日前まで
 | ||||
| 					.andWhere(new Brackets(qb => { | ||||
| 						qb.where(`((note.userId IN (${ followingQuery.getQuery() })) OR (note.userId = :meId))`, { meId: me.id }) | ||||
| 							.orWhere('(note.visibility = \'public\') AND (note.userHost IS NULL)'); | ||||
| 					})) | ||||
| 					.innerJoinAndSelect('note.user', 'user') | ||||
| 					.leftJoinAndSelect('note.reply', 'reply') | ||||
| 					.leftJoinAndSelect('note.renote', 'renote') | ||||
| 					.leftJoinAndSelect('reply.user', 'replyUser') | ||||
| 					.leftJoinAndSelect('renote.user', 'renoteUser') | ||||
| 					.setParameters(followingQuery.getParameters()); | ||||
| 
 | ||||
| 				this.queryService.generateChannelQuery(query, me); | ||||
| 				this.queryService.generateVisibilityQuery(query, me); | ||||
| 				this.queryService.generateMutedUserQuery(query, me); | ||||
| 				this.queryService.generateBlockedUserQuery(query, me); | ||||
| 				this.queryService.generateMutedUserRenotesQueryForNotes(query, me); | ||||
| 
 | ||||
| 				if (ps.includeMyRenotes === false) { | ||||
| 					query.andWhere(new Brackets(qb => { | ||||
| 						qb.orWhere('note.userId != :meId', { meId: me.id }); | ||||
| 						qb.orWhere('note.renoteId IS NULL'); | ||||
| 						qb.orWhere('note.text IS NOT NULL'); | ||||
| 						qb.orWhere('note.fileIds != \'{}\''); | ||||
| 						qb.orWhere('0 < (SELECT COUNT(*) FROM poll WHERE poll."noteId" = note.id)'); | ||||
| 					})); | ||||
| 				} | ||||
| 
 | ||||
| 				if (ps.includeRenotedMyNotes === false) { | ||||
| 					query.andWhere(new Brackets(qb => { | ||||
| 						qb.orWhere('note.renoteUserId != :meId', { meId: me.id }); | ||||
| 						qb.orWhere('note.renoteId IS NULL'); | ||||
| 						qb.orWhere('note.text IS NOT NULL'); | ||||
| 						qb.orWhere('note.fileIds != \'{}\''); | ||||
| 						qb.orWhere('0 < (SELECT COUNT(*) FROM poll WHERE poll."noteId" = note.id)'); | ||||
| 					})); | ||||
| 				} | ||||
| 
 | ||||
| 				if (ps.includeLocalRenotes === false) { | ||||
| 					query.andWhere(new Brackets(qb => { | ||||
| 						qb.orWhere('note.renoteUserHost IS NOT NULL'); | ||||
| 						qb.orWhere('note.renoteId IS NULL'); | ||||
| 						qb.orWhere('note.text IS NOT NULL'); | ||||
| 						qb.orWhere('note.fileIds != \'{}\''); | ||||
| 						qb.orWhere('0 < (SELECT COUNT(*) FROM poll WHERE poll."noteId" = note.id)'); | ||||
| 					})); | ||||
| 				} | ||||
| 
 | ||||
| 				if (ps.withFiles) { | ||||
| 					query.andWhere('note.fileIds != \'{}\''); | ||||
| 				} | ||||
| 				//#endregion
 | ||||
| 				const ids = await query.limit(ps.limit - noteIds.length).getMany(); | ||||
| 				noteIds = noteIds.concat(ids.map(note => note.id)); | ||||
| 
 | ||||
| 			} | ||||
| 
 | ||||
| 			if (noteIds.length === 0) { | ||||
| 				return []; | ||||
|  |  | |||
|  | @ -17,7 +17,6 @@ import { CacheService } from '@/core/CacheService.js'; | |||
| import { isUserRelated } from '@/misc/is-user-related.js'; | ||||
| import { RedisTimelineService } from '@/core/RedisTimelineService.js'; | ||||
| import { ApiError } from '../../error.js'; | ||||
| import {QueryService} from "@/core/QueryService.js"; | ||||
| 
 | ||||
| export const meta = { | ||||
| 	tags: ['notes'], | ||||
|  | @ -67,13 +66,15 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint- | |||
| 
 | ||||
| 		private noteEntityService: NoteEntityService, | ||||
| 		private roleService: RoleService, | ||||
| 		private queryService: QueryService, | ||||
| 		private activeUsersChart: ActiveUsersChart, | ||||
| 		private idService: IdService, | ||||
| 		private cacheService: CacheService, | ||||
| 		private redisTimelineService: RedisTimelineService, | ||||
| 	) { | ||||
| 		super(meta, paramDef, async (ps, me) => { | ||||
| 			const untilId = ps.untilId ?? (ps.untilDate ? this.idService.genId(new Date(ps.untilDate!)) : null); | ||||
| 			const sinceId = ps.sinceId ?? (ps.sinceDate ? this.idService.genId(new Date(ps.sinceDate!)) : null); | ||||
| 
 | ||||
| 			const policies = await this.roleService.getUserPolicies(me ? me.id : null); | ||||
| 			if (!policies.ltlAvailable) { | ||||
| 				throw new ApiError(meta.errors.ltlDisabled); | ||||
|  | @ -89,56 +90,8 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint- | |||
| 				this.cacheService.userBlockedCache.fetch(me.id), | ||||
| 			]) : [new Set<string>(), new Set<string>(), new Set<string>()]; | ||||
| 
 | ||||
| 			let timeline: MiNote[] = []; | ||||
| 
 | ||||
| 			const limit = ps.limit + (ps.untilId ? 1 : 0) + (ps.sinceId ? 1 : 0); // untilIdに指定したものも含まれるため+1
 | ||||
| 			let noteIdsRes: [string, string[]][] = []; | ||||
| 
 | ||||
| 			if (!ps.sinceId && !ps.sinceDate) { | ||||
| 				noteIdsRes = await this.redisForTimelines.xrevrange( | ||||
| 					ps.withFiles ? 'localTimelineWithFiles' : 'localTimeline', | ||||
| 					ps.untilId ? this.idService.parse(ps.untilId).date.getTime() : ps.untilDate ?? '+', | ||||
| 					ps.sinceId ? this.idService.parse(ps.sinceId).date.getTime() : ps.sinceDate ?? '-', | ||||
| 					'COUNT', limit); | ||||
| 			} | ||||
| 
 | ||||
| 			let noteIds = noteIdsRes.map(x => x[1][1]).filter(x => x !== ps.untilId && x !== ps.sinceId); | ||||
| 
 | ||||
| 			if (noteIds.length < limit) { | ||||
| 				//#region Construct query
 | ||||
| 				const query = this.queryService.makePaginationQuery(this.notesRepository.createQueryBuilder('note'), | ||||
| 					ps.sinceId, ps.untilId, ps.sinceDate, ps.untilDate) | ||||
| 					.andWhere('note.id > :minId', { minId: this.idService.genId(new Date(Date.now() - (1000 * 60 * 60 * 24 * 10))) }) // 10日前まで
 | ||||
| 					.andWhere('(note.visibility = \'public\') AND (note.userHost IS NULL)') | ||||
| 					.innerJoinAndSelect('note.user', 'user') | ||||
| 					.leftJoinAndSelect('note.reply', 'reply') | ||||
| 					.leftJoinAndSelect('note.renote', 'renote') | ||||
| 					.leftJoinAndSelect('reply.user', 'replyUser') | ||||
| 					.leftJoinAndSelect('renote.user', 'renoteUser'); | ||||
| 
 | ||||
| 				this.queryService.generateChannelQuery(query, me); | ||||
| 				this.queryService.generateVisibilityQuery(query, me); | ||||
| 				if (me) this.queryService.generateMutedUserQuery(query, me); | ||||
| 				if (me) this.queryService.generateBlockedUserQuery(query, me); | ||||
| 				if (me) this.queryService.generateMutedUserRenotesQueryForNotes(query, me); | ||||
| 
 | ||||
| 				if (ps.withFiles) { | ||||
| 					query.andWhere('note.fileIds != \'{}\''); | ||||
| 				} | ||||
| 
 | ||||
| 
 | ||||
| 				if (ps.withRenotes === false) { | ||||
| 					query.andWhere(new Brackets(qb => { | ||||
| 						qb.orWhere('note.renoteId IS NULL'); | ||||
| 						qb.orWhere(new Brackets(qb => { | ||||
| 							qb.orWhere('note.text IS NOT NULL'); | ||||
| 							qb.orWhere('note.fileIds != \'{}\''); | ||||
| 						})); | ||||
| 					})); | ||||
| 				} | ||||
| 				const ids = await query.limit(limit - noteIds.length).getMany(); | ||||
| 				noteIds = noteIds.concat(ids.map(note => note.id)); | ||||
| 			} | ||||
| 			let noteIds = await this.redisTimelineService.get(ps.withFiles ? 'localTimelineWithFiles' : 'localTimeline', untilId, sinceId); | ||||
| 			noteIds = noteIds.slice(0, ps.limit); | ||||
| 
 | ||||
| 			if (noteIds.length === 0) { | ||||
| 				return []; | ||||
|  | @ -153,7 +106,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint- | |||
| 				.leftJoinAndSelect('renote.user', 'renoteUser') | ||||
| 				.leftJoinAndSelect('note.channel', 'channel'); | ||||
| 
 | ||||
| 			timeline = await query.getMany(); | ||||
| 			let timeline = await query.getMany(); | ||||
| 
 | ||||
| 			timeline = timeline.filter(note => { | ||||
| 				if (me && (note.userId === me.id)) { | ||||
|  | @ -171,6 +124,8 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint- | |||
| 				return true; | ||||
| 			}); | ||||
| 
 | ||||
| 			// TODO: フィルタした結果件数が足りなかった場合の対応
 | ||||
| 
 | ||||
| 			timeline.sort((a, b) => a.id > b.id ? -1 : 1); | ||||
| 
 | ||||
| 			process.nextTick(() => { | ||||
|  |  | |||
|  | @ -60,15 +60,14 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint- | |||
| 		private notesRepository: NotesRepository, | ||||
| 
 | ||||
| 		private noteEntityService: NoteEntityService, | ||||
| 		private queryService: QueryService, | ||||
| 		private activeUsersChart: ActiveUsersChart, | ||||
| 		private idService: IdService, | ||||
| 		private cacheService: CacheService, | ||||
| 		private redisTimelineService: RedisTimelineService, | ||||
| 	) { | ||||
| 		super(meta, paramDef, async (ps, me) => { | ||||
| 			const untilId = ps.untilId ?? ps.untilDate ? this.idService.genId(new Date(ps.untilDate!)) : null; | ||||
| 			const sinceId = ps.sinceId ?? ps.sinceDate ? this.idService.genId(new Date(ps.sinceDate!)) : null; | ||||
| 			const untilId = ps.untilId ?? (ps.untilDate ? this.idService.genId(new Date(ps.untilDate!)) : null); | ||||
| 			const sinceId = ps.sinceId ?? (ps.sinceDate ? this.idService.genId(new Date(ps.sinceDate!)) : null); | ||||
| 
 | ||||
| 			const [ | ||||
| 				followings, | ||||
|  | @ -82,39 +81,8 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint- | |||
| 				this.cacheService.userBlockedCache.fetch(me.id), | ||||
| 			]); | ||||
| 
 | ||||
| 			let timeline: MiNote[] = []; | ||||
| 
 | ||||
| 			const limit = ps.limit + (ps.untilId ? 1 : 0) + (ps.sinceId ? 1 : 0); // untilIdに指定したものも含まれるため+1
 | ||||
| 			let noteIdsRes: [string, string[]][] = []; | ||||
| 
 | ||||
| 			if (!ps.sinceId && !ps.sinceDate) { | ||||
| 				noteIdsRes = await this.redisForTimelines.xrevrange( | ||||
| 					ps.withFiles ? `homeTimelineWithFiles:${me.id}` : `homeTimeline:${me.id}`, | ||||
| 					ps.untilId ? this.idService.parse(ps.untilId).date.getTime() : ps.untilDate ?? '+', | ||||
| 					ps.sinceId ? this.idService.parse(ps.sinceId).date.getTime() : ps.sinceDate ?? '-', | ||||
| 					'COUNT', limit); | ||||
| 			} | ||||
| 
 | ||||
| 			let noteIds = noteIdsRes.map(x => x[1][1]).filter(x => x !== ps.untilId && x !== ps.sinceId); | ||||
| 			if (noteIds.length < limit) { | ||||
| 				const query = this.queryService.makePaginationQuery(this.notesRepository.createQueryBuilder('note'), | ||||
| 					ps.sinceId, ps.untilId, ps.sinceDate, ps.untilDate); | ||||
| 				const followingIds = Object.keys(followings); | ||||
| 				if (followingIds.length > 0) { | ||||
| 					const meOrFolloweeIds = [me.id, ...followingIds]; | ||||
| 					query.andWhere('note.userId IN (:...meOrFolloweeIds)', { meOrFolloweeIds: meOrFolloweeIds }); | ||||
| 				} else { | ||||
| 					query.andWhere('note.userId = :meId', { meId: me.id }); | ||||
| 				} | ||||
| 
 | ||||
| 				this.queryService.generateChannelQuery(query, me); | ||||
| 				this.queryService.generateVisibilityQuery(query, me); | ||||
| 				this.queryService.generateMutedUserQuery(query, me); | ||||
| 				this.queryService.generateBlockedUserQuery(query, me); | ||||
| 				this.queryService.generateMutedUserRenotesQueryForNotes(query, me); | ||||
| 				const ids = await query.limit(limit - noteIds.length).getMany(); | ||||
| 				noteIds = noteIds.concat(ids.map(note => note.id)); | ||||
| 			} | ||||
| 			let noteIds = await this.redisTimelineService.get(ps.withFiles ? `homeTimelineWithFiles:${me.id}` : `homeTimeline:${me.id}`, untilId, sinceId); | ||||
| 			noteIds = noteIds.slice(0, ps.limit); | ||||
| 
 | ||||
| 			if (noteIds.length === 0) { | ||||
| 				return []; | ||||
|  | @ -129,7 +97,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint- | |||
| 				.leftJoinAndSelect('renote.user', 'renoteUser') | ||||
| 				.leftJoinAndSelect('note.channel', 'channel'); | ||||
| 
 | ||||
| 			timeline = await query.getMany(); | ||||
| 			let timeline = await query.getMany(); | ||||
| 
 | ||||
| 			timeline = timeline.filter(note => { | ||||
| 				if (note.userId === me.id) { | ||||
|  |  | |||
|  | @ -5,7 +5,7 @@ | |||
| 
 | ||||
| import ms from 'ms'; | ||||
| import { Inject, Injectable } from '@nestjs/common'; | ||||
| import type { UsersRepository, NotesRepository } from '@/models/_.js'; | ||||
| import type { UsersRepository, NotesRepository , DriveFilesRepository, MiDriveFile} from '@/models/_.js'; | ||||
| import { Endpoint } from '@/server/api/endpoint-base.js'; | ||||
| import { NoteDeleteService } from '@/core/NoteDeleteService.js'; | ||||
| import { DI } from '@/di-symbols.js'; | ||||
|  | @ -14,6 +14,7 @@ import { GlobalEventService } from '@/core/GlobalEventService.js'; | |||
| import { MAX_NOTE_TEXT_LENGTH } from '@/const.js'; | ||||
| import { ApiError } from '../../error.js'; | ||||
| 
 | ||||
| 
 | ||||
| export const meta = { | ||||
| 	tags: ['notes'], | ||||
| 
 | ||||
|  | @ -34,6 +35,11 @@ export const meta = { | |||
| 			code: 'NO_SUCH_NOTE', | ||||
| 			id: 'a6584e14-6e01-4ad3-b566-851e7bf0d474', | ||||
| 		}, | ||||
|       noSuchFile: { | ||||
|           message: 'Some files are not found.', | ||||
|           code: 'NO_SUCH_FILE', | ||||
|           id: 'b6992544-63e7-67f0-fa7f-32444b1b5306', | ||||
|       }, | ||||
| 	}, | ||||
| } as const; | ||||
| 
 | ||||
|  | @ -41,15 +47,68 @@ export const paramDef = { | |||
| 	type: 'object', | ||||
| 	properties: { | ||||
| 		noteId: { type: 'string', format: 'misskey:id' }, | ||||
| 		visibility: { type: 'string', enum: ['public', 'home', 'followers', 'specified'], default: 'public' }, | ||||
| 		visibleUserIds: { type: 'array', uniqueItems: true, items: { | ||||
| 				type: 'string', format: 'misskey:id', | ||||
| 			} }, | ||||
| 		cw: { type: 'string', nullable: true, maxLength: 100 }, | ||||
| 		localOnly: { type: 'boolean', default: false }, | ||||
| 		reactionAcceptance: { type: 'string', nullable: true, enum: [null, 'likeOnly', 'likeOnlyForRemote', 'nonSensitiveOnly', 'nonSensitiveOnlyForLocalLikeOnlyForRemote'], default: null }, | ||||
| 		noExtractMentions: { type: 'boolean', default: false }, | ||||
| 		noExtractHashtags: { type: 'boolean', default: false }, | ||||
| 		noExtractEmojis: { type: 'boolean', default: false }, | ||||
| 		replyId: { type: 'string', format: 'misskey:id', nullable: true }, | ||||
| 		renoteId: { type: 'string', format: 'misskey:id', nullable: true }, | ||||
| 		channelId: { type: 'string', format: 'misskey:id', nullable: true }, | ||||
| 
 | ||||
| 		// anyOf内にバリデーションを書いても最初の一つしかチェックされない
 | ||||
| 		// See https://github.com/misskey-dev/misskey/pull/10082
 | ||||
| 		text: { | ||||
| 			type: 'string', | ||||
| 			minLength: 1, | ||||
| 			maxLength: MAX_NOTE_TEXT_LENGTH, | ||||
| 			nullable: false, | ||||
| 			nullable: true, | ||||
| 		}, | ||||
| 		fileIds: { | ||||
| 			type: 'array', | ||||
| 			uniqueItems: true, | ||||
| 			minItems: 1, | ||||
| 			maxItems: 16, | ||||
| 			items: { type: 'string', format: 'misskey:id' }, | ||||
| 		}, | ||||
| 		mediaIds: { | ||||
| 			type: 'array', | ||||
| 			uniqueItems: true, | ||||
| 			minItems: 1, | ||||
| 			maxItems: 16, | ||||
| 			items: { type: 'string', format: 'misskey:id' }, | ||||
| 		}, | ||||
| 		poll: { | ||||
| 			type: 'object', | ||||
| 			nullable: true, | ||||
| 			properties: { | ||||
| 				choices: { | ||||
| 					type: 'array', | ||||
| 					uniqueItems: true, | ||||
| 					minItems: 2, | ||||
| 					maxItems: 10, | ||||
| 					items: { type: 'string', minLength: 1, maxLength: 50 }, | ||||
| 				}, | ||||
| 				multiple: { type: 'boolean' }, | ||||
| 				expiresAt: { type: 'integer', nullable: true }, | ||||
| 				expiredAfter: { type: 'integer', nullable: true, minimum: 1 }, | ||||
| 			}, | ||||
| 			required: ['choices'], | ||||
| 		}, | ||||
| 		cw: { type: 'string', nullable: true, maxLength: 100 }, | ||||
| 	}, | ||||
| 	required: ['noteId', 'text', 'cw'], | ||||
| 	// (re)note with text, files and poll are optional
 | ||||
| 	anyOf: [ | ||||
| 		{ required: ['text'] }, | ||||
| 		{ required: ['renoteId'] }, | ||||
| 		{ required: ['fileIds'] }, | ||||
| 		{ required: ['mediaIds'] }, | ||||
| 		{ required: ['poll'] }, | ||||
| 	], | ||||
| } as const; | ||||
| 
 | ||||
| @Injectable() | ||||
|  | @ -61,6 +120,9 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint- | |||
| 		@Inject(DI.notesRepository) | ||||
| 		private notesRepository: NotesRepository, | ||||
| 
 | ||||
|     @Inject(DI.driveFilesRepository) | ||||
|     private driveFilesRepository: DriveFilesRepository, | ||||
| 
 | ||||
| 		private getterService: GetterService, | ||||
| 		private globalEventService: GlobalEventService, | ||||
| 	) { | ||||
|  | @ -70,14 +132,34 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint- | |||
| 				throw err; | ||||
| 			}); | ||||
| 
 | ||||
|         let files: MiDriveFile[] = []; | ||||
|         const fileIds = ps.fileIds ?? null; | ||||
| 
 | ||||
|         if (fileIds != null) { | ||||
|             files = await this.driveFilesRepository.createQueryBuilder('file') | ||||
|                 .where('file.userId = :userId AND file.id IN (:...fileIds)', { | ||||
|                     userId: me.id, | ||||
|                     fileIds, | ||||
|                 }) | ||||
|                 .orderBy('array_position(ARRAY[:...fileIds], "id"::text)') | ||||
|                 .setParameters({ fileIds }) | ||||
|                 .getMany(); | ||||
| 
 | ||||
|             if (files.length !== fileIds.length) { | ||||
|                 throw new ApiError(meta.errors.noSuchFile); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
| 			if (note.userId !== me.id) { | ||||
| 				throw new ApiError(meta.errors.noSuchNote); | ||||
| 			} | ||||
| 
 | ||||
| 
 | ||||
| 			await this.notesRepository.update({ id: note.id }, { | ||||
| 				updatedAt: new Date(), | ||||
| 				cw: ps.cw, | ||||
| 				text: ps.text, | ||||
| 				fileIds: files.length > 0 ? files.map(f => f.id) : undefined, | ||||
| 			}); | ||||
| 
 | ||||
| 			this.globalEventService.publishNoteStream(note.id, 'updated', { | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue