yojo-art / cherrypick

連合志向のCherryPickフォーク
https://幼女.art
GNU Affero General Public License v3.0
10 stars 5 forks source link

予約投稿 #483

Closed kozakura913 closed 1 month ago

kozakura913 commented 1 month ago

resolve: #281 cherrypick from https://github.com/Type4ny-Project/Type4ny

What

予約投稿機能を追加する

Why

281

Additional info (optional)

Type4nyから持ってきたらだいぶコンフリクトしてた。事故ってるかも

Checklist

codecov[bot] commented 1 month ago

Codecov Report

Attention: Patch coverage is 62.77245% with 427 lines in your changes missing coverage. Please review.

Project coverage is 40.52%. Comparing base (a7b8df8) to head (b6a6379). Report is 24 commits behind head on develop.

Files with missing lines Patch % Lines
.../src/server/api/endpoints/notes/schedule/create.ts 52.92% 185 Missing :warning:
...ontend/src/components/MkSchedulePostListDialog.vue 0.00% 62 Missing and 1 partial :warning:
...eue/processors/ScheduleNotePostProcessorService.ts 40.00% 60 Missing :warning:
...nd/src/server/api/endpoints/notes/schedule/list.ts 60.93% 50 Missing :warning:
.../src/server/api/endpoints/notes/schedule/delete.ts 73.13% 18 Missing :warning:
packages/frontend/src/pages/admin/roles.editor.vue 0.00% 18 Missing :warning:
packages/backend/src/queue/types.ts 0.00% 16 Missing :warning:
packages/frontend/src/os.ts 0.00% 7 Missing :warning:
packages/frontend/src/pages/admin/roles.vue 0.00% 7 Missing :warning:
...ages/backend/src/server/web/ClientServerService.ts 33.33% 2 Missing :warning:
... and 1 more
Additional details and impacted files ```diff @@ Coverage Diff @@ ## develop #483 +/- ## ============================================ + Coverage 20.23% 40.52% +20.28% ============================================ Files 787 1675 +888 Lines 117347 226219 +108872 Branches 1088 3802 +2714 ============================================ + Hits 23744 91672 +67928 - Misses 93015 133901 +40886 - Partials 588 646 +58 ```

:umbrella: View full report in Codecov by Sentry.
:loudspeaker: Have feedback on the report? Share it here.

github-actions[bot] commented 1 month ago

이 PR에 의한 api.json 차이

차이점은 여기에서 볼 수 있음 ```diff --- base +++ head @@ -57707,6 +57707,946 @@ } } }, + "/notes/schedule/create": { + "post": { + "operationId": "notes___schedule___create", + "summary": "notes/schedule/create", + "description": "No description provided.\n\n**Credential required**: *Yes* / **Permission**: *write:notes-schedule*", + "externalDocs": { + "description": "Source code", + "url": "https://github.com/kokonect-link/cherrypick/blob/develop/packages/backend/src/server/api/endpoints/notes/schedule/create.ts" + }, + "tags": [ + "notes" + ], + "security": [ + { + "bearerAuth": [] + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "visibility": { + "type": "string", + "enum": [ + "public", + "home", + "followers", + "specified" + ], + "default": "public" + }, + "visibleUserIds": { + "type": "array", + "uniqueItems": true, + "items": { + "type": "string", + "format": "misskey:id" + } + }, + "cw": { + "type": [ + "string", + "null" + ], + "minLength": 1, + "maxLength": 100 + }, + "reactionAcceptance": { + "type": [ + "string", + "null" + ], + "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 + }, + "replyId": { + "type": [ + "string", + "null" + ], + "format": "misskey:id" + }, + "renoteId": { + "type": [ + "string", + "null" + ], + "format": "misskey:id" + }, + "text": { + "type": [ + "string", + "null" + ], + "minLength": 1, + "maxLength": 5120 + }, + "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", + "null" + ], + "properties": { + "choices": { + "type": "array", + "uniqueItems": true, + "minItems": 2, + "maxItems": 10, + "items": { + "type": "string", + "minLength": 1, + "maxLength": 50 + } + }, + "multiple": { + "type": "boolean" + }, + "expiresAt": { + "type": [ + "integer", + "null" + ] + }, + "expiredAfter": { + "type": [ + "integer", + "null" + ], + "minimum": 1 + } + }, + "required": [ + "choices" + ] + }, + "event": { + "type": [ + "object", + "null" + ], + "properties": { + "title": { + "type": "string", + "minLength": 1, + "maxLength": 128 + }, + "start": { + "type": "integer" + }, + "end": { + "type": [ + "integer", + "null" + ] + }, + "metadata": { + "type": "object" + } + } + }, + "schedule": { + "type": "object", + "properties": { + "expiresAt": { + "type": "integer" + } + } + } + }, + "anyOf": [ + { + "required": [ + "text" + ] + }, + { + "required": [ + "renoteId" + ] + }, + { + "required": [ + "fileIds" + ] + }, + { + "required": [ + "mediaIds" + ] + }, + { + "required": [ + "poll" + ] + } + ], + "required": [ + "schedule" + ] + } + } + } + }, + "responses": { + "204": { + "description": "OK (without any results)" + }, + "400": { + "description": "Client error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + }, + "examples": { + "SCHEDULE_NOTE_MAX": { + "value": { + "error": { + "message": "Schedule note max.", + "code": "SCHEDULE_NOTE_MAX", + "id": "168707c3-e7da-4031-989e-f42aa3a274b2" + } + } + }, + "NO_SUCH_RENOTE_TARGET": { + "value": { + "error": { + "message": "No such renote target.", + "code": "NO_SUCH_RENOTE_TARGET", + "id": "b5c90186-4ab0-49c8-9bba-a1f76c282ba4" + } + } + }, + "CANNOT_RENOTE_TO_A_PURE_RENOTE": { + "value": { + "error": { + "message": "You can not Renote a pure Renote.", + "code": "CANNOT_RENOTE_TO_A_PURE_RENOTE", + "id": "fd4cc33e-2a37-48dd-99cc-9b806eb2031a" + } + } + }, + "CANNOT_RENOTE_DUE_TO_VISIBILITY": { + "value": { + "error": { + "message": "You can not Renote due to target visibility.", + "code": "CANNOT_RENOTE_DUE_TO_VISIBILITY", + "id": "be9529e9-fe72-4de0-ae43-0b363c4938af" + } + } + }, + "NO_SUCH_REPLY_TARGET": { + "value": { + "error": { + "message": "No such reply target.", + "code": "NO_SUCH_REPLY_TARGET", + "id": "749ee0f6-d3da-459a-bf02-282e2da4292c" + } + } + }, + "CANNOT_REPLY_TO_A_PURE_RENOTE": { + "value": { + "error": { + "message": "You can not reply to a pure Renote.", + "code": "CANNOT_REPLY_TO_A_PURE_RENOTE", + "id": "3ac74a84-8fd5-4bb0-870f-01804f82ce15" + } + } + }, + "CANNOT_CREATE_ALREADY_EXPIRED_POLL": { + "value": { + "error": { + "message": "Poll is already expired.", + "code": "CANNOT_CREATE_ALREADY_EXPIRED_POLL", + "id": "04da457d-b083-4055-9082-955525eda5a5" + } + } + }, + "CANNOT_CREATE_ALREADY_EXPIRED_SCHEDULE": { + "value": { + "error": { + "message": "Schedule is already expired.", + "code": "CANNOT_CREATE_ALREADY_EXPIRED_SCHEDULE", + "id": "8a9bfb90-fc7e-4878-a3e8-d97faaf5fb07" + } + } + }, + "NO_SUCH_CHANNEL": { + "value": { + "error": { + "message": "No such channel.", + "code": "NO_SUCH_CHANNEL", + "id": "b1653923-5453-4edc-b786-7c4f39bb0bbb" + } + } + }, + "NO_SUCH_SCHEDULE": { + "value": { + "error": { + "message": "No such schedule.", + "code": "NO_SUCH_SCHEDULE", + "id": "44dee229-8da1-4a61-856d-e3a4bbc12032" + } + } + }, + "YOU_HAVE_BEEN_BLOCKED": { + "value": { + "error": { + "message": "You have been blocked by this user.", + "code": "YOU_HAVE_BEEN_BLOCKED", + "id": "b390d7e1-8a5e-46ed-b625-06271cafd3d3" + } + } + }, + "NO_SUCH_FILE": { + "value": { + "error": { + "message": "Some files are not found.", + "code": "NO_SUCH_FILE", + "id": "b6992544-63e7-67f0-fa7f-32444b1b5306" + } + } + }, + "CANNOT_RENOTE_OUTSIDE_OF_CHANNEL": { + "value": { + "error": { + "message": "Cannot renote outside of channel.", + "code": "CANNOT_RENOTE_OUTSIDE_OF_CHANNEL", + "id": "33510210-8452-094c-6227-4a6c05d99f00" + } + } + }, + "INVALID_PARAM": { + "value": { + "error": { + "message": "Invalid param.", + "code": "INVALID_PARAM", + "id": "3d81ceae-475f-4600-b2a8-2bc116157532" + } + } + } + } + } + } + }, + "401": { + "description": "Authentication error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + }, + "examples": { + "CREDENTIAL_REQUIRED": { + "value": { + "error": { + "message": "Credential required.", + "code": "CREDENTIAL_REQUIRED", + "id": "1384574d-a912-4b81-8601-c7b1c4085df1" + } + } + } + } + } + } + }, + "403": { + "description": "Forbidden error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + }, + "examples": { + "AUTHENTICATION_FAILED": { + "value": { + "error": { + "message": "Authentication failed. Please ensure your token is correct.", + "code": "AUTHENTICATION_FAILED", + "id": "b0a7f5f8-dc2f-4171-b91f-de88ad238e14" + } + } + } + } + } + } + }, + "418": { + "description": "I'm Ai", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + }, + "examples": { + "I_AM_AI": { + "value": { + "error": { + "message": "You sent a request to Ai-chan, CherryPick's showgirl, instead of the server.", + "code": "I_AM_AI", + "id": "60c46cd1-f23a-46b1-bebe-5d2b73951a84" + } + } + } + } + } + } + }, + "429": { + "description": "To many requests", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + }, + "examples": { + "RATE_LIMIT_EXCEEDED": { + "value": { + "error": { + "message": "Rate limit exceeded. Please try again later.", + "code": "RATE_LIMIT_EXCEEDED", + "id": "d5826d14-3982-4d2e-8011-b9e9f02499ef" + } + } + } + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + }, + "examples": { + "INTERNAL_ERROR": { + "value": { + "error": { + "message": "Internal error occurred. Please contact us if the error persists.", + "code": "INTERNAL_ERROR", + "id": "5d37dbcb-891e-41ca-a3d6-e690c97775ac" + } + } + } + } + } + } + } + } + } + }, + "/notes/schedule/list": { + "post": { + "operationId": "notes___schedule___list", + "summary": "notes/schedule/list", + "description": "No description provided.\n\n**Credential required**: *Yes* / **Permission**: *read:notes-schedule*", + "externalDocs": { + "description": "Source code", + "url": "https://github.com/kokonect-link/cherrypick/blob/develop/packages/backend/src/server/api/endpoints/notes/schedule/list.ts" + }, + "tags": [ + "notes" + ], + "security": [ + { + "bearerAuth": [] + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "sinceId": { + "type": "string", + "format": "misskey:id" + }, + "untilId": { + "type": "string", + "format": "misskey:id" + }, + "limit": { + "type": "integer", + "minimum": 1, + "maximum": 100, + "default": 10 + } + } + } + } + } + }, + "responses": { + "200": { + "description": "OK (with results)", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "misskey:id" + }, + "note": { + "type": "object", + "properties": { + "createdAt": { + "type": "string" + }, + "text": { + "type": "string" + }, + "cw": { + "type": [ + "string", + "null" + ] + }, + "fileIds": { + "type": "array", + "items": { + "type": "string", + "format": "misskey:id" + } + }, + "visibility": { + "type": "string", + "enum": [ + "public", + "home", + "followers", + "specified" + ] + }, + "visibleUsers": { + "type": "array", + "items": { + "type": "object", + "$ref": "#/components/schemas/UserLite" + } + }, + "user": { + "type": "object", + "$ref": "#/components/schemas/User" + }, + "reactionAcceptance": { + "type": [ + "string", + "null" + ], + "enum": [ + null, + "likeOnly", + "likeOnlyForRemote", + "nonSensitiveOnly", + "nonSensitiveOnlyForLocalLikeOnlyForRemote" + ], + "default": null + }, + "isSchedule": { + "type": "boolean" + } + }, + "required": [ + "createdAt", + "fileIds", + "visibility", + "visibleUsers", + "user", + "reactionAcceptance", + "isSchedule" + ] + }, + "userId": { + "type": "string" + }, + "expiresAt": { + "type": "string" + } + }, + "required": [ + "id", + "note", + "userId", + "expiresAt" + ] + } + } + } + } + }, + "400": { + "description": "Client error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + }, + "examples": { + "INVALID_PARAM": { + "value": { + "error": { + "message": "Invalid param.", + "code": "INVALID_PARAM", + "id": "3d81ceae-475f-4600-b2a8-2bc116157532" + } + } + } + } + } + } + }, + "401": { + "description": "Authentication error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + }, + "examples": { + "CREDENTIAL_REQUIRED": { + "value": { + "error": { + "message": "Credential required.", + "code": "CREDENTIAL_REQUIRED", + "id": "1384574d-a912-4b81-8601-c7b1c4085df1" + } + } + } + } + } + } + }, + "403": { + "description": "Forbidden error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + }, + "examples": { + "AUTHENTICATION_FAILED": { + "value": { + "error": { + "message": "Authentication failed. Please ensure your token is correct.", + "code": "AUTHENTICATION_FAILED", + "id": "b0a7f5f8-dc2f-4171-b91f-de88ad238e14" + } + } + } + } + } + } + }, + "418": { + "description": "I'm Ai", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + }, + "examples": { + "I_AM_AI": { + "value": { + "error": { + "message": "You sent a request to Ai-chan, CherryPick's showgirl, instead of the server.", + "code": "I_AM_AI", + "id": "60c46cd1-f23a-46b1-bebe-5d2b73951a84" + } + } + } + } + } + } + }, + "429": { + "description": "To many requests", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + }, + "examples": { + "RATE_LIMIT_EXCEEDED": { + "value": { + "error": { + "message": "Rate limit exceeded. Please try again later.", + "code": "RATE_LIMIT_EXCEEDED", + "id": "d5826d14-3982-4d2e-8011-b9e9f02499ef" + } + } + } + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + }, + "examples": { + "INTERNAL_ERROR": { + "value": { + "error": { + "message": "Internal error occurred. Please contact us if the error persists.", + "code": "INTERNAL_ERROR", + "id": "5d37dbcb-891e-41ca-a3d6-e690c97775ac" + } + } + } + } + } + } + } + } + } + }, + "/notes/schedule/delete": { + "post": { + "operationId": "notes___schedule___delete", + "summary": "notes/schedule/delete", + "description": "No description provided.\n\n**Credential required**: *Yes* / **Permission**: *write:notes-schedule*", + "externalDocs": { + "description": "Source code", + "url": "https://github.com/kokonect-link/cherrypick/blob/develop/packages/backend/src/server/api/endpoints/notes/schedule/delete.ts" + }, + "tags": [ + "notes" + ], + "security": [ + { + "bearerAuth": [] + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "noteId": { + "type": "string", + "format": "misskey:id" + } + }, + "required": [ + "noteId" + ] + } + } + } + }, + "responses": { + "204": { + "description": "OK (without any results)" + }, + "400": { + "description": "Client error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + }, + "examples": { + "NO_SUCH_NOTE": { + "value": { + "error": { + "message": "No such note.", + "code": "NO_SUCH_NOTE", + "id": "a58056ba-8ba1-4323-8ebf-e0b585bc244f" + } + } + }, + "PERMISSION_DENIED": { + "value": { + "error": { + "message": "Permission denied.", + "code": "PERMISSION_DENIED", + "id": "c0da2fed-8f61-4c47-a41d-431992607b5c", + "httpStatusCode": 403 + } + } + }, + "INVALID_PARAM": { + "value": { + "error": { + "message": "Invalid param.", + "code": "INVALID_PARAM", + "id": "3d81ceae-475f-4600-b2a8-2bc116157532" + } + } + } + } + } + } + }, + "401": { + "description": "Authentication error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + }, + "examples": { + "CREDENTIAL_REQUIRED": { + "value": { + "error": { + "message": "Credential required.", + "code": "CREDENTIAL_REQUIRED", + "id": "1384574d-a912-4b81-8601-c7b1c4085df1" + } + } + } + } + } + } + }, + "403": { + "description": "Forbidden error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + }, + "examples": { + "AUTHENTICATION_FAILED": { + "value": { + "error": { + "message": "Authentication failed. Please ensure your token is correct.", + "code": "AUTHENTICATION_FAILED", + "id": "b0a7f5f8-dc2f-4171-b91f-de88ad238e14" + } + } + } + } + } + } + }, + "418": { + "description": "I'm Ai", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + }, + "examples": { + "I_AM_AI": { + "value": { + "error": { + "message": "You sent a request to Ai-chan, CherryPick's showgirl, instead of the server.", + "code": "I_AM_AI", + "id": "60c46cd1-f23a-46b1-bebe-5d2b73951a84" + } + } + } + } + } + } + }, + "429": { + "description": "To many requests", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + }, + "examples": { + "RATE_LIMIT_EXCEEDED": { + "value": { + "error": { + "message": "Rate limit exceeded. Please try again later.", + "code": "RATE_LIMIT_EXCEEDED", + "id": "d5826d14-3982-4d2e-8011-b9e9f02499ef" + } + } + } + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + }, + "examples": { + "INTERNAL_ERROR": { + "value": { + "error": { + "message": "Internal error occurred. Please contact us if the error persists.", + "code": "INTERNAL_ERROR", + "id": "5d37dbcb-891e-41ca-a3d6-e690c97775ac" + } + } + } + } + } + } + } + } + } + }, "/notes/delete": { "post": { "operationId": "notes___delete", @@ -86781,6 +87721,9 @@ "canEditNote": { "type": "boolean" }, + "scheduleNoteMax": { + "type": "integer" + }, "mutualLinkSectionLimit": { "type": "integer" }, @@ -86818,6 +87761,7 @@ "avatarDecorationLimit", "fileSizeLimit", "canEditNote", + "scheduleNoteMax", "mutualLinkSectionLimit", "mutualLinkLimit" ] ```

Get diff files from Workflow Page

kozakura913 commented 1 month ago

コミット分かれてて幾つか取り込む必要があるから後でまとめて直す

kozakura913 commented 1 month ago

Co-authoredミスってるっぽいから修正する

kozakura913 commented 1 month ago

API互換になるよう後で調整する

kozakura913 commented 1 month ago

API互換性は実装しない。Type4nyの予約投稿、notes/createでやってるっぽくてその実装すると誤って通常投稿として作成する事がありそう

kozakura913 commented 1 month ago

型汚すぎ。弄る

penginn-net commented 1 month ago

予約削除するときに確認ダイアログ

kozakura913 commented 1 month ago

予約投稿できる/できないで実装したけど何件キューに積めるか、にしたい

penginn-net commented 1 month ago
kozakura913 commented 1 month ago

「同じ時/分だと予約投稿ができる」はサーバー時間とクライアント時間の時計ずれが原因っぽい。近すぎる時間を拒否とかしか対策無さそう