Skip to content

Commit

Permalink
idの状態でキューに格納しておく
Browse files Browse the repository at this point in the history
  • Loading branch information
kozakura913 committed Sep 29, 2024
1 parent 4919bf0 commit cdbe68b
Show file tree
Hide file tree
Showing 4 changed files with 144 additions and 64 deletions.
63 changes: 42 additions & 21 deletions packages/backend/src/models/NoteSchedule.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,35 +9,56 @@ import { MiNote } from '@/models/Note.js';
import { id } from './util/id.js';
import { MiUser } from './User.js';
import { MiChannel } from './Channel.js';
import { EventSchema } from './Event.js';
import type { MiDriveFile } from './DriveFile.js';

type MinimumUser = {
id: MiUser['id'];
host: MiUser['host'];
username: MiUser['username'];
uri: MiUser['uri'];
};

export type MiScheduleNoteType={
/** Date.toISOString() */
createdAt: string;
visibility: 'public' | 'home' | 'followers' | 'specified';
visibleUsers: MinimumUser[];
channel?: MiChannel['id'];
poll: {
multiple: boolean;
choices: string[];
/** Date.toISOString() */
expiresAt: string | null
} | undefined;
renote?: MiNote['id'];
localOnly: boolean;
cw?: string|null;
reactionAcceptance: 'likeOnly'|'likeOnlyForRemote'| 'nonSensitiveOnly'| 'nonSensitiveOnlyForLocalLikeOnlyForRemote'| null;
files: MiDriveFile['id'][];
text?: string|null;
reply?: MiNote['id'];
event?: {
/** Date.toISOString() */
start: string;
/** Date.toISOString() */
end: string | null;
title: string;
metadata: EventSchema;
} | null;
disableRightClick:boolean,
apMentions?: MinimumUser[] | null;
apHashtags?: string[] | null;
apEmojis?: string[] | null;
}

@Entity('note_schedule')
export class MiNoteSchedule {
@PrimaryColumn(id())
public id: string;

@Column('jsonb')
public note:{
id: MiNote['id'];
apEmojis?: any[];
visibility: 'public' | 'home' | 'followers' | 'specified';
apMentions?: any[];
visibleUsers: MiUser[];
channel: null | MiChannel;
poll: {
multiple: boolean;
choices: string[];
expiresAt: Date | null
} | undefined;
renote: null | MiNote;
localOnly: boolean;
cw?: string|null;
apHashtags?: string[];
reactionAcceptance: 'likeOnly'|'likeOnlyForRemote'| 'nonSensitiveOnly'| 'nonSensitiveOnlyForLocalLikeOnlyForRemote'| null;
files: MiDriveFile[];
text: string;
reply: null | MiNote
};
public note:MiScheduleNoteType;

@Index()
@Column('varchar', {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { Inject, Injectable } from '@nestjs/common';
import type Logger from '@/logger.js';
import { bindThis } from '@/decorators.js';
import { NoteCreateService } from '@/core/NoteCreateService.js';
import type { NoteScheduleRepository, UsersRepository } from '@/models/_.js';
import type { ChannelsRepository, DriveFilesRepository, MiDriveFile, NoteScheduleRepository, NotesRepository, UsersRepository } from '@/models/_.js';
import { DI } from '@/di-symbols.js';
import { QueueLoggerService } from '../QueueLoggerService.js';
import type * as Bull from 'bullmq';
Expand All @@ -23,9 +23,15 @@ export class ScheduleNotePostProcessorService {

@Inject(DI.usersRepository)
private usersRepository: UsersRepository,
@Inject(DI.driveFilesRepository)
private driveFilesRepository: DriveFilesRepository,
@Inject(DI.notesRepository)
private notesRepository: NotesRepository,
@Inject(DI.channelsRepository)
private channelsRepository: ChannelsRepository,

private noteCreateService: NoteCreateService,
private queueLoggerService: QueueLoggerService,
private noteCreateService: NoteCreateService,
private queueLoggerService: QueueLoggerService,
) {
this.logger = this.queueLoggerService.logger.createSubLogger('schedule-note-post');
}
Expand All @@ -36,8 +42,57 @@ export class ScheduleNotePostProcessorService {
if (!data) {
this.logger.warn(`Schedule note ${job.data.scheduleNoteId} not found`);
} else {
const me = await this.usersRepository.findOneByOrFail({ id: data.userId });
await this.noteCreateService.create(me, data.note);
const me = await this.usersRepository.findOneBy({ id: data.userId });
const note = data.note;

//idの形式でキューに積んであったのをDBから取り寄せる
const reply = note.reply ? await this.notesRepository.findOneBy({ id: note.reply }) : undefined;
const renote = note.reply ? await this.notesRepository.findOneBy({ id: note.renote }) : undefined;
const channel = note.channel ? await this.channelsRepository.findOneBy({ id: note.channel, isArchived: false }) : undefined;
let files: MiDriveFile[] = [];
const fileIds = note.files ?? null;
if (fileIds != null && fileIds.length > 0 && me) {
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 (
!data.userId ||
!me ||
(note.reply && !reply) ||
(note.renote && !renote) ||
(note.channel && !channel) ||
(note.files.length !== files.length)
) {
//キューに積んだときは有った物が消滅してたら予約投稿をキャンセルする
this.logger.warn('cancel schedule note');
await this.noteScheduleRepository.remove(data);
return;
}
await this.noteCreateService.create(me, {
...note,
createdAt: new Date(note.createdAt), //typeORMのjsonbで何故かstringにされるから戻す
files,
poll: note.poll ? {
choices: note.poll.choices,
multiple: note.poll.multiple,
expiresAt: note.poll.expiresAt ? new Date(note.poll.expiresAt) : null,
} : undefined,
event: note.event ? {
start: new Date(note.event.start),
end: note.event.end ? new Date(note.event.end) : null,
title: note.event.title,
metadata: note.event.metadata,
} : undefined,
reply,
renote,
channel,
});
await this.noteScheduleRepository.remove(data);
}
});
Expand Down
58 changes: 30 additions & 28 deletions packages/backend/src/server/api/endpoints/notes/schedule/create.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import type {
DriveFilesRepository,
ChannelsRepository,
NoteScheduleRepository,
MiNoteSchedule,
} from '@/models/_.js';
import type { MiDriveFile } from '@/models/DriveFile.js';
import type { MiNote } from '@/models/Note.js';
Expand All @@ -24,6 +25,8 @@ import { Endpoint } from '@/server/api/endpoint-base.js';
import { DI } from '@/di-symbols.js';
import { QueueService } from '@/core/QueueService.js';
import { IdService } from '@/core/IdService.js';
import { IEvent } from '@/models/Event.js';
import { MiScheduleNoteType } from '@/models/NoteSchedule.js';
import { ApiError } from '../../../error.js';

export const meta = {
Expand Down Expand Up @@ -123,6 +126,7 @@ export const paramDef = {
} },
cw: { type: 'string', nullable: true, minLength: 1, maxLength: 100 },
reactionAcceptance: { type: 'string', nullable: true, enum: [null, 'likeOnly', 'likeOnlyForRemote', 'nonSensitiveOnly', 'nonSensitiveOnlyForLocalLikeOnlyForRemote'], default: null },
disableRightClick: { type: 'boolean', default: false },
noExtractMentions: { type: 'boolean', default: false },
noExtractHashtags: { type: 'boolean', default: false },
noExtractEmojis: { type: 'boolean', default: false },
Expand Down Expand Up @@ -169,6 +173,16 @@ export const paramDef = {
},
required: ['choices'],
},
event: {
type: 'object',
nullable: true,
properties: {
title: { type: 'string', minLength: 1, maxLength: 128, nullable: false },
start: { type: 'integer', nullable: false },
end: { type: 'integer', nullable: true },
metadata: { type: 'object' },
},
},
schedule: {
type: 'object',
nullable: false,
Expand Down Expand Up @@ -333,48 +347,36 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
if (ps.schedule.expiresAt < Date.now()) {
throw new ApiError(meta.errors.cannotCreateAlreadyExpiredSchedule);
}
} else {
throw new ApiError(meta.errors.cannotCreateAlreadyExpiredSchedule);
}
type NoteType = {
id:MiNote['id'];
apEmojis: any[] | undefined;
visibility: 'public' | 'home' | 'followers' | 'specified';
apMentions: any[] | undefined;
visibleUsers: MiUser[];
channel: null | MiChannel;
poll: {
multiple: boolean;
choices: string[];
expiresAt: Date | null;
} | undefined;
renote: null | MiNote;
localOnly: boolean;
cw?: string|null;
apHashtags: any[] | undefined;
reactionAcceptance: 'likeOnly'|'likeOnlyForRemote'| 'nonSensitiveOnly'| 'nonSensitiveOnlyForLocalLikeOnlyForRemote'| null;
files: MiDriveFile[];
text?: string;
reply: null | MiNote;
};
const note:NoteType = {
id: this.idService.gen(ps.schedule.expiresAt),
files: files,
const note:MiScheduleNoteType = {
createdAt: new Date(ps.schedule.expiresAt!).toISOString(),
files: files.map(f => f.id),
poll: ps.poll ? {
choices: ps.poll.choices,
multiple: ps.poll.multiple ?? false,
expiresAt: ps.poll.expiresAt ? new Date(ps.poll.expiresAt) : null,
expiresAt: ps.poll.expiresAt ? new Date(ps.poll.expiresAt).toISOString() : null,
} : undefined,
text: ps.text ?? undefined,
reply,
renote,
reply: reply?.id,
renote: renote?.id,
cw: ps.cw,
localOnly: false,
reactionAcceptance: ps.reactionAcceptance,
visibility: ps.visibility,
visibleUsers,
channel,
channel: channel?.id,
apMentions: ps.noExtractMentions ? [] : undefined,
apHashtags: ps.noExtractHashtags ? [] : undefined,
apEmojis: ps.noExtractEmojis ? [] : undefined,
event: ps.event ? {
start: new Date(ps.event.start!).toISOString(),
end: ps.event.end ? new Date(ps.event.end).toISOString() : null,
title: ps.event.title!,
metadata: ps.event.metadata ?? {},
} : undefined,
disableRightClick: ps.disableRightClick,
};

if (ps.schedule.expiresAt) {
Expand Down
22 changes: 12 additions & 10 deletions packages/backend/src/server/api/endpoints/notes/schedule/list.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,11 @@ import ms from 'ms';
import { Inject, Injectable } from '@nestjs/common';
import { Endpoint } from '@/server/api/endpoint-base.js';
import { DI } from '@/di-symbols.js';
import type { MiNoteSchedule, NoteScheduleRepository } from '@/models/_.js';
import type { MiNote, MiNoteSchedule, NoteScheduleRepository } from '@/models/_.js';
import { UserEntityService } from '@/core/entities/UserEntityService.js';
import { QueryService } from '@/core/QueryService.js';
import { Packed } from '@/misc/json-schema.js';
import { noteVisibilities } from '@/types.js';

export const meta = {
tags: ['notes'],
Expand All @@ -29,8 +30,8 @@ export const meta = {
type: 'object',
optional: false, nullable: false,
properties: {
id: { type: 'string', optional: false, nullable: false },
text: { type: 'string', optional: false, nullable: false },
createdAt: { type: 'string', optional: false, nullable: false },
text: { type: 'string', optional: true, nullable: false },
cw: { type: 'string', optional: true, nullable: true },
fileIds: { type: 'array', optional: false, nullable: false, items: { type: 'string', format: 'misskey:id', optional: false, nullable: false } },
visibility: { type: 'string', enum: ['public', 'home', 'followers', 'specified'], optional: false, nullable: false },
Expand All @@ -47,7 +48,6 @@ export const meta = {
ref: 'User',
},
reactionAcceptance: { type: 'string', nullable: true, enum: [null, 'likeOnly', 'likeOnlyForRemote', 'nonSensitiveOnly', 'nonSensitiveOnlyForLocalLikeOnlyForRemote'], default: null },
createdAt: { type: 'string', format: 'misskey:id', optional: false, nullable: false },
isSchedule: { type: 'boolean', optional: false, nullable: false },
},
},
Expand Down Expand Up @@ -91,13 +91,12 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
const scheduleNotesPack: {
id: string;
note: {
id: string;
text: string;
text?: string;
cw?: string|null;
fileIds: string[];
visibility: 'public' | 'home' | 'followers' | 'specified';
visibility: typeof noteVisibilities[number];
visibleUsers: Packed<'UserLite'>[];
reactionAcceptance: 'likeOnly'|'likeOnlyForRemote'| 'nonSensitiveOnly'| 'nonSensitiveOnlyForLocalLikeOnlyForRemote'| null;
reactionAcceptance: MiNote['reactionAcceptance'];
user: Packed<'User'>;
createdAt: string;
isSchedule: boolean;
Expand All @@ -110,9 +109,12 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
expiresAt: item.expiresAt.toISOString(),
note: {
...item.note,
text: item.note.text ?? '',
user: user,
visibleUsers: await userEntityService.packMany(item.note.visibleUsers, me),
fileIds: item.note.files.map(f => f.id),
visibility: item.note.visibility ?? 'public',
reactionAcceptance: item.note.reactionAcceptance ?? null,
visibleUsers: item.note.visibleUsers ? await userEntityService.packMany(item.note.visibleUsers.map(u => u.id), me) : [],
fileIds: item.note.files ? item.note.files : [],
createdAt: item.expiresAt.toISOString(),
isSchedule: true,
id: item.id,
Expand Down

0 comments on commit cdbe68b

Please sign in to comment.