summaryrefslogtreecommitdiff
path: root/packages/backend/src/server/api/endpoints/notes/drafts
diff options
context:
space:
mode:
authorsyuilo <4439005+syuilo@users.noreply.github.com>2025-09-26 15:29:52 +0900
committerGitHub <noreply@github.com>2025-09-26 15:29:52 +0900
commitd1446d195abb52c560c7c97177d08103a175acf7 (patch)
tree355689adb542333f4c5abb186ab9819c29274612 /packages/backend/src/server/api/endpoints/notes/drafts
parentfix(frontend): ビルド成果物のファイル名にlocalesのhashを含め... (diff)
downloadmisskey-d1446d195abb52c560c7c97177d08103a175acf7.tar.gz
misskey-d1446d195abb52c560c7c97177d08103a175acf7.tar.bz2
misskey-d1446d195abb52c560c7c97177d08103a175acf7.zip
feat: scheduled post (#16577)
* Update NoteDraft.ts * Update NoteDraft.ts * wip * Update CHANGELOG.md * wip * Update PostScheduledNoteProcessorService.ts * Update PostScheduledNoteProcessorService.ts * Update Notification.ts * wip * Update NoteDraftService.ts * Update NoteDraftService.ts * Update NoteDraftService.ts * wip * Create 1758677617888-scheduled-post.js * Update index.d.ts * Update stats.ts * wip * wip * wip * wip * wip * Update MkNotification.vue * wip * wip * wip * Update NoteDraftService.ts * Update NoteDraftService.ts * wip * wip * Update NoteDraftEntityService.ts * wip * Update index.d.ts * Update MkPostForm.vue * wip * wip * wip * Update NoteCreateService.ts * wip * wip * wip * Update NoteDraftEntityService.ts * Update NoteCreateService.ts * Update NoteDraftService.ts * wip * Update NoteDraftService.ts * wip * wip * Update MkPostForm.vue * wip * Update MkPostForm.vue * Update os.ts * wip * Update MkNoteDraftsDialog.vue
Diffstat (limited to 'packages/backend/src/server/api/endpoints/notes/drafts')
-rw-r--r--packages/backend/src/server/api/endpoints/notes/drafts/create.ts41
-rw-r--r--packages/backend/src/server/api/endpoints/notes/drafts/list.ts7
-rw-r--r--packages/backend/src/server/api/endpoints/notes/drafts/update.ts44
3 files changed, 60 insertions, 32 deletions
diff --git a/packages/backend/src/server/api/endpoints/notes/drafts/create.ts b/packages/backend/src/server/api/endpoints/notes/drafts/create.ts
index 1c28ec22d0..8f2fbf9197 100644
--- a/packages/backend/src/server/api/endpoints/notes/drafts/create.ts
+++ b/packages/backend/src/server/api/endpoints/notes/drafts/create.ts
@@ -124,6 +124,12 @@ export const meta = {
id: '9ee33bbe-fde3-4c71-9b51-e50492c6b9c8',
},
+ tooManyScheduledNotes: {
+ message: 'You cannot create scheduled notes any more.',
+ code: 'TOO_MANY_SCHEDULED_NOTES',
+ id: '22ae69eb-09e3-4541-a850-773cfa45e693',
+ },
+
cannotRenoteToExternal: {
message: 'Cannot Renote to External.',
code: 'CANNOT_RENOTE_TO_EXTERNAL',
@@ -162,7 +168,7 @@ export const paramDef = {
fileIds: {
type: 'array',
uniqueItems: true,
- minItems: 1,
+ minItems: 0,
maxItems: 16,
items: { type: 'string', format: 'misskey:id' },
},
@@ -183,8 +189,10 @@ export const paramDef = {
},
required: ['choices'],
},
+ scheduledAt: { type: 'integer', nullable: true },
+ isActuallyScheduled: { type: 'boolean', default: false },
},
- required: [],
+ required: ['visibility', 'visibleUserIds', 'cw', 'hashtag', 'localOnly', 'reactionAcceptance', 'replyId', 'renoteId', 'channelId', 'text', 'fileIds', 'poll', 'scheduledAt', 'isActuallyScheduled'],
} as const;
@Injectable()
@@ -196,22 +204,23 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
super(meta, paramDef, async (ps, me) => {
const draft = await this.noteDraftService.create(me, {
fileIds: ps.fileIds,
- poll: ps.poll ? {
- choices: ps.poll.choices,
- multiple: ps.poll.multiple ?? false,
- expiresAt: ps.poll.expiresAt ? new Date(ps.poll.expiresAt) : null,
- expiredAfter: ps.poll.expiredAfter ?? null,
- } : undefined,
- text: ps.text ?? null,
- replyId: ps.replyId ?? undefined,
- renoteId: ps.renoteId ?? undefined,
- cw: ps.cw ?? null,
- ...(ps.hashtag ? { hashtag: ps.hashtag } : {}),
+ pollChoices: ps.poll?.choices ?? [],
+ pollMultiple: ps.poll?.multiple ?? false,
+ pollExpiresAt: ps.poll?.expiresAt ? new Date(ps.poll.expiresAt) : null,
+ pollExpiredAfter: ps.poll?.expiredAfter ?? null,
+ hasPoll: ps.poll != null,
+ text: ps.text,
+ replyId: ps.replyId,
+ renoteId: ps.renoteId,
+ cw: ps.cw,
+ hashtag: ps.hashtag,
localOnly: ps.localOnly,
reactionAcceptance: ps.reactionAcceptance,
visibility: ps.visibility,
- visibleUserIds: ps.visibleUserIds ?? [],
- channelId: ps.channelId ?? undefined,
+ visibleUserIds: ps.visibleUserIds,
+ channelId: ps.channelId,
+ scheduledAt: ps.scheduledAt ? new Date(ps.scheduledAt) : null,
+ isActuallyScheduled: ps.isActuallyScheduled,
}).catch((err) => {
if (err instanceof IdentifiableError) {
switch (err.id) {
@@ -241,6 +250,8 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
throw new ApiError(meta.errors.cannotReplyToInvisibleNote);
case '215dbc76-336c-4d2a-9605-95766ba7dab0':
throw new ApiError(meta.errors.cannotReplyToSpecifiedVisibilityNoteWithExtendedVisibility);
+ case 'c3275f19-4558-4c59-83e1-4f684b5fab66':
+ throw new ApiError(meta.errors.tooManyScheduledNotes);
default:
throw err;
}
diff --git a/packages/backend/src/server/api/endpoints/notes/drafts/list.ts b/packages/backend/src/server/api/endpoints/notes/drafts/list.ts
index f24f9b8fb2..0774f09228 100644
--- a/packages/backend/src/server/api/endpoints/notes/drafts/list.ts
+++ b/packages/backend/src/server/api/endpoints/notes/drafts/list.ts
@@ -41,6 +41,7 @@ export const paramDef = {
untilId: { type: 'string', format: 'misskey:id' },
sinceDate: { type: 'integer' },
untilDate: { type: 'integer' },
+ scheduled: { type: 'boolean', nullable: true },
},
required: [],
} as const;
@@ -58,6 +59,12 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
const query = this.queryService.makePaginationQuery<MiNoteDraft>(this.noteDraftsRepository.createQueryBuilder('drafts'), ps.sinceId, ps.untilId, ps.sinceDate, ps.untilDate)
.andWhere('drafts.userId = :meId', { meId: me.id });
+ if (ps.scheduled === true) {
+ query.andWhere('drafts.isActuallyScheduled = true');
+ } else if (ps.scheduled === false) {
+ query.andWhere('drafts.isActuallyScheduled = false');
+ }
+
const drafts = await query
.limit(ps.limit)
.getMany();
diff --git a/packages/backend/src/server/api/endpoints/notes/drafts/update.ts b/packages/backend/src/server/api/endpoints/notes/drafts/update.ts
index ee221fb765..9a2e2ca415 100644
--- a/packages/backend/src/server/api/endpoints/notes/drafts/update.ts
+++ b/packages/backend/src/server/api/endpoints/notes/drafts/update.ts
@@ -159,6 +159,12 @@ export const meta = {
code: 'CANNOT_REPLY_TO_SPECIFIED_VISIBILITY_NOTE_WITH_EXTENDED_VISIBILITY',
id: '215dbc76-336c-4d2a-9605-95766ba7dab0',
},
+
+ tooManyScheduledNotes: {
+ message: 'You cannot create scheduled notes any more.',
+ code: 'TOO_MANY_SCHEDULED_NOTES',
+ id: '02f5df79-08ae-4a33-8524-f1503c8f6212',
+ },
},
limit: {
@@ -171,14 +177,14 @@ export const paramDef = {
type: 'object',
properties: {
draftId: { type: 'string', nullable: false, format: 'misskey:id' },
- visibility: { type: 'string', enum: ['public', 'home', 'followers', 'specified'], default: 'public' },
+ visibility: { type: 'string', enum: ['public', 'home', 'followers', 'specified'] },
visibleUserIds: { type: 'array', uniqueItems: true, items: {
type: 'string', format: 'misskey:id',
} },
cw: { type: 'string', nullable: true, minLength: 1, maxLength: 100 },
hashtag: { type: 'string', nullable: true, maxLength: 200 },
- localOnly: { type: 'boolean', default: false },
- reactionAcceptance: { type: 'string', nullable: true, enum: [null, 'likeOnly', 'likeOnlyForRemote', 'nonSensitiveOnly', 'nonSensitiveOnlyForLocalLikeOnlyForRemote'], default: null },
+ localOnly: { type: 'boolean' },
+ reactionAcceptance: { type: 'string', nullable: true, enum: [null, 'likeOnly', 'likeOnlyForRemote', 'nonSensitiveOnly', 'nonSensitiveOnlyForLocalLikeOnlyForRemote'] },
replyId: { type: 'string', format: 'misskey:id', nullable: true },
renoteId: { type: 'string', format: 'misskey:id', nullable: true },
channelId: { type: 'string', format: 'misskey:id', nullable: true },
@@ -194,7 +200,7 @@ export const paramDef = {
fileIds: {
type: 'array',
uniqueItems: true,
- minItems: 1,
+ minItems: 0,
maxItems: 16,
items: { type: 'string', format: 'misskey:id' },
},
@@ -215,6 +221,8 @@ export const paramDef = {
},
required: ['choices'],
},
+ scheduledAt: { type: 'integer', nullable: true },
+ isActuallyScheduled: { type: 'boolean' },
},
required: ['draftId'],
} as const;
@@ -228,22 +236,22 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
super(meta, paramDef, async (ps, me) => {
const draft = await this.noteDraftService.update(me, ps.draftId, {
fileIds: ps.fileIds,
- poll: ps.poll ? {
- choices: ps.poll.choices,
- multiple: ps.poll.multiple ?? false,
- expiresAt: ps.poll.expiresAt ? new Date(ps.poll.expiresAt) : null,
- expiredAfter: ps.poll.expiredAfter ?? null,
- } : undefined,
- text: ps.text ?? null,
- replyId: ps.replyId ?? undefined,
- renoteId: ps.renoteId ?? undefined,
- cw: ps.cw ?? null,
- ...(ps.hashtag ? { hashtag: ps.hashtag } : {}),
+ pollChoices: ps.poll?.choices,
+ pollMultiple: ps.poll?.multiple,
+ pollExpiresAt: ps.poll?.expiresAt ? new Date(ps.poll.expiresAt) : null,
+ pollExpiredAfter: ps.poll?.expiredAfter,
+ text: ps.text,
+ replyId: ps.replyId,
+ renoteId: ps.renoteId,
+ cw: ps.cw,
+ hashtag: ps.hashtag,
localOnly: ps.localOnly,
reactionAcceptance: ps.reactionAcceptance,
visibility: ps.visibility,
- visibleUserIds: ps.visibleUserIds ?? [],
- channelId: ps.channelId ?? undefined,
+ visibleUserIds: ps.visibleUserIds,
+ channelId: ps.channelId,
+ scheduledAt: ps.scheduledAt ? new Date(ps.scheduledAt) : null,
+ isActuallyScheduled: ps.isActuallyScheduled,
}).catch((err) => {
if (err instanceof IdentifiableError) {
switch (err.id) {
@@ -285,6 +293,8 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
throw new ApiError(meta.errors.containsProhibitedWords);
case '4de0363a-3046-481b-9b0f-feff3e211025':
throw new ApiError(meta.errors.containsTooManyMentions);
+ case 'bacdf856-5c51-4159-b88a-804fa5103be5':
+ throw new ApiError(meta.errors.tooManyScheduledNotes);
default:
throw err;
}