wip
This commit is contained in:
parent
d9d90a04e2
commit
8fede2d670
|
@ -11,12 +11,14 @@ export class ScheduledPost1758677617888 {
|
|||
*/
|
||||
async up(queryRunner) {
|
||||
await queryRunner.query(`ALTER TABLE "note_draft" ADD "scheduledAt" TIMESTAMP WITH TIME ZONE`);
|
||||
await queryRunner.query(`ALTER TABLE "note_draft" ADD "isActuallyScheduled" boolean NOT NULL DEFAULT false`);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {QueryRunner} queryRunner
|
||||
*/
|
||||
async down(queryRunner) {
|
||||
await queryRunner.query(`ALTER TABLE "note_draft" DROP COLUMN "isActuallyScheduled"`);
|
||||
await queryRunner.query(`ALTER TABLE "note_draft" DROP COLUMN "scheduledAt"`);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -32,6 +32,7 @@ export type NoteDraftOptions = {
|
|||
channelId?: MiChannel['id'] | null;
|
||||
poll?: (IPoll & { expiredAfter?: number | null }) | null;
|
||||
scheduledAt?: Date | null;
|
||||
isActuallyScheduled?: boolean;
|
||||
};
|
||||
|
||||
@Injectable()
|
||||
|
@ -100,7 +101,7 @@ export class NoteDraftService {
|
|||
appliedDraft.userId = me.id;
|
||||
const draft = await this.noteDraftsRepository.insertOne(appliedDraft);
|
||||
|
||||
if (draft.scheduledAt) {
|
||||
if (draft.scheduledAt && draft.isActuallyScheduled) {
|
||||
this.schedule(draft);
|
||||
}
|
||||
|
||||
|
@ -133,7 +134,7 @@ export class NoteDraftService {
|
|||
await this.noteDraftsRepository.update(draftId, appliedDraft);
|
||||
|
||||
this.clearSchedule(draft).then(() => {
|
||||
if (appliedDraft.scheduledAt) {
|
||||
if (appliedDraft.scheduledAt != null && appliedDraft.isActuallyScheduled) {
|
||||
this.schedule(draft);
|
||||
}
|
||||
});
|
||||
|
@ -328,6 +329,7 @@ export class NoteDraftService {
|
|||
localOnly: data.localOnly,
|
||||
reactionAcceptance: data.reactionAcceptance,
|
||||
scheduledAt: data.scheduledAt ?? null,
|
||||
isActuallyScheduled: data.isActuallyScheduled ?? false,
|
||||
} satisfies MiNoteDraft;
|
||||
|
||||
return appliedDraft;
|
||||
|
@ -335,6 +337,7 @@ export class NoteDraftService {
|
|||
|
||||
@bindThis
|
||||
public async schedule(draft: MiNoteDraft): Promise<void> {
|
||||
if (!draft.isActuallyScheduled) return;
|
||||
if (draft.scheduledAt == null) return;
|
||||
if (draft.scheduledAt.getTime() <= Date.now()) return;
|
||||
|
||||
|
|
|
@ -106,6 +106,7 @@ export class NoteDraftEntityService implements OnModuleInit {
|
|||
id: noteDraft.id,
|
||||
createdAt: this.idService.parse(noteDraft.id).date.toISOString(),
|
||||
scheduledAt: noteDraft.scheduledAt?.getTime() ?? null,
|
||||
isActuallyScheduled: noteDraft.isActuallyScheduled,
|
||||
userId: noteDraft.userId,
|
||||
user: packedUsers?.get(noteDraft.userId) ?? this.userEntityService.pack(noteDraft.user ?? noteDraft.userId, me),
|
||||
text: text,
|
||||
|
|
|
@ -153,12 +153,16 @@ export class MiNoteDraft {
|
|||
|
||||
//#endregion
|
||||
|
||||
// 予約投稿
|
||||
@Column('timestamp with time zone', {
|
||||
nullable: true,
|
||||
})
|
||||
public scheduledAt: Date | null;
|
||||
|
||||
@Column('boolean', {
|
||||
default: false,
|
||||
})
|
||||
public isActuallyScheduled: boolean;
|
||||
|
||||
constructor(data: Partial<MiNoteDraft>) {
|
||||
if (data == null) return;
|
||||
|
||||
|
|
|
@ -171,5 +171,9 @@ export const packedNoteDraftSchema = {
|
|||
type: 'number',
|
||||
optional: false, nullable: true,
|
||||
},
|
||||
isActuallyScheduled: {
|
||||
type: 'boolean',
|
||||
optional: false, nullable: false,
|
||||
},
|
||||
},
|
||||
} as const;
|
||||
|
|
|
@ -32,7 +32,7 @@ export class PostScheduledNoteProcessorService {
|
|||
@bindThis
|
||||
public async process(job: Bull.Job<PostScheduledNoteJobData>): Promise<void> {
|
||||
const draft = await this.noteDraftsRepository.findOne({ where: { id: job.data.noteDraftId }, relations: ['user'] });
|
||||
if (draft == null || draft.user == null || draft.scheduledAt == null) {
|
||||
if (draft == null || draft.user == null || draft.scheduledAt == null || !draft.isActuallyScheduled) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -184,6 +184,7 @@ export const paramDef = {
|
|||
required: ['choices'],
|
||||
},
|
||||
scheduledAt: { type: 'integer', nullable: true },
|
||||
isActuallyScheduled: { type: 'boolean', default: false },
|
||||
},
|
||||
required: [],
|
||||
} as const;
|
||||
|
@ -214,6 +215,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
|||
visibleUserIds: ps.visibleUserIds ?? [],
|
||||
channelId: ps.channelId ?? undefined,
|
||||
scheduledAt: ps.scheduledAt ? new Date(ps.scheduledAt) : null,
|
||||
isActuallyScheduled: ps.isActuallyScheduled ?? false,
|
||||
}).catch((err) => {
|
||||
if (err instanceof IdentifiableError) {
|
||||
switch (err.id) {
|
||||
|
|
|
@ -216,6 +216,7 @@ export const paramDef = {
|
|||
required: ['choices'],
|
||||
},
|
||||
scheduledAt: { type: 'integer', nullable: true },
|
||||
isActuallyScheduled: { type: 'boolean', default: false },
|
||||
},
|
||||
required: ['draftId'],
|
||||
} as const;
|
||||
|
@ -246,6 +247,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
|||
visibleUserIds: ps.visibleUserIds ?? [],
|
||||
channelId: ps.channelId ?? undefined,
|
||||
scheduledAt: ps.scheduledAt ? new Date(ps.scheduledAt) : null,
|
||||
isActuallyScheduled: ps.isActuallyScheduled ?? false,
|
||||
}).catch((err) => {
|
||||
if (err instanceof IdentifiableError) {
|
||||
switch (err.id) {
|
||||
|
|
|
@ -669,6 +669,7 @@ function clear() {
|
|||
files.value = [];
|
||||
poll.value = null;
|
||||
quoteId.value = null;
|
||||
scheduledAt.value = null;
|
||||
}
|
||||
|
||||
function onKeydown(ev: KeyboardEvent) {
|
||||
|
@ -839,7 +840,9 @@ function deleteDraft() {
|
|||
miLocalStorage.setItem('drafts', JSON.stringify(draftData));
|
||||
}
|
||||
|
||||
async function saveServerDraft(clearLocal = false) {
|
||||
async function saveServerDraft(options: {
|
||||
isActuallyScheduled?: boolean;
|
||||
} = {}) {
|
||||
return await os.apiWithDialog(serverDraftId.value == null ? 'notes/drafts/create' : 'notes/drafts/update', {
|
||||
...(serverDraftId.value == null ? {} : { draftId: serverDraftId.value }),
|
||||
text: text.value,
|
||||
|
@ -855,12 +858,7 @@ async function saveServerDraft(clearLocal = false) {
|
|||
channelId: targetChannel.value ? targetChannel.value.id : undefined,
|
||||
reactionAcceptance: reactionAcceptance.value,
|
||||
scheduledAt: scheduledAt.value,
|
||||
}).then(() => {
|
||||
if (clearLocal) {
|
||||
clear();
|
||||
deleteDraft();
|
||||
}
|
||||
}).catch((err) => {
|
||||
isActuallyScheduled: options.isActuallyScheduled ?? false,
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -895,6 +893,21 @@ async function post(ev?: MouseEvent) {
|
|||
}
|
||||
}
|
||||
|
||||
if (scheduledAt.value != null) {
|
||||
if (uploader.items.value.some(x => x.uploaded == null)) {
|
||||
await uploadFiles();
|
||||
|
||||
// アップロード失敗したものがあったら中止
|
||||
if (uploader.items.value.some(x => x.uploaded == null)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
await postAsScheduled();
|
||||
clear();
|
||||
return;
|
||||
}
|
||||
|
||||
if (props.mock) return;
|
||||
|
||||
if (visibility.value === 'public' && (
|
||||
|
@ -1066,6 +1079,14 @@ async function post(ev?: MouseEvent) {
|
|||
});
|
||||
}
|
||||
|
||||
async function postAsScheduled() {
|
||||
if (props.mock) return;
|
||||
|
||||
await saveServerDraft({
|
||||
isActuallyScheduled: true,
|
||||
});
|
||||
}
|
||||
|
||||
function cancel() {
|
||||
emit('cancel');
|
||||
}
|
||||
|
@ -1247,6 +1268,10 @@ async function schedule() {
|
|||
scheduledAt.value = result.getTime();
|
||||
}
|
||||
|
||||
function cancelSchedule() {
|
||||
scheduledAt.value = null;
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
if (props.autofocus) {
|
||||
focus();
|
||||
|
|
|
@ -4463,6 +4463,7 @@ export type components = {
|
|||
/** @enum {string|null} */
|
||||
reactionAcceptance: 'likeOnly' | 'likeOnlyForRemote' | 'nonSensitiveOnly' | 'nonSensitiveOnlyForLocalLikeOnlyForRemote' | null;
|
||||
scheduledAt: number | null;
|
||||
isActuallyScheduled: boolean;
|
||||
};
|
||||
NoteReaction: {
|
||||
/** Format: id */
|
||||
|
@ -29205,6 +29206,8 @@ export interface operations {
|
|||
expiredAfter?: number | null;
|
||||
} | null;
|
||||
scheduledAt?: number | null;
|
||||
/** @default false */
|
||||
isActuallyScheduled?: boolean;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
@ -29447,6 +29450,8 @@ export interface operations {
|
|||
expiredAfter?: number | null;
|
||||
} | null;
|
||||
scheduledAt?: number | null;
|
||||
/** @default false */
|
||||
isActuallyScheduled?: boolean;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue