mirror of
https://github.com/misskey-dev/misskey.git
synced 2026-06-08 14:24:16 +02:00
feat: 投稿通知設定したユーザーをリストで見ることができるように (#17385)
* feat: 投稿通知を設定したユーザーをリストで見ることができるように * test(e2e): 投稿通知のテスト追加 * chore: 不必要なコードの削除
This commit is contained in:
@@ -1217,6 +1217,7 @@ keepScreenOn: "デバイスの画面を常にオンにする"
|
|||||||
verifiedLink: "このリンク先の所有者であることが確認されました"
|
verifiedLink: "このリンク先の所有者であることが確認されました"
|
||||||
notifyNotes: "投稿を通知"
|
notifyNotes: "投稿を通知"
|
||||||
unnotifyNotes: "投稿の通知を解除"
|
unnotifyNotes: "投稿の通知を解除"
|
||||||
|
notifyUsers: "投稿通知を設定したユーザー"
|
||||||
authentication: "認証"
|
authentication: "認証"
|
||||||
authenticationRequiredToContinue: "続けるには認証を行ってください"
|
authenticationRequiredToContinue: "続けるには認証を行ってください"
|
||||||
dateAndTime: "日時"
|
dateAndTime: "日時"
|
||||||
|
|||||||
@@ -391,6 +391,7 @@ export * as 'users/featured-notes' from './endpoints/users/featured-notes.js';
|
|||||||
export * as 'users/flashs' from './endpoints/users/flashs.js';
|
export * as 'users/flashs' from './endpoints/users/flashs.js';
|
||||||
export * as 'users/followers' from './endpoints/users/followers.js';
|
export * as 'users/followers' from './endpoints/users/followers.js';
|
||||||
export * as 'users/following' from './endpoints/users/following.js';
|
export * as 'users/following' from './endpoints/users/following.js';
|
||||||
|
export * as 'users/notify/list' from './endpoints/users/notify/list.js';
|
||||||
export * as 'users/get-following-users-by-birthday' from './endpoints/users/get-following-users-by-birthday.js';
|
export * as 'users/get-following-users-by-birthday' from './endpoints/users/get-following-users-by-birthday.js';
|
||||||
export * as 'users/gallery/posts' from './endpoints/users/gallery/posts.js';
|
export * as 'users/gallery/posts' from './endpoints/users/gallery/posts.js';
|
||||||
export * as 'users/get-frequently-replied-users' from './endpoints/users/get-frequently-replied-users.js';
|
export * as 'users/get-frequently-replied-users' from './endpoints/users/get-frequently-replied-users.js';
|
||||||
|
|||||||
@@ -0,0 +1,66 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: syuilo and misskey-project
|
||||||
|
* SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { Inject, Injectable } from '@nestjs/common';
|
||||||
|
import { UserEntityService } from '@/core/entities/UserEntityService.js';
|
||||||
|
import type { FollowingsRepository } from '@/models/_.js';
|
||||||
|
import { Endpoint } from '@/server/api/endpoint-base.js';
|
||||||
|
import { QueryService } from '@/core/QueryService.js';
|
||||||
|
import { DI } from '@/di-symbols.js';
|
||||||
|
|
||||||
|
export const meta = {
|
||||||
|
tags: ['users'],
|
||||||
|
|
||||||
|
requireCredential: true,
|
||||||
|
kind: 'read:following',
|
||||||
|
description: 'List of following users with notification enabled.',
|
||||||
|
|
||||||
|
res: {
|
||||||
|
type: 'array',
|
||||||
|
optional: false, nullable: false,
|
||||||
|
items: {
|
||||||
|
type: 'object',
|
||||||
|
optional: false, nullable: false,
|
||||||
|
ref: 'UserDetailed',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
} as const;
|
||||||
|
|
||||||
|
export const paramDef = {
|
||||||
|
type: 'object',
|
||||||
|
properties: {
|
||||||
|
sinceId: { type: 'string', format: 'misskey:id' },
|
||||||
|
untilId: { type: 'string', format: 'misskey:id' },
|
||||||
|
sinceDate: { type: 'integer' },
|
||||||
|
untilDate: { type: 'integer' },
|
||||||
|
limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 },
|
||||||
|
},
|
||||||
|
} as const;
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-disable-line import/no-default-export
|
||||||
|
constructor(
|
||||||
|
@Inject(DI.followingsRepository)
|
||||||
|
private followingsRepository: FollowingsRepository,
|
||||||
|
|
||||||
|
private userEntityService: UserEntityService,
|
||||||
|
private queryService: QueryService,
|
||||||
|
) {
|
||||||
|
super(meta, paramDef, async (ps, me) => {
|
||||||
|
const query = this.queryService.makePaginationQuery(this.followingsRepository.createQueryBuilder('following'), ps.sinceId, ps.untilId, ps.sinceDate, ps.untilDate)
|
||||||
|
.innerJoinAndSelect('following.followee', 'followee')
|
||||||
|
.andWhere('following.followerId = :userId', { userId: me.id })
|
||||||
|
.andWhere('following.notify IS NOT NULL');
|
||||||
|
|
||||||
|
const followings = await query
|
||||||
|
.limit(ps.limit)
|
||||||
|
.getMany();
|
||||||
|
|
||||||
|
const users = followings.map(f => f.followee!);
|
||||||
|
|
||||||
|
return await this.userEntityService.packMany(users, me, { schema: 'UserDetailed' });
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
131
packages/backend/test/e2e/note-notify.ts
Normal file
131
packages/backend/test/e2e/note-notify.ts
Normal file
@@ -0,0 +1,131 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: syuilo and misskey-project
|
||||||
|
* SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
*/
|
||||||
|
|
||||||
|
import * as assert from 'node:assert';
|
||||||
|
import { setTimeout } from 'node:timers/promises';
|
||||||
|
import { describe, beforeAll, test } from 'vitest';
|
||||||
|
import { api, signup } from '../utils.js';
|
||||||
|
import type * as misskey from 'misskey-js';
|
||||||
|
|
||||||
|
describe('users/notify/list', () => {
|
||||||
|
let alice: misskey.entities.SignupResponse;
|
||||||
|
let bob: misskey.entities.SignupResponse;
|
||||||
|
let carol: misskey.entities.SignupResponse;
|
||||||
|
|
||||||
|
beforeAll(async () => {
|
||||||
|
alice = await signup({ username: 'alice' });
|
||||||
|
bob = await signup({ username: 'bob' });
|
||||||
|
carol = await signup({ username: 'carol' });
|
||||||
|
}, 1000 * 60 * 2);
|
||||||
|
|
||||||
|
test('通知設定なしのフォローのみの場合、空配列が返る', async () => {
|
||||||
|
// alice が bob を普通にフォロー(通知設定なし)
|
||||||
|
await api('following/create', { userId: bob.id }, alice);
|
||||||
|
|
||||||
|
const res = await api('users/notify/list', {}, alice);
|
||||||
|
|
||||||
|
assert.strictEqual(res.status, 200);
|
||||||
|
assert.strictEqual(Array.isArray(res.body), true);
|
||||||
|
assert.strictEqual(res.body.length, 0);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('通知設定ありのフォローがある場合、そのユーザーが返る', async () => {
|
||||||
|
// alice が carol をフォローして通知ON
|
||||||
|
await api('following/create', { userId: carol.id, withReplies: false }, alice);
|
||||||
|
await api('following/update', { userId: carol.id, notify: 'normal' }, alice);
|
||||||
|
|
||||||
|
const res = await api('users/notify/list', {}, alice);
|
||||||
|
|
||||||
|
assert.strictEqual(res.status, 200);
|
||||||
|
assert.strictEqual(res.body.length, 1);
|
||||||
|
assert.strictEqual(res.body[0].id, carol.id);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('複数ユーザーで通知設定ありの場合、全員返る', async () => {
|
||||||
|
// bob にも通知設定をON
|
||||||
|
await api('following/update', { userId: bob.id, notify: 'normal' }, alice);
|
||||||
|
|
||||||
|
const res = await api('users/notify/list', {}, alice);
|
||||||
|
|
||||||
|
assert.strictEqual(res.status, 200);
|
||||||
|
assert.strictEqual(res.body.length, 2);
|
||||||
|
|
||||||
|
const ids = res.body.map((u: { id: string }) => u.id).sort();
|
||||||
|
assert.deepStrictEqual(ids, [bob.id, carol.id].sort());
|
||||||
|
});
|
||||||
|
|
||||||
|
test('通知設定をOFF(none)にすると一覧から外れる', async () => {
|
||||||
|
await api('following/update', { userId: bob.id, notify: 'none' }, alice);
|
||||||
|
|
||||||
|
const res = await api('users/notify/list', {}, alice);
|
||||||
|
|
||||||
|
assert.strictEqual(res.status, 200);
|
||||||
|
assert.strictEqual(res.body.length, 1);
|
||||||
|
assert.strictEqual(res.body[0].id, carol.id);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('他のユーザーの通知対象は見えない', async () => {
|
||||||
|
// bob が carol をフォローして通知ON
|
||||||
|
await api('following/create', { userId: carol.id }, bob);
|
||||||
|
await api('following/update', { userId: carol.id, notify: 'normal' }, bob);
|
||||||
|
|
||||||
|
// alice の一覧には bob の通知設定は反映されない
|
||||||
|
const aliceRes = await api('users/notify/list', {}, alice);
|
||||||
|
const aliceIds = aliceRes.body.map((u: { id: string }) => u.id);
|
||||||
|
assert.strictEqual(aliceIds.includes(bob.id), false);
|
||||||
|
|
||||||
|
// bob の一覧には carol だけが含まれる
|
||||||
|
const bobRes = await api('users/notify/list', {}, bob);
|
||||||
|
assert.strictEqual(bobRes.body.length, 1);
|
||||||
|
assert.strictEqual(bobRes.body[0].id, carol.id);
|
||||||
|
|
||||||
|
// 後片付け: bob → carol のフォローを解除
|
||||||
|
await api('following/delete', { userId: carol.id }, bob);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('normal通知設定時、投稿で通知が届く', async () => {
|
||||||
|
await api('following/update', { userId: bob.id, notify: 'normal' }, alice);
|
||||||
|
|
||||||
|
await api('notifications/mark-all-as-read', {}, alice);
|
||||||
|
const textOnlyRes = await api('notes/create', {
|
||||||
|
text: 'ファイルなしの投稿',
|
||||||
|
}, bob);
|
||||||
|
assert.strictEqual(textOnlyRes.status, 200);
|
||||||
|
// redisに追加されるのを待つ
|
||||||
|
await setTimeout(100);
|
||||||
|
|
||||||
|
const beforeRes = await api('i/notifications', {}, alice);
|
||||||
|
assert.strictEqual(beforeRes.status, 200);
|
||||||
|
const noteNotif = beforeRes.body.filter((n: { type: string; note?: { id: string } }) =>
|
||||||
|
n.type === 'note' && n.note?.id === textOnlyRes.body.createdNote.id,
|
||||||
|
);
|
||||||
|
|
||||||
|
assert.strictEqual(noteNotif.length, 1, '投稿の通知が届かなかった');
|
||||||
|
|
||||||
|
// 後片付け
|
||||||
|
await api('following/update', { userId: bob.id, notify: 'none' }, alice);
|
||||||
|
await api('notifications/mark-all-as-read', {}, alice);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('limit パラメータが効く', async () => {
|
||||||
|
// limit テスト用に bob を再度ONにして2件状態を作る
|
||||||
|
await api('following/update', { userId: bob.id, notify: 'normal' }, alice);
|
||||||
|
|
||||||
|
// limitなしだと2件返ることを確認
|
||||||
|
const allRes = await api('users/notify/list', {}, alice);
|
||||||
|
assert.strictEqual(allRes.status, 200);
|
||||||
|
assert.strictEqual(allRes.body.length, 2);
|
||||||
|
|
||||||
|
// limit:1 で1件に絞られることを確認
|
||||||
|
const res = await api('users/notify/list', { limit: 1 }, alice);
|
||||||
|
assert.strictEqual(res.status, 200);
|
||||||
|
assert.strictEqual(res.body.length, 1);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('未認証の場合はエラー', async () => {
|
||||||
|
const res = await api('users/notify/list', {});
|
||||||
|
assert.strictEqual(res.status, 401);
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -36,6 +36,28 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||||||
</MkFolder>
|
</MkFolder>
|
||||||
</div>
|
</div>
|
||||||
</FormSection>
|
</FormSection>
|
||||||
|
|
||||||
|
<FormSection>
|
||||||
|
<SearchMarker
|
||||||
|
:keywords="['notify', 'hide', 'user']"
|
||||||
|
>
|
||||||
|
<MkFolder>
|
||||||
|
<template #label><SearchLabel>{{ i18n.ts.notifyUsers }}</SearchLabel></template>
|
||||||
|
<MkPagination v-slot="{items}" :paginator="notifyUserPaginator" withControl>
|
||||||
|
<div class="_gaps_s">
|
||||||
|
<div v-for="item in items" :key="item.id" :class="[$style.userItem ]">
|
||||||
|
<div :class="$style.userItemMain">
|
||||||
|
<MkA :class="$style.userItemMainBody" :to="userPage(item)">
|
||||||
|
<MkUserCardMini :user="item"/>
|
||||||
|
</MkA>
|
||||||
|
<button class="_button" :class="$style.notifyMenu" @click="showNotifyMenu(item, $event)"><i class="ti ti-dots"></i></button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</MkPagination>
|
||||||
|
</MkFolder>
|
||||||
|
</SearchMarker>
|
||||||
|
</FormSection>
|
||||||
<FormSection>
|
<FormSection>
|
||||||
<div class="_gaps_m">
|
<div class="_gaps_m">
|
||||||
<FormLink to="/settings/sounds">{{ i18n.ts.notificationSoundSettings }}</FormLink>
|
<FormLink to="/settings/sounds">{{ i18n.ts.notificationSoundSettings }}</FormLink>
|
||||||
@@ -64,8 +86,9 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { useTemplateRef, computed } from 'vue';
|
import { useTemplateRef, computed, ref, markRaw } from 'vue';
|
||||||
import { notificationTypes } from 'misskey-js';
|
import { notificationTypes } from 'misskey-js';
|
||||||
|
import * as Misskey from 'misskey-js';
|
||||||
import XNotificationConfig from './notifications.notification-config.vue';
|
import XNotificationConfig from './notifications.notification-config.vue';
|
||||||
import type { NotificationConfig } from './notifications.notification-config.vue';
|
import type { NotificationConfig } from './notifications.notification-config.vue';
|
||||||
import FormLink from '@/components/form/link.vue';
|
import FormLink from '@/components/form/link.vue';
|
||||||
@@ -80,9 +103,32 @@ import { i18n } from '@/i18n.js';
|
|||||||
import { definePage } from '@/page.js';
|
import { definePage } from '@/page.js';
|
||||||
import MkPushNotificationAllowButton from '@/components/MkPushNotificationAllowButton.vue';
|
import MkPushNotificationAllowButton from '@/components/MkPushNotificationAllowButton.vue';
|
||||||
import MkFeatureBanner from '@/components/MkFeatureBanner.vue';
|
import MkFeatureBanner from '@/components/MkFeatureBanner.vue';
|
||||||
|
import { Paginator } from '@/utility/paginator.js';
|
||||||
|
import MkPagination from '@/components/MkPagination.vue';
|
||||||
|
import { userPage } from '@/filters/user.js';
|
||||||
|
import MkUserCardMini from '@/components/MkUserCardMini.vue';
|
||||||
|
|
||||||
const $i = ensureSignin();
|
const $i = ensureSignin();
|
||||||
|
|
||||||
|
async function showNotifyMenu(user: Misskey.entities.UserDetailed, ev: PointerEvent) {
|
||||||
|
os.popupMenu([{
|
||||||
|
text: (user.notify === 'normal') ? i18n.ts.unnotifyNotes : i18n.ts.notifyNotes,
|
||||||
|
icon: (user.notify === 'normal') ? 'ti ti-x' : 'ti ti-plus',
|
||||||
|
action: async () => {
|
||||||
|
await os.apiWithDialog('following/update', {
|
||||||
|
userId: user.id,
|
||||||
|
notify: user.notify === 'normal' ? 'none' : 'normal',
|
||||||
|
}).then(() => {
|
||||||
|
user.notify = user.notify === 'normal' ? 'none' : 'normal';
|
||||||
|
});
|
||||||
|
},
|
||||||
|
}], ev.currentTarget ?? ev.target);
|
||||||
|
}
|
||||||
|
|
||||||
|
const notifyUserPaginator = markRaw(new Paginator('users/notify/list', {
|
||||||
|
limit: 10,
|
||||||
|
}));
|
||||||
|
|
||||||
const nonConfigurableNotificationTypes = ['note', 'roleAssigned', 'followRequestAccepted', 'test', 'exportCompleted'] as const satisfies (typeof notificationTypes[number])[];
|
const nonConfigurableNotificationTypes = ['note', 'roleAssigned', 'followRequestAccepted', 'test', 'exportCompleted'] as const satisfies (typeof notificationTypes[number])[];
|
||||||
|
|
||||||
const configurableNotificationTypes = notificationTypes.filter(type => !nonConfigurableNotificationTypes.includes(type as any)) as Exclude<typeof notificationTypes[number], typeof nonConfigurableNotificationTypes[number]>[];
|
const configurableNotificationTypes = notificationTypes.filter(type => !nonConfigurableNotificationTypes.includes(type as any)) as Exclude<typeof notificationTypes[number], typeof nonConfigurableNotificationTypes[number]>[];
|
||||||
@@ -145,3 +191,25 @@ definePage(() => ({
|
|||||||
icon: 'ti ti-bell',
|
icon: 'ti ti-bell',
|
||||||
}));
|
}));
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" module>
|
||||||
|
.userItemMain {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
.userItemMainBody {
|
||||||
|
flex: 1;
|
||||||
|
min-width: 0;
|
||||||
|
margin-right: 8px;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.notifyMenu {
|
||||||
|
width: 32px;
|
||||||
|
height: 32px;
|
||||||
|
align-self: center;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|||||||
@@ -4880,6 +4880,10 @@ export interface Locale extends ILocale {
|
|||||||
* 投稿の通知を解除
|
* 投稿の通知を解除
|
||||||
*/
|
*/
|
||||||
"unnotifyNotes": string;
|
"unnotifyNotes": string;
|
||||||
|
/**
|
||||||
|
* 投稿通知を設定したユーザー
|
||||||
|
*/
|
||||||
|
"notifyUsers": string;
|
||||||
/**
|
/**
|
||||||
* 認証
|
* 認証
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -2162,6 +2162,8 @@ declare namespace entities {
|
|||||||
UsersListsUpdateMembershipRequest,
|
UsersListsUpdateMembershipRequest,
|
||||||
UsersNotesRequest,
|
UsersNotesRequest,
|
||||||
UsersNotesResponse,
|
UsersNotesResponse,
|
||||||
|
UsersNotifyListRequest,
|
||||||
|
UsersNotifyListResponse,
|
||||||
UsersPagesRequest,
|
UsersPagesRequest,
|
||||||
UsersPagesResponse,
|
UsersPagesResponse,
|
||||||
UsersReactionsRequest,
|
UsersReactionsRequest,
|
||||||
@@ -3827,6 +3829,12 @@ type UsersNotesRequest = operations['users___notes']['requestBody']['content']['
|
|||||||
// @public (undocumented)
|
// @public (undocumented)
|
||||||
type UsersNotesResponse = operations['users___notes']['responses']['200']['content']['application/json'];
|
type UsersNotesResponse = operations['users___notes']['responses']['200']['content']['application/json'];
|
||||||
|
|
||||||
|
// @public (undocumented)
|
||||||
|
type UsersNotifyListRequest = operations['users___notify___list']['requestBody']['content']['application/json'];
|
||||||
|
|
||||||
|
// @public (undocumented)
|
||||||
|
type UsersNotifyListResponse = operations['users___notify___list']['responses']['200']['content']['application/json'];
|
||||||
|
|
||||||
// @public (undocumented)
|
// @public (undocumented)
|
||||||
type UsersPagesRequest = operations['users___pages']['requestBody']['content']['application/json'];
|
type UsersPagesRequest = operations['users___pages']['requestBody']['content']['application/json'];
|
||||||
|
|
||||||
|
|||||||
@@ -4697,6 +4697,17 @@ declare module '../api.js' {
|
|||||||
credential?: string | null,
|
credential?: string | null,
|
||||||
): Promise<SwitchCaseResponseType<E, P>>;
|
): Promise<SwitchCaseResponseType<E, P>>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* List of following users with notification enabled.
|
||||||
|
*
|
||||||
|
* **Credential required**: *Yes* / **Permission**: *read:following*
|
||||||
|
*/
|
||||||
|
request<E extends 'users/notify/list', P extends Endpoints[E]['req']>(
|
||||||
|
endpoint: E,
|
||||||
|
params: P,
|
||||||
|
credential?: string | null,
|
||||||
|
): Promise<SwitchCaseResponseType<E, P>>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Show all pages this user created.
|
* Show all pages this user created.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -640,6 +640,8 @@ import type {
|
|||||||
UsersListsUpdateMembershipRequest,
|
UsersListsUpdateMembershipRequest,
|
||||||
UsersNotesRequest,
|
UsersNotesRequest,
|
||||||
UsersNotesResponse,
|
UsersNotesResponse,
|
||||||
|
UsersNotifyListRequest,
|
||||||
|
UsersNotifyListResponse,
|
||||||
UsersPagesRequest,
|
UsersPagesRequest,
|
||||||
UsersPagesResponse,
|
UsersPagesResponse,
|
||||||
UsersReactionsRequest,
|
UsersReactionsRequest,
|
||||||
@@ -1084,6 +1086,7 @@ export type Endpoints = {
|
|||||||
'users/lists/update': { req: UsersListsUpdateRequest; res: UsersListsUpdateResponse };
|
'users/lists/update': { req: UsersListsUpdateRequest; res: UsersListsUpdateResponse };
|
||||||
'users/lists/update-membership': { req: UsersListsUpdateMembershipRequest; res: EmptyResponse };
|
'users/lists/update-membership': { req: UsersListsUpdateMembershipRequest; res: EmptyResponse };
|
||||||
'users/notes': { req: UsersNotesRequest; res: UsersNotesResponse };
|
'users/notes': { req: UsersNotesRequest; res: UsersNotesResponse };
|
||||||
|
'users/notify/list': { req: UsersNotifyListRequest; res: UsersNotifyListResponse };
|
||||||
'users/pages': { req: UsersPagesRequest; res: UsersPagesResponse };
|
'users/pages': { req: UsersPagesRequest; res: UsersPagesResponse };
|
||||||
'users/reactions': { req: UsersReactionsRequest; res: UsersReactionsResponse };
|
'users/reactions': { req: UsersReactionsRequest; res: UsersReactionsResponse };
|
||||||
'users/recommendation': { req: UsersRecommendationRequest; res: UsersRecommendationResponse };
|
'users/recommendation': { req: UsersRecommendationRequest; res: UsersRecommendationResponse };
|
||||||
|
|||||||
@@ -643,6 +643,8 @@ export type UsersListsUpdateResponse = operations['users___lists___update']['res
|
|||||||
export type UsersListsUpdateMembershipRequest = operations['users___lists___update-membership']['requestBody']['content']['application/json'];
|
export type UsersListsUpdateMembershipRequest = operations['users___lists___update-membership']['requestBody']['content']['application/json'];
|
||||||
export type UsersNotesRequest = operations['users___notes']['requestBody']['content']['application/json'];
|
export type UsersNotesRequest = operations['users___notes']['requestBody']['content']['application/json'];
|
||||||
export type UsersNotesResponse = operations['users___notes']['responses']['200']['content']['application/json'];
|
export type UsersNotesResponse = operations['users___notes']['responses']['200']['content']['application/json'];
|
||||||
|
export type UsersNotifyListRequest = operations['users___notify___list']['requestBody']['content']['application/json'];
|
||||||
|
export type UsersNotifyListResponse = operations['users___notify___list']['responses']['200']['content']['application/json'];
|
||||||
export type UsersPagesRequest = operations['users___pages']['requestBody']['content']['application/json'];
|
export type UsersPagesRequest = operations['users___pages']['requestBody']['content']['application/json'];
|
||||||
export type UsersPagesResponse = operations['users___pages']['responses']['200']['content']['application/json'];
|
export type UsersPagesResponse = operations['users___pages']['responses']['200']['content']['application/json'];
|
||||||
export type UsersReactionsRequest = operations['users___reactions']['requestBody']['content']['application/json'];
|
export type UsersReactionsRequest = operations['users___reactions']['requestBody']['content']['application/json'];
|
||||||
|
|||||||
@@ -3852,6 +3852,15 @@ export type paths = {
|
|||||||
*/
|
*/
|
||||||
post: operations['users___notes'];
|
post: operations['users___notes'];
|
||||||
};
|
};
|
||||||
|
'/users/notify/list': {
|
||||||
|
/**
|
||||||
|
* users/notify/list
|
||||||
|
* @description List of following users with notification enabled.
|
||||||
|
*
|
||||||
|
* **Credential required**: *Yes* / **Permission**: *read:following*
|
||||||
|
*/
|
||||||
|
post: operations['users___notify___list'];
|
||||||
|
};
|
||||||
'/users/pages': {
|
'/users/pages': {
|
||||||
/**
|
/**
|
||||||
* users/pages
|
* users/pages
|
||||||
@@ -36047,6 +36056,78 @@ export interface operations {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
users___notify___list: {
|
||||||
|
requestBody: {
|
||||||
|
content: {
|
||||||
|
'application/json': {
|
||||||
|
/** Format: misskey:id */
|
||||||
|
sinceId?: string;
|
||||||
|
/** Format: misskey:id */
|
||||||
|
untilId?: string;
|
||||||
|
sinceDate?: number;
|
||||||
|
untilDate?: number;
|
||||||
|
/** @default 10 */
|
||||||
|
limit?: number;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
responses: {
|
||||||
|
/** @description OK (with results) */
|
||||||
|
200: {
|
||||||
|
headers: {
|
||||||
|
[name: string]: unknown;
|
||||||
|
};
|
||||||
|
content: {
|
||||||
|
'application/json': components['schemas']['UserDetailed'][];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
/** @description Client error */
|
||||||
|
400: {
|
||||||
|
headers: {
|
||||||
|
[name: string]: unknown;
|
||||||
|
};
|
||||||
|
content: {
|
||||||
|
'application/json': components['schemas']['Error'];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
/** @description Authentication error */
|
||||||
|
401: {
|
||||||
|
headers: {
|
||||||
|
[name: string]: unknown;
|
||||||
|
};
|
||||||
|
content: {
|
||||||
|
'application/json': components['schemas']['Error'];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
/** @description Forbidden error */
|
||||||
|
403: {
|
||||||
|
headers: {
|
||||||
|
[name: string]: unknown;
|
||||||
|
};
|
||||||
|
content: {
|
||||||
|
'application/json': components['schemas']['Error'];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
/** @description I'm Ai */
|
||||||
|
418: {
|
||||||
|
headers: {
|
||||||
|
[name: string]: unknown;
|
||||||
|
};
|
||||||
|
content: {
|
||||||
|
'application/json': components['schemas']['Error'];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
/** @description Internal server error */
|
||||||
|
500: {
|
||||||
|
headers: {
|
||||||
|
[name: string]: unknown;
|
||||||
|
};
|
||||||
|
content: {
|
||||||
|
'application/json': components['schemas']['Error'];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
users___pages: {
|
users___pages: {
|
||||||
requestBody: {
|
requestBody: {
|
||||||
content: {
|
content: {
|
||||||
|
|||||||
Reference in New Issue
Block a user