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