From a3a99467f029d37457c102852071ae4298d2d551 Mon Sep 17 00:00:00 2001 From: かっこかり <67428053+kakkokari-gtyih@users.noreply.github.com> Date: Sat, 19 Oct 2024 17:25:11 +0900 Subject: enhance(frontend): Bull Dashboard に relationship queue を追加 (#14777) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * spec(frontend): Bull Dashboard に relationship queue を追加 (MisskeyIO#751) (cherry picked from commit a8bbccbefa67ca0f2c1ec0880da88dfc7517b6a0) * Update Changelog * Update Changelog --------- Co-authored-by: riku6460 <17585784+riku6460@users.noreply.github.com> --- packages/backend/src/server/web/ClientServerService.ts | 3 +++ 1 file changed, 3 insertions(+) (limited to 'packages/backend/src/server') diff --git a/packages/backend/src/server/web/ClientServerService.ts b/packages/backend/src/server/web/ClientServerService.ts index dd7bb7823e..c9c29e42a8 100644 --- a/packages/backend/src/server/web/ClientServerService.ts +++ b/packages/backend/src/server/web/ClientServerService.ts @@ -30,6 +30,7 @@ import type { EndedPollNotificationQueue, InboxQueue, ObjectStorageQueue, + RelationshipQueue, SystemQueue, UserWebhookDeliverQueue, SystemWebhookDeliverQueue, @@ -121,6 +122,7 @@ export class ClientServerService { @Inject('queue:deliver') public deliverQueue: DeliverQueue, @Inject('queue:inbox') public inboxQueue: InboxQueue, @Inject('queue:db') public dbQueue: DbQueue, + @Inject('queue:relationship') public relationshipQueue: RelationshipQueue, @Inject('queue:objectStorage') public objectStorageQueue: ObjectStorageQueue, @Inject('queue:userWebhookDeliver') public userWebhookDeliverQueue: UserWebhookDeliverQueue, @Inject('queue:systemWebhookDeliver') public systemWebhookDeliverQueue: SystemWebhookDeliverQueue, @@ -248,6 +250,7 @@ export class ClientServerService { this.deliverQueue, this.inboxQueue, this.dbQueue, + this.relationshipQueue, this.objectStorageQueue, this.userWebhookDeliverQueue, this.systemWebhookDeliverQueue, -- cgit v1.2.3-freya From 5c79d8db208da1fd7c5bc4900090c3d7b9512196 Mon Sep 17 00:00:00 2001 From: syuilo <4439005+syuilo@users.noreply.github.com> Date: Mon, 21 Oct 2024 12:49:29 +0900 Subject: feat: ノートの閲覧にログイン必須にする設定 (#14799) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * wip * wip * wip * Update packages/frontend/src/pages/note.vue Co-authored-by: かっこかり <67428053+kakkokari-gtyih@users.noreply.github.com> * wip * Update WebhookTestService.ts * Update privacy.vue * wip * rename * Update locales/ja-JP.yml Co-authored-by: Sayamame-beans <61457993+Sayamame-beans@users.noreply.github.com> * :art: * wip --------- Co-authored-by: かっこかり <67428053+kakkokari-gtyih@users.noreply.github.com> Co-authored-by: Sayamame-beans <61457993+Sayamame-beans@users.noreply.github.com> --- CHANGELOG.md | 2 +- locales/index.d.ts | 26 ++++++++++++++++++++++ locales/ja-JP.yml | 8 +++++++ .../1729333924409-signinRequiredForShowContents.js | 16 +++++++++++++ packages/backend/src/core/WebhookTestService.ts | 1 + .../src/core/activitypub/ApRendererService.ts | 1 + .../backend/src/core/activitypub/misc/contexts.ts | 1 + .../src/core/activitypub/models/ApPersonService.ts | 1 + packages/backend/src/core/activitypub/type.ts | 1 + .../backend/src/core/entities/NoteEntityService.ts | 4 ++++ .../backend/src/core/entities/UserEntityService.ts | 1 + packages/backend/src/models/User.ts | 5 +++++ packages/backend/src/models/json-schema/user.ts | 4 ++++ packages/backend/src/server/api/GetterService.ts | 11 +++++++++ .../backend/src/server/api/endpoints/i/update.ts | 2 ++ .../backend/src/server/api/endpoints/notes/show.ts | 12 +++++++++- .../src/server/api/endpoints/users/notes.ts | 6 +++++ .../backend/src/server/web/ClientServerService.ts | 11 +++++---- .../frontend/src/components/MkFollowButton.vue | 4 ++-- packages/frontend/src/components/MkNote.vue | 8 +++---- .../frontend/src/components/MkNoteDetailed.vue | 10 ++++----- packages/frontend/src/components/MkPoll.vue | 6 ++--- packages/frontend/src/os.ts | 18 ++++++++------- packages/frontend/src/pages/not-found.vue | 2 +- packages/frontend/src/pages/note.vue | 6 +++++ packages/frontend/src/pages/settings/privacy.vue | 19 +++++++++++++++- packages/frontend/src/scripts/please-login.ts | 14 +++++++----- packages/misskey-js/src/autogen/types.ts | 2 ++ 28 files changed, 167 insertions(+), 35 deletions(-) create mode 100644 packages/backend/migration/1729333924409-signinRequiredForShowContents.js (limited to 'packages/backend/src/server') diff --git a/CHANGELOG.md b/CHANGELOG.md index c815e65ab3..4d8c8ded3a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,7 +1,7 @@ ## Unreleased ### General -- +- Feat: コンテンツの表示にログインを必須にできるように ### Client - Enhance: Bull DashboardでRelationship Queueの状態も確認できるように diff --git a/locales/index.d.ts b/locales/index.d.ts index fb010d9353..e002540307 100644 --- a/locales/index.d.ts +++ b/locales/index.d.ts @@ -5190,6 +5190,32 @@ export interface Locale extends ILocale { * 名前に禁止されている文字列が含まれています。この名前を使用したい場合は、サーバー管理者にお問い合わせください。 */ "yourNameContainsProhibitedWordsDescription": string; + /** + * 投稿者により、表示にはログインが必要と設定されています + */ + "thisContentsAreMarkedAsSigninRequiredByAuthor": string; + /** + * ロックダウン + */ + "lockdown": string; + "_accountSettings": { + /** + * コンテンツの表示にログインを必須にする + */ + "requireSigninToViewContents": string; + /** + * あなたが作成した全てのノートなどのコンテンツを表示するのにログインを必須にします。クローラーから情報を収集されるのを防ぐ効果が期待できます。 + */ + "requireSigninToViewContentsDescription1": string; + /** + * URLプレビュー(OGP)、Webページへの埋め込み、ノートの引用に対応していないサーバーからの表示も不可になります。 + */ + "requireSigninToViewContentsDescription2": string; + /** + * リモートサーバーに連合されたコンテンツでは、これらの制限が適用されない場合があります。 + */ + "requireSigninToViewContentsDescription3": string; + }; "_abuseUserReport": { /** * 転送 diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml index c241a9e560..f3f7e5c77f 100644 --- a/locales/ja-JP.yml +++ b/locales/ja-JP.yml @@ -1293,6 +1293,14 @@ prohibitedWordsForNameOfUser: "禁止ワード(ユーザーの名前)" prohibitedWordsForNameOfUserDescription: "このリストに含まれる文字列がユーザーの名前に含まれる場合、ユーザーの名前の変更を拒否します。モデレーター権限を持つユーザーはこの制限の影響を受けません。" yourNameContainsProhibitedWords: "変更しようとした名前に禁止された文字列が含まれています" yourNameContainsProhibitedWordsDescription: "名前に禁止されている文字列が含まれています。この名前を使用したい場合は、サーバー管理者にお問い合わせください。" +thisContentsAreMarkedAsSigninRequiredByAuthor: "投稿者により、表示にはログインが必要と設定されています" +lockdown: "ロックダウン" + +_accountSettings: + requireSigninToViewContents: "コンテンツの表示にログインを必須にする" + requireSigninToViewContentsDescription1: "あなたが作成した全てのノートなどのコンテンツを表示するのにログインを必須にします。クローラーから情報を収集されるのを防ぐ効果が期待できます。" + requireSigninToViewContentsDescription2: "URLプレビュー(OGP)、Webページへの埋め込み、ノートの引用に対応していないサーバーからの表示も不可になります。" + requireSigninToViewContentsDescription3: "リモートサーバーに連合されたコンテンツでは、これらの制限が適用されない場合があります。" _abuseUserReport: forward: "転送" diff --git a/packages/backend/migration/1729333924409-signinRequiredForShowContents.js b/packages/backend/migration/1729333924409-signinRequiredForShowContents.js new file mode 100644 index 0000000000..5d4d1fcce2 --- /dev/null +++ b/packages/backend/migration/1729333924409-signinRequiredForShowContents.js @@ -0,0 +1,16 @@ +/* + * SPDX-FileCopyrightText: syuilo and misskey-project + * SPDX-License-Identifier: AGPL-3.0-only + */ + +export class SigninRequiredForShowContents1729333924409 { + name = 'SigninRequiredForShowContents1729333924409' + + async up(queryRunner) { + await queryRunner.query(`ALTER TABLE "user" ADD "requireSigninToViewContents" boolean NOT NULL DEFAULT false`); + } + + async down(queryRunner) { + await queryRunner.query(`ALTER TABLE "user" DROP COLUMN "requireSigninToViewContents"`); + } +} diff --git a/packages/backend/src/core/WebhookTestService.ts b/packages/backend/src/core/WebhookTestService.ts index 55c8a52705..254d961040 100644 --- a/packages/backend/src/core/WebhookTestService.ts +++ b/packages/backend/src/core/WebhookTestService.ts @@ -83,6 +83,7 @@ function generateDummyUser(override?: Partial): MiUser { isExplorable: true, isHibernated: false, isDeleted: false, + requireSigninToViewContents: false, emojis: [], score: 0, host: null, diff --git a/packages/backend/src/core/activitypub/ApRendererService.ts b/packages/backend/src/core/activitypub/ApRendererService.ts index fba8947f03..8235d7ba30 100644 --- a/packages/backend/src/core/activitypub/ApRendererService.ts +++ b/packages/backend/src/core/activitypub/ApRendererService.ts @@ -495,6 +495,7 @@ export class ApRendererService { summary: profile.description ? this.mfmService.toHtml(mfm.parse(profile.description)) : null, _misskey_summary: profile.description, _misskey_followedMessage: profile.followedMessage, + _misskey_requireSigninToViewContents: user.requireSigninToViewContents, icon: avatar ? this.renderImage(avatar) : null, image: banner ? this.renderImage(banner) : null, tag, diff --git a/packages/backend/src/core/activitypub/misc/contexts.ts b/packages/backend/src/core/activitypub/misc/contexts.ts index 3dd85b9b86..447f7ef3db 100644 --- a/packages/backend/src/core/activitypub/misc/contexts.ts +++ b/packages/backend/src/core/activitypub/misc/contexts.ts @@ -555,6 +555,7 @@ const extension_context_definition = { '_misskey_votes': 'misskey:_misskey_votes', '_misskey_summary': 'misskey:_misskey_summary', '_misskey_followedMessage': 'misskey:_misskey_followedMessage', + '_misskey_requireSigninToViewContents': 'misskey:_misskey_requireSigninToViewContents', 'isCat': 'misskey:isCat', // vcard vcard: 'http://www.w3.org/2006/vcard/ns#', diff --git a/packages/backend/src/core/activitypub/models/ApPersonService.ts b/packages/backend/src/core/activitypub/models/ApPersonService.ts index 73281078e5..c7915ed94f 100644 --- a/packages/backend/src/core/activitypub/models/ApPersonService.ts +++ b/packages/backend/src/core/activitypub/models/ApPersonService.ts @@ -356,6 +356,7 @@ export class ApPersonService implements OnModuleInit { tags, isBot, isCat: (person as any).isCat === true, + requireSigninToViewContents: (person as any).requireSigninToViewContents === true, emojis, })) as MiRemoteUser; diff --git a/packages/backend/src/core/activitypub/type.ts b/packages/backend/src/core/activitypub/type.ts index 154965b9d5..8a860335fa 100644 --- a/packages/backend/src/core/activitypub/type.ts +++ b/packages/backend/src/core/activitypub/type.ts @@ -14,6 +14,7 @@ export interface IObject { summary?: string; _misskey_summary?: string; _misskey_followedMessage?: string | null; + _misskey_requireSigninToViewContents?: boolean; published?: string; cc?: ApObject; to?: ApObject; diff --git a/packages/backend/src/core/entities/NoteEntityService.ts b/packages/backend/src/core/entities/NoteEntityService.ts index 3e1f094fce..62016936a2 100644 --- a/packages/backend/src/core/entities/NoteEntityService.ts +++ b/packages/backend/src/core/entities/NoteEntityService.ts @@ -149,6 +149,10 @@ export class NoteEntityService implements OnModuleInit { } } + if (packedNote.user.requireSigninToViewContents && meId == null) { + hide = true; + } + if (hide) { packedNote.visibleUserIds = undefined; packedNote.fileIds = []; diff --git a/packages/backend/src/core/entities/UserEntityService.ts b/packages/backend/src/core/entities/UserEntityService.ts index c9939adf11..747ffc780f 100644 --- a/packages/backend/src/core/entities/UserEntityService.ts +++ b/packages/backend/src/core/entities/UserEntityService.ts @@ -490,6 +490,7 @@ export class UserEntityService implements OnModuleInit { }))) : [], isBot: user.isBot, isCat: user.isCat, + requireSigninToViewContents: user.requireSigninToViewContents === false ? undefined : true, instance: user.host ? this.federatedInstanceService.federatedInstanceCache.fetch(user.host).then(instance => instance ? { name: instance.name, softwareName: instance.softwareName, diff --git a/packages/backend/src/models/User.ts b/packages/backend/src/models/User.ts index 805a1e75ae..6fcff77854 100644 --- a/packages/backend/src/models/User.ts +++ b/packages/backend/src/models/User.ts @@ -202,6 +202,11 @@ export class MiUser { }) public isHibernated: boolean; + @Column('boolean', { + default: false, + }) + public requireSigninToViewContents: boolean; + // アカウントが削除されたかどうかのフラグだが、完全に削除される際は物理削除なので実質削除されるまでの「削除が進行しているかどうか」のフラグ @Column('boolean', { default: false, diff --git a/packages/backend/src/models/json-schema/user.ts b/packages/backend/src/models/json-schema/user.ts index 9cffd680f2..817f8e9292 100644 --- a/packages/backend/src/models/json-schema/user.ts +++ b/packages/backend/src/models/json-schema/user.ts @@ -115,6 +115,10 @@ export const packedUserLiteSchema = { type: 'boolean', nullable: false, optional: true, }, + requireSigninToViewContents: { + type: 'boolean', + nullable: false, optional: true, + }, instance: { type: 'object', nullable: false, optional: true, diff --git a/packages/backend/src/server/api/GetterService.ts b/packages/backend/src/server/api/GetterService.ts index bff3ab96f3..444e6db744 100644 --- a/packages/backend/src/server/api/GetterService.ts +++ b/packages/backend/src/server/api/GetterService.ts @@ -39,6 +39,17 @@ export class GetterService { return note; } + @bindThis + public async getNoteWithUser(noteId: MiNote['id']) { + const note = await this.notesRepository.findOne({ where: { id: noteId }, relations: ['user'] }); + + if (note == null) { + throw new IdentifiableError('9725d0ce-ba28-4dde-95a7-2cbb2c15de24', 'No such note.'); + } + + return note; + } + /** * Get user for API processing */ diff --git a/packages/backend/src/server/api/endpoints/i/update.ts b/packages/backend/src/server/api/endpoints/i/update.ts index 0b35005a87..6680c96f3f 100644 --- a/packages/backend/src/server/api/endpoints/i/update.ts +++ b/packages/backend/src/server/api/endpoints/i/update.ts @@ -179,6 +179,7 @@ export const paramDef = { autoAcceptFollowed: { type: 'boolean' }, noCrawle: { type: 'boolean' }, preventAiLearning: { type: 'boolean' }, + requireSigninToViewContents: { type: 'boolean' }, isBot: { type: 'boolean' }, isCat: { type: 'boolean' }, injectFeaturedNote: { type: 'boolean' }, @@ -334,6 +335,7 @@ export default class extends Endpoint { // eslint- if (typeof ps.autoAcceptFollowed === 'boolean') profileUpdates.autoAcceptFollowed = ps.autoAcceptFollowed; if (typeof ps.noCrawle === 'boolean') profileUpdates.noCrawle = ps.noCrawle; if (typeof ps.preventAiLearning === 'boolean') profileUpdates.preventAiLearning = ps.preventAiLearning; + if (typeof ps.requireSigninToViewContents === 'boolean') updates.requireSigninToViewContents = ps.requireSigninToViewContents; if (typeof ps.isCat === 'boolean') updates.isCat = ps.isCat; if (typeof ps.injectFeaturedNote === 'boolean') profileUpdates.injectFeaturedNote = ps.injectFeaturedNote; if (typeof ps.receiveAnnouncementEmail === 'boolean') profileUpdates.receiveAnnouncementEmail = ps.receiveAnnouncementEmail; diff --git a/packages/backend/src/server/api/endpoints/notes/show.ts b/packages/backend/src/server/api/endpoints/notes/show.ts index adcda30a7d..11839bce36 100644 --- a/packages/backend/src/server/api/endpoints/notes/show.ts +++ b/packages/backend/src/server/api/endpoints/notes/show.ts @@ -26,6 +26,12 @@ export const meta = { code: 'NO_SUCH_NOTE', id: '24fcbfc6-2e37-42b6-8388-c29b3861a08d', }, + + signinRequired: { + message: 'Signin required.', + code: 'SIGNIN_REQUIRED', + id: '8e75455b-738c-471d-9f80-62693f33372e', + }, }, } as const; @@ -44,11 +50,15 @@ export default class extends Endpoint { // eslint- private getterService: GetterService, ) { super(meta, paramDef, async (ps, me) => { - const note = await this.getterService.getNote(ps.noteId).catch(err => { + const note = await this.getterService.getNoteWithUser(ps.noteId).catch(err => { if (err.id === '9725d0ce-ba28-4dde-95a7-2cbb2c15de24') throw new ApiError(meta.errors.noSuchNote); throw err; }); + if (note.user!.requireSigninToViewContents && me == null) { + throw new ApiError(meta.errors.signinRequired); + } + return await this.noteEntityService.pack(note, me, { detail: true, }); diff --git a/packages/backend/src/server/api/endpoints/users/notes.ts b/packages/backend/src/server/api/endpoints/users/notes.ts index 7fc11ba369..e9c334057e 100644 --- a/packages/backend/src/server/api/endpoints/users/notes.ts +++ b/packages/backend/src/server/api/endpoints/users/notes.ts @@ -42,6 +42,12 @@ export const meta = { code: 'BOTH_WITH_REPLIES_AND_WITH_FILES', id: '91c8cb9f-36ed-46e7-9ca2-7df96ed6e222', }, + + signinRequired: { + message: 'Signin required.', + code: 'SIGNIN_REQUIRED', + id: 'd1588a9e-4b4d-4c07-807f-16f1486577a2', + }, }, } as const; diff --git a/packages/backend/src/server/web/ClientServerService.ts b/packages/backend/src/server/web/ClientServerService.ts index c9c29e42a8..4860ef3e12 100644 --- a/packages/backend/src/server/web/ClientServerService.ts +++ b/packages/backend/src/server/web/ClientServerService.ts @@ -601,12 +601,15 @@ export class ClientServerService { fastify.get<{ Params: { note: string; } }>('/notes/:note', async (request, reply) => { vary(reply.raw, 'Accept'); - const note = await this.notesRepository.findOneBy({ - id: request.params.note, - visibility: In(['public', 'home']), + const note = await this.notesRepository.findOne({ + where: { + id: request.params.note, + visibility: In(['public', 'home']), + }, + relations: ['user'], }); - if (note) { + if (note && !note.user!.requireSigninToViewContents) { const _note = await this.noteEntityService.pack(note); const profile = await this.userProfilesRepository.findOneByOrFail({ userId: note.userId }); reply.header('Cache-Control', 'public, max-age=15'); diff --git a/packages/frontend/src/components/MkFollowButton.vue b/packages/frontend/src/components/MkFollowButton.vue index ccea7cd453..cc07175907 100644 --- a/packages/frontend/src/components/MkFollowButton.vue +++ b/packages/frontend/src/components/MkFollowButton.vue @@ -37,13 +37,13 @@ SPDX-License-Identifier: AGPL-3.0-only + + diff --git a/packages/frontend/src/pages/avatar-decorations.vue b/packages/frontend/src/pages/avatar-decorations.vue index b97e7c0eea..a5cafb1678 100644 --- a/packages/frontend/src/pages/avatar-decorations.vue +++ b/packages/frontend/src/pages/avatar-decorations.vue @@ -5,92 +5,38 @@ SPDX-License-Identifier: AGPL-3.0-only diff --git a/packages/frontend/src/pages/settings/avatar-decoration.decoration.vue b/packages/frontend/src/pages/settings/avatar-decoration.decoration.vue index f72a0b9383..3c9914b4e2 100644 --- a/packages/frontend/src/pages/settings/avatar-decoration.decoration.vue +++ b/packages/frontend/src/pages/settings/avatar-decoration.decoration.vue @@ -10,12 +10,12 @@ SPDX-License-Identifier: AGPL-3.0-only >
{{ decoration.name }}
- + diff --git a/packages/frontend/src/pages/settings/avatar-decoration.dialog.vue b/packages/frontend/src/pages/settings/avatar-decoration.dialog.vue index 853e536ea3..aa899ac649 100644 --- a/packages/frontend/src/pages/settings/avatar-decoration.dialog.vue +++ b/packages/frontend/src/pages/settings/avatar-decoration.dialog.vue @@ -38,7 +38,7 @@ SPDX-License-Identifier: AGPL-3.0-only
{{ i18n.ts.update }} {{ i18n.ts.detach }} - {{ i18n.ts.attach }} + {{ i18n.ts.attach }}
@@ -61,6 +61,7 @@ const props = defineProps<{ id: string; url: string; name: string; + roleIdsThatCanBeUsedThisDecoration: string[]; }; }>(); @@ -83,6 +84,7 @@ const emit = defineEmits<{ const dialog = shallowRef>(); const exceeded = computed(() => ($i.policies.avatarDecorationLimit - $i.avatarDecorations.length) <= 0); +const locked = computed(() => props.decoration.roleIdsThatCanBeUsedThisDecoration.length > 0 && !$i.roles.some(r => props.decoration.roleIdsThatCanBeUsedThisDecoration.includes(r.id))); const angle = ref((props.usingIndex != null ? $i.avatarDecorations[props.usingIndex].angle : null) ?? 0); const flipH = ref((props.usingIndex != null ? $i.avatarDecorations[props.usingIndex].flipH : null) ?? false); const offsetX = ref((props.usingIndex != null ? $i.avatarDecorations[props.usingIndex].offsetX : null) ?? 0); diff --git a/packages/misskey-js/etc/misskey-js.api.md b/packages/misskey-js/etc/misskey-js.api.md index 61de8b8c7e..061b533b72 100644 --- a/packages/misskey-js/etc/misskey-js.api.md +++ b/packages/misskey-js/etc/misskey-js.api.md @@ -121,6 +121,9 @@ type AdminAnnouncementsUpdateRequest = operations['admin___announcements___updat // @public (undocumented) type AdminAvatarDecorationsCreateRequest = operations['admin___avatar-decorations___create']['requestBody']['content']['application/json']; +// @public (undocumented) +type AdminAvatarDecorationsCreateResponse = operations['admin___avatar-decorations___create']['responses']['200']['content']['application/json']; + // @public (undocumented) type AdminAvatarDecorationsDeleteRequest = operations['admin___avatar-decorations___delete']['requestBody']['content']['application/json']; @@ -1253,6 +1256,7 @@ declare namespace entities { AdminAnnouncementsListResponse, AdminAnnouncementsUpdateRequest, AdminAvatarDecorationsCreateRequest, + AdminAvatarDecorationsCreateResponse, AdminAvatarDecorationsDeleteRequest, AdminAvatarDecorationsListRequest, AdminAvatarDecorationsListResponse, diff --git a/packages/misskey-js/src/autogen/endpoint.ts b/packages/misskey-js/src/autogen/endpoint.ts index d0367d8496..5e6bc0a99c 100644 --- a/packages/misskey-js/src/autogen/endpoint.ts +++ b/packages/misskey-js/src/autogen/endpoint.ts @@ -31,6 +31,7 @@ import type { AdminAnnouncementsListResponse, AdminAnnouncementsUpdateRequest, AdminAvatarDecorationsCreateRequest, + AdminAvatarDecorationsCreateResponse, AdminAvatarDecorationsDeleteRequest, AdminAvatarDecorationsListRequest, AdminAvatarDecorationsListResponse, @@ -597,7 +598,7 @@ export type Endpoints = { 'admin/announcements/delete': { req: AdminAnnouncementsDeleteRequest; res: EmptyResponse }; 'admin/announcements/list': { req: AdminAnnouncementsListRequest; res: AdminAnnouncementsListResponse }; 'admin/announcements/update': { req: AdminAnnouncementsUpdateRequest; res: EmptyResponse }; - 'admin/avatar-decorations/create': { req: AdminAvatarDecorationsCreateRequest; res: EmptyResponse }; + 'admin/avatar-decorations/create': { req: AdminAvatarDecorationsCreateRequest; res: AdminAvatarDecorationsCreateResponse }; 'admin/avatar-decorations/delete': { req: AdminAvatarDecorationsDeleteRequest; res: EmptyResponse }; 'admin/avatar-decorations/list': { req: AdminAvatarDecorationsListRequest; res: AdminAvatarDecorationsListResponse }; 'admin/avatar-decorations/update': { req: AdminAvatarDecorationsUpdateRequest; res: EmptyResponse }; diff --git a/packages/misskey-js/src/autogen/entities.ts b/packages/misskey-js/src/autogen/entities.ts index ced87c4c7e..f3ddf64481 100644 --- a/packages/misskey-js/src/autogen/entities.ts +++ b/packages/misskey-js/src/autogen/entities.ts @@ -34,6 +34,7 @@ export type AdminAnnouncementsListRequest = operations['admin___announcements___ export type AdminAnnouncementsListResponse = operations['admin___announcements___list']['responses']['200']['content']['application/json']; export type AdminAnnouncementsUpdateRequest = operations['admin___announcements___update']['requestBody']['content']['application/json']; export type AdminAvatarDecorationsCreateRequest = operations['admin___avatar-decorations___create']['requestBody']['content']['application/json']; +export type AdminAvatarDecorationsCreateResponse = operations['admin___avatar-decorations___create']['responses']['200']['content']['application/json']; export type AdminAvatarDecorationsDeleteRequest = operations['admin___avatar-decorations___delete']['requestBody']['content']['application/json']; export type AdminAvatarDecorationsListRequest = operations['admin___avatar-decorations___list']['requestBody']['content']['application/json']; export type AdminAvatarDecorationsListResponse = operations['admin___avatar-decorations___list']['responses']['200']['content']['application/json']; diff --git a/packages/misskey-js/src/autogen/types.ts b/packages/misskey-js/src/autogen/types.ts index 560960f018..a5333d4f93 100644 --- a/packages/misskey-js/src/autogen/types.ts +++ b/packages/misskey-js/src/autogen/types.ts @@ -6324,9 +6324,22 @@ export type operations = { }; }; responses: { - /** @description OK (without any results) */ - 204: { - content: never; + /** @description OK (with results) */ + 200: { + content: { + 'application/json': { + /** Format: id */ + id: string; + /** Format: date-time */ + createdAt: string; + /** Format: date-time */ + updatedAt: string | null; + name: string; + description: string; + url: string; + roleIdsThatCanBeUsedThisDecoration: string[]; + }; + }; }; /** @description Client error */ 400: { -- cgit v1.2.3-freya From b1c82213a320dd7c83f8b2e742406646ef18ff1c Mon Sep 17 00:00:00 2001 From: かっこかり <67428053+kakkokari-gtyih@users.noreply.github.com> Date: Wed, 6 Nov 2024 22:01:21 +0900 Subject: fix(backend): FTT無効時にユーザーリストタイムラインが使用できない問題を修正 (#14878) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix: return getfromdb when FanoutTimeline is not enabled * Update Changelog * fix --------- Co-authored-by: Lhc_fl --- CHANGELOG.md | 2 ++ packages/backend/src/server/api/endpoints/notes/user-list-timeline.ts | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) (limited to 'packages/backend/src/server') diff --git a/CHANGELOG.md b/CHANGELOG.md index 0309f338f1..1740d0171e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -35,6 +35,8 @@ (Cherry-picked from https://activitypub.software/TransFem-org/Sharkey/-/merge_requests/706) - Fix: 連合への配信時に、acctの大小文字が区別されてしまい正しくメンションが処理されないことがある問題を修正 (Cherry-picked from https://activitypub.software/TransFem-org/Sharkey/-/merge_requests/711) +- Fix: FTT無効時にユーザーリストタイムラインが使用できない問題を修正 + (Cherry-picked from https://activitypub.software/TransFem-org/Sharkey/-/merge_requests/709) ### Misskey.js - Fix: Stream初期化時、別途WebSocketを指定する場合の型定義を修正 diff --git a/packages/backend/src/server/api/endpoints/notes/user-list-timeline.ts b/packages/backend/src/server/api/endpoints/notes/user-list-timeline.ts index 6c7185c9eb..87f9b322a6 100644 --- a/packages/backend/src/server/api/endpoints/notes/user-list-timeline.ts +++ b/packages/backend/src/server/api/endpoints/notes/user-list-timeline.ts @@ -112,7 +112,7 @@ export default class extends Endpoint { // eslint- this.activeUsersChart.read(me); - await this.noteEntityService.packMany(timeline, me); + return await this.noteEntityService.packMany(timeline, me); } const timeline = await this.fanoutTimelineEndpointService.timeline({ -- cgit v1.2.3-freya From bca690f256721815fb1c918c1f66a2172f4fcf40 Mon Sep 17 00:00:00 2001 From: 4ster1sk <146138447+4ster1sk@users.noreply.github.com> Date: Thu, 7 Nov 2024 15:10:10 +0900 Subject: fix(backend): フォロワーへのメッセージの絵文字をemojisに含めるように (#14904) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/backend/src/server/api/endpoints/i/update.ts | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'packages/backend/src/server') diff --git a/packages/backend/src/server/api/endpoints/i/update.ts b/packages/backend/src/server/api/endpoints/i/update.ts index 2183beac7c..d91e2fef4b 100644 --- a/packages/backend/src/server/api/endpoints/i/update.ts +++ b/packages/backend/src/server/api/endpoints/i/update.ts @@ -465,6 +465,7 @@ export default class extends Endpoint { // eslint- const newName = updates.name === undefined ? user.name : updates.name; const newDescription = profileUpdates.description === undefined ? profile.description : profileUpdates.description; const newFields = profileUpdates.fields === undefined ? profile.fields : profileUpdates.fields; + const newFollowedMessage = profileUpdates.description === undefined ? profile.followedMessage : profileUpdates.followedMessage; if (newName != null) { let hasProhibitedWords = false; @@ -494,6 +495,11 @@ export default class extends Endpoint { // eslint- ]); } + if (newFollowedMessage != null) { + const tokens = mfm.parse(newFollowedMessage); + emojis = emojis.concat(extractCustomEmojisFromMfm(tokens)); + } + updates.emojis = emojis; updates.tags = tags; -- cgit v1.2.3-freya From 794cb9ffe205b1e2ca838978f80d2d6a35f17f77 Mon Sep 17 00:00:00 2001 From: 4ster1sk <146138447+4ster1sk@users.noreply.github.com> Date: Thu, 7 Nov 2024 17:16:51 +0900 Subject: fix(backend): followedMessageではなくdescriptionになっていたのを修正 (#14908) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/backend/src/server/api/endpoints/i/update.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'packages/backend/src/server') diff --git a/packages/backend/src/server/api/endpoints/i/update.ts b/packages/backend/src/server/api/endpoints/i/update.ts index d91e2fef4b..d3eeb75b27 100644 --- a/packages/backend/src/server/api/endpoints/i/update.ts +++ b/packages/backend/src/server/api/endpoints/i/update.ts @@ -465,7 +465,7 @@ export default class extends Endpoint { // eslint- const newName = updates.name === undefined ? user.name : updates.name; const newDescription = profileUpdates.description === undefined ? profile.description : profileUpdates.description; const newFields = profileUpdates.fields === undefined ? profile.fields : profileUpdates.fields; - const newFollowedMessage = profileUpdates.description === undefined ? profile.followedMessage : profileUpdates.followedMessage; + const newFollowedMessage = profileUpdates.followedMessage === undefined ? profile.followedMessage : profileUpdates.followedMessage; if (newName != null) { let hasProhibitedWords = false; -- cgit v1.2.3-freya From e75b62f3f5f58e39baf949d0d601c8826f43dba3 Mon Sep 17 00:00:00 2001 From: かっこかり <67428053+kakkokari-gtyih@users.noreply.github.com> Date: Sat, 9 Nov 2024 10:53:09 +0900 Subject: enhance(frontend): 個別お知らせページではmetaタグを出力するように (#14902) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * enhance(frontend): 個別お知らせページではmetaタグを出力するように * Update Changelog --- CHANGELOG.md | 3 +- .../backend/src/server/web/ClientServerService.ts | 37 +++++++++++++++++++++- .../backend/src/server/web/views/announcement.pug | 21 ++++++++++++ packages/backend/src/server/web/views/base.pug | 3 +- packages/frontend/src/pages/announcement.vue | 2 +- 5 files changed, 62 insertions(+), 4 deletions(-) create mode 100644 packages/backend/src/server/web/views/announcement.pug (limited to 'packages/backend/src/server') diff --git a/CHANGELOG.md b/CHANGELOG.md index 464bdd677f..cddd9f1ad7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,7 +15,8 @@ - どのアカウントで認証しようとしているのかがわかるように - 認証するアカウントを切り替えられるように - Enhance: Self-XSS防止用の警告を追加 -- Enhance: カタルーニャ語 (ca-ES) に対応 +- Enhance: カタルーニャ語 (ca-ES) に対応 +- Enhance: 個別お知らせページではMetaタグを出力するように - Fix: 通知の範囲指定の設定項目が必要ない通知設定でも範囲指定の設定がでている問題を修正 - Fix: Turnstileが失敗・期限切れした際にも成功扱いとなってしまう問題を修正 (Cherry-picked from https://github.com/MisskeyIO/misskey/pull/768) diff --git a/packages/backend/src/server/web/ClientServerService.ts b/packages/backend/src/server/web/ClientServerService.ts index 4860ef3e12..5ebec4ffd0 100644 --- a/packages/backend/src/server/web/ClientServerService.ts +++ b/packages/backend/src/server/web/ClientServerService.ts @@ -42,13 +42,26 @@ import { MetaEntityService } from '@/core/entities/MetaEntityService.js'; import { GalleryPostEntityService } from '@/core/entities/GalleryPostEntityService.js'; import { ClipEntityService } from '@/core/entities/ClipEntityService.js'; import { ChannelEntityService } from '@/core/entities/ChannelEntityService.js'; -import type { ChannelsRepository, ClipsRepository, FlashsRepository, GalleryPostsRepository, MiMeta, NotesRepository, PagesRepository, ReversiGamesRepository, UserProfilesRepository, UsersRepository } from '@/models/_.js'; +import type { + AnnouncementsRepository, + ChannelsRepository, + ClipsRepository, + FlashsRepository, + GalleryPostsRepository, + MiMeta, + NotesRepository, + PagesRepository, + ReversiGamesRepository, + UserProfilesRepository, + UsersRepository, +} from '@/models/_.js'; import type Logger from '@/logger.js'; import { handleRequestRedirectToOmitSearch } from '@/misc/fastify-hook-handlers.js'; import { bindThis } from '@/decorators.js'; import { FlashEntityService } from '@/core/entities/FlashEntityService.js'; import { RoleService } from '@/core/RoleService.js'; import { ReversiGameEntityService } from '@/core/entities/ReversiGameEntityService.js'; +import { AnnouncementEntityService } from '@/core/entities/AnnouncementEntityService.js'; import { FeedService } from './FeedService.js'; import { UrlPreviewService } from './UrlPreviewService.js'; import { ClientLoggerService } from './ClientLoggerService.js'; @@ -103,6 +116,9 @@ export class ClientServerService { @Inject(DI.reversiGamesRepository) private reversiGamesRepository: ReversiGamesRepository, + @Inject(DI.announcementsRepository) + private announcementsRepository: AnnouncementsRepository, + private flashEntityService: FlashEntityService, private userEntityService: UserEntityService, private noteEntityService: NoteEntityService, @@ -112,6 +128,7 @@ export class ClientServerService { private clipEntityService: ClipEntityService, private channelEntityService: ChannelEntityService, private reversiGameEntityService: ReversiGameEntityService, + private announcementEntityService: AnnouncementEntityService, private urlPreviewService: UrlPreviewService, private feedService: FeedService, private roleService: RoleService, @@ -776,6 +793,24 @@ export class ClientServerService { return await renderBase(reply); } }); + + // 個別お知らせページ + fastify.get<{ Params: { announcementId: string; } }>('/announcements/:announcementId', async (request, reply) => { + const announcement = await this.announcementsRepository.findOneBy({ + id: request.params.announcementId, + }); + + if (announcement) { + const _announcement = await this.announcementEntityService.pack(announcement); + reply.header('Cache-Control', 'public, max-age=3600'); + return await reply.view('announcement', { + announcement: _announcement, + ...await this.generateCommonPugData(this.meta), + }); + } else { + return await renderBase(reply); + } + }); //#endregion //#region noindex pages diff --git a/packages/backend/src/server/web/views/announcement.pug b/packages/backend/src/server/web/views/announcement.pug new file mode 100644 index 0000000000..7a4052e8a4 --- /dev/null +++ b/packages/backend/src/server/web/views/announcement.pug @@ -0,0 +1,21 @@ +extends ./base + +block vars + - const title = announcement.title; + - const description = announcement.text.length > 100 ? announcement.text.slice(0, 100) + '…' : announcement.text; + - const url = `${config.url}/announcements/${announcement.id}`; + +block title + = `${title} | ${instanceName}` + +block desc + meta(name='description' content=description) + +block og + meta(property='og:type' content='article') + meta(property='og:title' content= title) + meta(property='og:description' content= description) + meta(property='og:url' content= url) + if announcement.imageUrl + meta(property='og:image' content=announcement.imageUrl) + meta(property='twitter:card' content='summary_large_image') diff --git a/packages/backend/src/server/web/views/base.pug b/packages/backend/src/server/web/views/base.pug index 88714b2556..280a5923c2 100644 --- a/packages/backend/src/server/web/views/base.pug +++ b/packages/backend/src/server/web/views/base.pug @@ -2,6 +2,7 @@ block vars block loadClientEntry - const entry = config.frontendEntry; + - const baseUrl = config.url; doctype html @@ -32,7 +33,7 @@ html link(rel='icon' href= icon || '/favicon.ico') link(rel='apple-touch-icon' href= appleTouchIcon || '/apple-touch-icon.png') link(rel='manifest' href='/manifest.json') - link(rel='search' type='application/opensearchdescription+xml' title=(title || "Misskey") href=`${url}/opensearch.xml`) + link(rel='search' type='application/opensearchdescription+xml' title=(title || "Misskey") href=`${baseUrl}/opensearch.xml`) link(rel='prefetch' href=serverErrorImageUrl) link(rel='prefetch' href=infoImageUrl) link(rel='prefetch' href=notFoundImageUrl) diff --git a/packages/frontend/src/pages/announcement.vue b/packages/frontend/src/pages/announcement.vue index 01c29cf02d..56c10fb292 100644 --- a/packages/frontend/src/pages/announcement.vue +++ b/packages/frontend/src/pages/announcement.vue @@ -103,7 +103,7 @@ const headerActions = computed(() => []); const headerTabs = computed(() => []); definePageMetadata(() => ({ - title: announcement.value ? `${i18n.ts.announcements}: ${announcement.value.title}` : i18n.ts.announcements, + title: announcement.value ? announcement.value.title : i18n.ts.announcements, icon: 'ti ti-speakerphone', })); -- cgit v1.2.3-freya From a4c5ce1413078c9b98816644bebfcc0a24e94a85 Mon Sep 17 00:00:00 2001 From: momoirodouhu Date: Sat, 9 Nov 2024 10:54:44 +0900 Subject: enhance(backend) : リモートユーザーの照会をオリジナルにリダイレクトするように (#12892) (#14897) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * enhance(backend) : リモートユーザーの照会をオリジナルにリダイレクトするように (#12892) * オリジンリダイレクトのテストをtodoとして追加。 e2eテストにリモートユーザー考慮のテストがなさそうなので。 次のコマンドで動くことは確認済みです。 curl "http://localhost:3000/@foo@bar" -H "accept: application/activity+json" -L * Acctのパースを既存のパーサーでするように修正 * lint --- CHANGELOG.md | 1 + .../backend/src/server/ActivityPubServerService.ts | 20 ++++++++++++++++---- packages/backend/test/e2e/fetch-resource.ts | 2 ++ 3 files changed, 19 insertions(+), 4 deletions(-) (limited to 'packages/backend/src/server') diff --git a/CHANGELOG.md b/CHANGELOG.md index cddd9f1ad7..b986273d0d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -39,6 +39,7 @@ (Cherry-picked from https://activitypub.software/TransFem-org/Sharkey/-/merge_requests/711) - Fix: FTT無効時にユーザーリストタイムラインが使用できない問題を修正 (Cherry-picked from https://activitypub.software/TransFem-org/Sharkey/-/merge_requests/709) +- Enhance: リモートユーザーの照会をオリジナルにリダイレクトするように ### Misskey.js - Fix: Stream初期化時、別途WebSocketを指定する場合の型定義を修正 diff --git a/packages/backend/src/server/ActivityPubServerService.ts b/packages/backend/src/server/ActivityPubServerService.ts index 3255d64621..ba2342b630 100644 --- a/packages/backend/src/server/ActivityPubServerService.ts +++ b/packages/backend/src/server/ActivityPubServerService.ts @@ -29,6 +29,7 @@ import { UserEntityService } from '@/core/entities/UserEntityService.js'; import { bindThis } from '@/decorators.js'; import { IActivity } from '@/core/activitypub/type.js'; import { isQuote, isRenote } from '@/misc/is-renote.js'; +import * as Acct from '@/misc/acct.js'; import type { FastifyInstance, FastifyRequest, FastifyReply, FastifyPluginOptions, FastifyBodyParser } from 'fastify'; import type { FindOptionsWhere } from 'typeorm'; @@ -486,6 +487,16 @@ export class ActivityPubServerService { return; } + // リモートだったらリダイレクト + if (user.host != null) { + if (user.uri == null || this.utilityService.isSelfHost(user.host)) { + reply.code(500); + return; + } + reply.redirect(user.uri, 301); + return; + } + reply.header('Cache-Control', 'public, max-age=180'); this.setResponseType(request, reply); return (this.apRendererService.addContext(await this.apRendererService.renderPerson(user as MiLocalUser))); @@ -654,19 +665,20 @@ export class ActivityPubServerService { const user = await this.usersRepository.findOneBy({ id: userId, - host: IsNull(), isSuspended: false, }); return await this.userInfo(request, reply, user); }); - fastify.get<{ Params: { user: string; } }>('/@:user', { constraints: { apOrHtml: 'ap' } }, async (request, reply) => { + fastify.get<{ Params: { acct: string; } }>('/@:acct', { constraints: { apOrHtml: 'ap' } }, async (request, reply) => { vary(reply.raw, 'Accept'); + const acct = Acct.parse(request.params.acct); + const user = await this.usersRepository.findOneBy({ - usernameLower: request.params.user.toLowerCase(), - host: IsNull(), + usernameLower: acct.username, + host: acct.host ?? IsNull(), isSuspended: false, }); diff --git a/packages/backend/test/e2e/fetch-resource.ts b/packages/backend/test/e2e/fetch-resource.ts index 7efd688ec2..8ea4cb9800 100644 --- a/packages/backend/test/e2e/fetch-resource.ts +++ b/packages/backend/test/e2e/fetch-resource.ts @@ -230,6 +230,7 @@ describe('Webリソース', () => { path: path('xxxxxxxxxx'), type: HTML, })); + test.todo('HTMLとしてGETできる。(リモートユーザーでもリダイレクトせず)'); }); describe.each([ @@ -249,6 +250,7 @@ describe('Webリソース', () => { path: path('xxxxxxxxxx'), accept, })); + test.todo('はオリジナルにリダイレクトされる。(リモートユーザー)'); }); }); -- cgit v1.2.3-freya From c0d168260482caa974e3fc9e084b121fc32e8ec4 Mon Sep 17 00:00:00 2001 From: かっこかり <67428053+kakkokari-gtyih@users.noreply.github.com> Date: Fri, 15 Nov 2024 17:30:54 +0900 Subject: feat: 送信したフォローリクエストを確認できるように (#14856) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * FEAT: Allow users to view pending follow requests they sent This commit implements the `following/requests/sent` interface firstly implemented on Firefish, and provides a UI interface to view the pending follow requests users sent. * ux: should not show follow requests tab when have no pending sent follow req * fix default followreq tab * fix default followreq tab * restore missing hasPendingReceivedFollowRequest in navbar * refactor * use tabler icons * tweak design * Revert "ux: should not show follow requests tab when have no pending sent follow req" This reverts commit e580b92c37f27c2849c6d27e22ca4c47086081bb. * Update Changelog * Update Changelog * change tab titles --------- Co-authored-by: Lhc_fl Co-authored-by: Hazelnoot --- CHANGELOG.md | 2 + locales/index.d.ts | 10 ++ locales/ja-JP.yml | 4 + packages/backend/src/server/api/EndpointsModule.ts | 3 + packages/backend/src/server/api/endpoints.ts | 2 + .../api/endpoints/following/requests/sent.ts | 77 +++++++++++++++ .../frontend/src/components/MkFollowButton.vue | 10 +- packages/frontend/src/navbar.ts | 1 - packages/frontend/src/pages/follow-requests.vue | 105 ++++++++++++++------- packages/misskey-js/etc/misskey-js.api.md | 8 ++ packages/misskey-js/src/autogen/apiClientJSDoc.ts | 11 +++ packages/misskey-js/src/autogen/endpoint.ts | 3 + packages/misskey-js/src/autogen/entities.ts | 2 + packages/misskey-js/src/autogen/types.ts | 72 ++++++++++++++ 14 files changed, 272 insertions(+), 38 deletions(-) create mode 100644 packages/backend/src/server/api/endpoints/following/requests/sent.ts (limited to 'packages/backend/src/server') diff --git a/CHANGELOG.md b/CHANGELOG.md index fcbfed5900..232d52d7e1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -24,6 +24,8 @@ - Enhance: カタルーニャ語 (ca-ES) に対応 - Enhance: 個別お知らせページではMetaタグを出力するように - Enhance: ノート詳細画面にロールのバッジを表示 +- Enhance: 過去に送信したフォローリクエストを確認できるように + (Based on https://activitypub.software/TransFem-org/Sharkey/-/merge_requests/663) - Fix: 通知の範囲指定の設定項目が必要ない通知設定でも範囲指定の設定がでている問題を修正 - Fix: Turnstileが失敗・期限切れした際にも成功扱いとなってしまう問題を修正 (Cherry-picked from https://github.com/MisskeyIO/misskey/pull/768) diff --git a/locales/index.d.ts b/locales/index.d.ts index 440f24ac84..18fbfd15f0 100644 --- a/locales/index.d.ts +++ b/locales/index.d.ts @@ -10579,6 +10579,16 @@ export interface Locale extends ILocale { */ "description3": ParameterizedString<"link">; }; + "_followRequest": { + /** + * 受け取った申請 + */ + "recieved": string; + /** + * 送った申請 + */ + "sent": string; + }; } declare const locales: { [lang: string]: Locale; diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml index 5d8e1a5e72..439ae708c5 100644 --- a/locales/ja-JP.yml +++ b/locales/ja-JP.yml @@ -2819,3 +2819,7 @@ _selfXssPrevention: description1: "ここに何かを貼り付けると、悪意のあるユーザーにアカウントを乗っ取られたり、個人情報を盗まれたりする可能性があります。" description2: "貼り付けようとしているものが何なのかを正確に理解していない場合は、%c今すぐ作業を中止してこのウィンドウを閉じてください。" description3: "詳しくはこちらをご確認ください。 {link}" + +_followRequest: + recieved: "受け取った申請" + sent: "送った申請" diff --git a/packages/backend/src/server/api/EndpointsModule.ts b/packages/backend/src/server/api/EndpointsModule.ts index 3557fa40a5..5bb194313d 100644 --- a/packages/backend/src/server/api/EndpointsModule.ts +++ b/packages/backend/src/server/api/EndpointsModule.ts @@ -187,6 +187,7 @@ import * as ep___following_invalidate from './endpoints/following/invalidate.js' import * as ep___following_requests_accept from './endpoints/following/requests/accept.js'; import * as ep___following_requests_cancel from './endpoints/following/requests/cancel.js'; import * as ep___following_requests_list from './endpoints/following/requests/list.js'; +import * as ep___following_requests_sent from './endpoints/following/requests/sent.js'; import * as ep___following_requests_reject from './endpoints/following/requests/reject.js'; import * as ep___gallery_featured from './endpoints/gallery/featured.js'; import * as ep___gallery_popular from './endpoints/gallery/popular.js'; @@ -574,6 +575,7 @@ const $following_invalidate: Provider = { provide: 'ep:following/invalidate', us const $following_requests_accept: Provider = { provide: 'ep:following/requests/accept', useClass: ep___following_requests_accept.default }; const $following_requests_cancel: Provider = { provide: 'ep:following/requests/cancel', useClass: ep___following_requests_cancel.default }; const $following_requests_list: Provider = { provide: 'ep:following/requests/list', useClass: ep___following_requests_list.default }; +const $following_requests_sent: Provider = { provide: 'ep:following/requests/sent', useClass: ep___following_requests_sent.default }; const $following_requests_reject: Provider = { provide: 'ep:following/requests/reject', useClass: ep___following_requests_reject.default }; const $gallery_featured: Provider = { provide: 'ep:gallery/featured', useClass: ep___gallery_featured.default }; const $gallery_popular: Provider = { provide: 'ep:gallery/popular', useClass: ep___gallery_popular.default }; @@ -965,6 +967,7 @@ const $reversi_verify: Provider = { provide: 'ep:reversi/verify', useClass: ep__ $following_requests_accept, $following_requests_cancel, $following_requests_list, + $following_requests_sent, $following_requests_reject, $gallery_featured, $gallery_popular, diff --git a/packages/backend/src/server/api/endpoints.ts b/packages/backend/src/server/api/endpoints.ts index 49b07d6ced..15809b2678 100644 --- a/packages/backend/src/server/api/endpoints.ts +++ b/packages/backend/src/server/api/endpoints.ts @@ -193,6 +193,7 @@ import * as ep___following_invalidate from './endpoints/following/invalidate.js' import * as ep___following_requests_accept from './endpoints/following/requests/accept.js'; import * as ep___following_requests_cancel from './endpoints/following/requests/cancel.js'; import * as ep___following_requests_list from './endpoints/following/requests/list.js'; +import * as ep___following_requests_sent from './endpoints/following/requests/sent.js'; import * as ep___following_requests_reject from './endpoints/following/requests/reject.js'; import * as ep___gallery_featured from './endpoints/gallery/featured.js'; import * as ep___gallery_popular from './endpoints/gallery/popular.js'; @@ -578,6 +579,7 @@ const eps = [ ['following/requests/accept', ep___following_requests_accept], ['following/requests/cancel', ep___following_requests_cancel], ['following/requests/list', ep___following_requests_list], + ['following/requests/sent', ep___following_requests_sent], ['following/requests/reject', ep___following_requests_reject], ['gallery/featured', ep___gallery_featured], ['gallery/popular', ep___gallery_popular], diff --git a/packages/backend/src/server/api/endpoints/following/requests/sent.ts b/packages/backend/src/server/api/endpoints/following/requests/sent.ts new file mode 100644 index 0000000000..6325f01bb8 --- /dev/null +++ b/packages/backend/src/server/api/endpoints/following/requests/sent.ts @@ -0,0 +1,77 @@ +/* + * SPDX-FileCopyrightText: syuilo and misskey-project + * SPDX-License-Identifier: AGPL-3.0-only + */ + +import { Inject, Injectable } from '@nestjs/common'; +import { Endpoint } from '@/server/api/endpoint-base.js'; +import { QueryService } from '@/core/QueryService.js'; +import type { FollowRequestsRepository } from '@/models/_.js'; +import { FollowRequestEntityService } from '@/core/entities/FollowRequestEntityService.js'; +import { DI } from '@/di-symbols.js'; + +export const meta = { + tags: ['following', 'account'], + + requireCredential: true, + + kind: 'read:following', + + res: { + type: 'array', + optional: false, nullable: false, + items: { + type: 'object', + optional: false, nullable: false, + properties: { + id: { + type: 'string', + optional: false, nullable: false, + format: 'id', + }, + follower: { + type: 'object', + optional: false, nullable: false, + ref: 'UserLite', + }, + followee: { + type: 'object', + optional: false, nullable: false, + ref: 'UserLite', + }, + }, + }, + }, +} as const; + +export const paramDef = { + type: 'object', + properties: { + sinceId: { type: 'string', format: 'misskey:id' }, + untilId: { type: 'string', format: 'misskey:id' }, + limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 }, + }, + required: [], +} as const; + +@Injectable() +export default class extends Endpoint { // eslint-disable-line import/no-default-export + constructor( + @Inject(DI.followRequestsRepository) + private followRequestsRepository: FollowRequestsRepository, + + private followRequestEntityService: FollowRequestEntityService, + private queryService: QueryService, + ) { + super(meta, paramDef, async (ps, me) => { + const query = this.queryService.makePaginationQuery(this.followRequestsRepository.createQueryBuilder('request'), ps.sinceId, ps.untilId) + .andWhere('request.followerId = :meId', { meId: me.id }); + + const requests = await query + .limit(ps.limit) + .getMany(); + + return await this.followRequestEntityService.packMany(requests, me); + }); + } +} diff --git a/packages/frontend/src/components/MkFollowButton.vue b/packages/frontend/src/components/MkFollowButton.vue index cc07175907..c1dc67f776 100644 --- a/packages/frontend/src/components/MkFollowButton.vue +++ b/packages/frontend/src/components/MkFollowButton.vue @@ -91,7 +91,10 @@ async function onClick() { text: i18n.tsx.unfollowConfirm({ name: props.user.name || props.user.username }), }); - if (canceled) return; + if (canceled) { + wait.value = false; + return; + } await misskeyApi('following/delete', { userId: props.user.id, @@ -125,7 +128,10 @@ async function onClick() { }); hasPendingFollowRequestFromYou.value = true; - if ($i == null) return; + if ($i == null) { + wait.value = false; + return; + } claimAchievement('following1'); diff --git a/packages/frontend/src/navbar.ts b/packages/frontend/src/navbar.ts index ac730f8021..096d404a57 100644 --- a/packages/frontend/src/navbar.ts +++ b/packages/frontend/src/navbar.ts @@ -40,7 +40,6 @@ export const navbarItemDef = reactive({ followRequests: { title: i18n.ts.followRequests, icon: 'ti ti-user-plus', - show: computed(() => $i != null && $i.isLocked), indicated: computed(() => $i != null && $i.hasPendingReceivedFollowRequest), to: '/my/follow-requests', }, diff --git a/packages/frontend/src/pages/follow-requests.vue b/packages/frontend/src/pages/follow-requests.vue index a840d0d0b3..8688863c2c 100644 --- a/packages/frontend/src/pages/follow-requests.vue +++ b/packages/frontend/src/pages/follow-requests.vue @@ -5,69 +5,104 @@ SPDX-License-Identifier: AGPL-3.0-only