Merge upstream
This commit is contained in:
commit
0df3eb7dc4
15 changed files with 180 additions and 10 deletions
|
@ -536,7 +536,7 @@ export class NoteCreateService implements OnApplicationShutdown {
|
||||||
const meta = await this.metaService.fetch();
|
const meta = await this.metaService.fetch();
|
||||||
|
|
||||||
this.notesChart.update(note, true);
|
this.notesChart.update(note, true);
|
||||||
if (meta.enableChartsForRemoteUser || (user.host == null)) {
|
if (note.visibility !== 'specified' && (meta.enableChartsForRemoteUser || (user.host == null))) {
|
||||||
this.perUserNotesChart.update(user, note, true);
|
this.perUserNotesChart.update(user, note, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,6 +10,7 @@ import { QueryService } from '@/core/QueryService.js';
|
||||||
import { NoteEntityService } from '@/core/entities/NoteEntityService.js';
|
import { NoteEntityService } from '@/core/entities/NoteEntityService.js';
|
||||||
import { DI } from '@/di-symbols.js';
|
import { DI } from '@/di-symbols.js';
|
||||||
import { ApiError } from '../../../error.js';
|
import { ApiError } from '../../../error.js';
|
||||||
|
import { RoleService } from '@/core/RoleService.js';
|
||||||
|
|
||||||
export const meta = {
|
export const meta = {
|
||||||
tags: ['drive', 'notes'],
|
tags: ['drive', 'notes'],
|
||||||
|
@ -61,12 +62,13 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||||
|
|
||||||
private noteEntityService: NoteEntityService,
|
private noteEntityService: NoteEntityService,
|
||||||
private queryService: QueryService,
|
private queryService: QueryService,
|
||||||
|
private roleService: RoleService,
|
||||||
) {
|
) {
|
||||||
super(meta, paramDef, async (ps, me) => {
|
super(meta, paramDef, async (ps, me) => {
|
||||||
// Fetch file
|
// Fetch file
|
||||||
const file = await this.driveFilesRepository.findOneBy({
|
const file = await this.driveFilesRepository.findOneBy({
|
||||||
id: ps.fileId,
|
id: ps.fileId,
|
||||||
userId: me.id,
|
userId: await this.roleService.isModerator(me) ? undefined : me.id,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (file == null) {
|
if (file == null) {
|
||||||
|
|
|
@ -58,6 +58,12 @@ export const meta = {
|
||||||
code: 'BLOCKED',
|
code: 'BLOCKED',
|
||||||
id: 'c4ab57cc-4e41-45e9-bfd9-584f61e35ce0',
|
id: 'c4ab57cc-4e41-45e9-bfd9-584f61e35ce0',
|
||||||
},
|
},
|
||||||
|
|
||||||
|
followingAnotherBot: {
|
||||||
|
message: 'Following another bot account is not allowed.',
|
||||||
|
code: 'FOLLOWING_BOT_NOT_ALLOWED',
|
||||||
|
id: '9a61d572-4a95-7f6b-b595-2817d42017b0',
|
||||||
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
res: {
|
res: {
|
||||||
|
@ -100,6 +106,10 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||||
throw err;
|
throw err;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if ( me.isBot && followee.isBot ) {
|
||||||
|
throw new ApiError(meta.errors.followingAnotherBot);
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await this.userFollowingService.follow(follower, followee, { withReplies: ps.withReplies });
|
await this.userFollowingService.follow(follower, followee, { withReplies: ps.withReplies });
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
|
|
@ -141,6 +141,13 @@ export const meta = {
|
||||||
code: 'CONTAINS_TOO_MANY_MENTIONS',
|
code: 'CONTAINS_TOO_MANY_MENTIONS',
|
||||||
id: '4de0363a-3046-481b-9b0f-feff3e211025',
|
id: '4de0363a-3046-481b-9b0f-feff3e211025',
|
||||||
},
|
},
|
||||||
|
|
||||||
|
replyingToAnotherBot: {
|
||||||
|
message: 'Replying to another bot account is not allowed.',
|
||||||
|
code: 'REPLY_TO_BOT_NOT_ALLOWED',
|
||||||
|
id: '66819f28-9525-389d-4b0a-4974363fbbbf',
|
||||||
|
},
|
||||||
|
|
||||||
},
|
},
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
|
@ -375,6 +382,11 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||||
throw new ApiError(meta.errors.cannotReplyToInvisibleNote);
|
throw new ApiError(meta.errors.cannotReplyToInvisibleNote);
|
||||||
} else if (reply.visibility === 'specified' && ps.visibility !== 'specified') {
|
} else if (reply.visibility === 'specified' && ps.visibility !== 'specified') {
|
||||||
throw new ApiError(meta.errors.cannotReplyToSpecifiedVisibilityNoteWithExtendedVisibility);
|
throw new ApiError(meta.errors.cannotReplyToSpecifiedVisibilityNoteWithExtendedVisibility);
|
||||||
|
} else if ( me.isBot ) {
|
||||||
|
const replayuser = await this.usersRepository.findOneBy({ id: reply.userId });
|
||||||
|
if (replayuser?.isBot) {
|
||||||
|
throw new ApiError(meta.errors.replyingToAnotherBot);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check blocking
|
// Check blocking
|
||||||
|
|
|
@ -66,6 +66,13 @@ export const meta = {
|
||||||
id: '4362f8dc-731f-4ad8-a694-be5a88922a24',
|
id: '4362f8dc-731f-4ad8-a694-be5a88922a24',
|
||||||
httpStatusCode: 404,
|
httpStatusCode: 404,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
userSuspended: {
|
||||||
|
message: 'User is suspended.',
|
||||||
|
code: 'USER_SUSPENDED',
|
||||||
|
id: 'c1e1b0d6-2b7c-4c1d-9f1d-2d3d6e8d7e7f',
|
||||||
|
httpStatusCode: 403,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
|
@ -147,10 +154,19 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||||
user = await this.usersRepository.findOneBy(q);
|
user = await this.usersRepository.findOneBy(q);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (user == null || (!isModerator && user.isSuspended)) {
|
if (user == null) {
|
||||||
throw new ApiError(meta.errors.noSuchUser);
|
throw new ApiError(meta.errors.noSuchUser);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!isModerator) {
|
||||||
|
if (user.isDeleted && user.isSuspended) {
|
||||||
|
throw new ApiError(meta.errors.noSuchUser);
|
||||||
|
}
|
||||||
|
if (user.isSuspended) {
|
||||||
|
throw new ApiError(meta.errors.userSuspended);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (user.host == null) {
|
if (user.host == null) {
|
||||||
if (me == null && ip != null) {
|
if (me == null && ip != null) {
|
||||||
this.perUserPvChart.commitByVisitor(user, ip);
|
this.perUserPvChart.commitByVisitor(user, ip);
|
||||||
|
|
|
@ -8,7 +8,7 @@ process.env.NODE_ENV = 'test';
|
||||||
import * as assert from 'assert';
|
import * as assert from 'assert';
|
||||||
import { inspect } from 'node:util';
|
import { inspect } from 'node:util';
|
||||||
import { DEFAULT_POLICIES } from '@/core/RoleService.js';
|
import { DEFAULT_POLICIES } from '@/core/RoleService.js';
|
||||||
import { api, post, role, signup, successfulApiCall, uploadFile } from '../utils.js';
|
import { api, post, role, signup, successfulApiCall, uploadFile, failedApiCall } from '../utils.js';
|
||||||
import type * as misskey from 'misskey-js';
|
import type * as misskey from 'misskey-js';
|
||||||
|
|
||||||
describe('ユーザー', () => {
|
describe('ユーザー', () => {
|
||||||
|
@ -885,6 +885,22 @@ describe('ユーザー', () => {
|
||||||
|
|
||||||
//#endregion
|
//#endregion
|
||||||
|
|
||||||
|
//#region 凍結/削除ユーザー
|
||||||
|
test('が凍結済みのユーザー情報を取得できない', async () => {
|
||||||
|
const parameters = { userId: userSuspended.id };
|
||||||
|
await failedApiCall({ endpoint: 'users/show', parameters, user: alice },
|
||||||
|
{ status: 403, code: 'USER_SUSPENDED', id: 'c1e1b0d6-2b7c-4c1d-9f1d-2d3d6e8d7e7f' });
|
||||||
|
});
|
||||||
|
|
||||||
|
test('(Admin)が凍結済みユーザー情報を取得できる', async () => {
|
||||||
|
const parameters = { userId: userSuspended.id };
|
||||||
|
await successfulApiCall({ endpoint: 'users/show', parameters, user: root });
|
||||||
|
// Adminとユーザー情報は持っている情報が違うので、比較はできない
|
||||||
|
// const expected = userSuspended;
|
||||||
|
// assert.deepStrictEqual(response, expected);
|
||||||
|
});
|
||||||
|
//#endregion
|
||||||
|
|
||||||
test.todo('を管理人として確認することができる(admin/show-user)');
|
test.todo('を管理人として確認することができる(admin/show-user)');
|
||||||
test.todo('を管理人として確認することができる(admin/show-users)');
|
test.todo('を管理人として確認することができる(admin/show-users)');
|
||||||
test.todo('をサーバー向けに取得することができる(federation/users)');
|
test.todo('をサーバー向けに取得することができる(federation/users)');
|
||||||
|
|
|
@ -121,7 +121,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
<button ref="reactButton" :class="$style.footerButton" class="_button" @click="toggleReact()">
|
<button ref="reactButton" :class="$style.footerButton" class="_button" @click="toggleReact()">
|
||||||
<i v-if=" (appearNote.reactionAcceptance === 'likeOnly' || !$i?.policies.canUseReaction) && appearNote.myReaction != null " class="ti ti-heart-filled" style="color: var(--eventReactionHeart);"></i>
|
<i v-if=" (appearNote.reactionAcceptance === 'likeOnly' || !$i?.policies.canUseReaction) && appearNote.myReaction != null " class="ti ti-heart-filled" style="color: var(--eventReactionHeart);"></i>
|
||||||
<i v-else-if="appearNote.myReaction != null " class="ti ti-minus" style="color: var(--accent);"></i>
|
<i v-else-if="appearNote.myReaction != null " class="ti ti-minus" style="color: var(--accent);"></i>
|
||||||
<i v-else-if="appearNote.reactionAcceptance === 'likeOnly' || !$i?.policies.canUseReaction" class="ti ti-heart"></i>
|
<i v-else-if="appearNote.reactionAcceptance === 'likeOnly' || $i && !$i.policies.canUseReaction" class="ti ti-heart"></i>
|
||||||
<i v-else class="ti ti-plus"></i>
|
<i v-else class="ti ti-plus"></i>
|
||||||
<p v-if="(appearNote.reactionAcceptance === 'likeOnly' || defaultStore.state.showReactionsCount) && appearNote.reactionCount > 0" :class="$style.footerButtonCount">{{ number(appearNote.reactionCount) }}</p>
|
<p v-if="(appearNote.reactionAcceptance === 'likeOnly' || defaultStore.state.showReactionsCount) && appearNote.reactionCount > 0" :class="$style.footerButtonCount">{{ number(appearNote.reactionCount) }}</p>
|
||||||
</button>
|
</button>
|
||||||
|
|
|
@ -129,7 +129,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
<button ref="reactButton" :class="$style.noteFooterButton" class="_button" @click="toggleReact()">
|
<button ref="reactButton" :class="$style.noteFooterButton" class="_button" @click="toggleReact()">
|
||||||
<i v-if=" (appearNote.reactionAcceptance === 'likeOnly' || !$i?.policies.canUseReaction) && appearNote.myReaction != null " class="ti ti-heart-filled" style="color: var(--eventReactionHeart);"></i>
|
<i v-if=" (appearNote.reactionAcceptance === 'likeOnly' || !$i?.policies.canUseReaction) && appearNote.myReaction != null " class="ti ti-heart-filled" style="color: var(--eventReactionHeart);"></i>
|
||||||
<i v-else-if="appearNote.myReaction != null " class="ti ti-minus" style="color: var(--accent);"></i>
|
<i v-else-if="appearNote.myReaction != null " class="ti ti-minus" style="color: var(--accent);"></i>
|
||||||
<i v-else-if="appearNote.reactionAcceptance === 'likeOnly' || !$i?.policies.canUseReaction" class="ti ti-heart"></i>
|
<i v-else-if="appearNote.reactionAcceptance === 'likeOnly' || $i && !$i.policies.canUseReaction" class="ti ti-heart"></i>
|
||||||
<i v-else class="ti ti-plus"></i>
|
<i v-else class="ti ti-plus"></i>
|
||||||
<p v-if="(appearNote.reactionAcceptance === 'likeOnly' || defaultStore.state.showReactionsCount) && appearNote.reactionCount > 0" :class="$style.noteFooterButtonCount">{{ number(appearNote.reactionCount) }}</p>
|
<p v-if="(appearNote.reactionAcceptance === 'likeOnly' || defaultStore.state.showReactionsCount) && appearNote.reactionCount > 0" :class="$style.noteFooterButtonCount">{{ number(appearNote.reactionCount) }}</p>
|
||||||
</button>
|
</button>
|
||||||
|
|
|
@ -81,6 +81,7 @@ function getReactionName(reaction: string): string {
|
||||||
}
|
}
|
||||||
|
|
||||||
.user {
|
.user {
|
||||||
|
display: flex;
|
||||||
line-height: 24px;
|
line-height: 24px;
|
||||||
padding-top: 4px;
|
padding-top: 4px;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
|
|
44
packages/frontend/src/components/MkUserNotFound.vue
Normal file
44
packages/frontend/src/components/MkUserNotFound.vue
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
<!--
|
||||||
|
SPDX-FileCopyrightText: syuilo and misskey-project
|
||||||
|
SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
-->
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<Transition :name="defaultStore.state.animation ? '_transition_zoom' : ''" appear>
|
||||||
|
<div :class="$style.root">
|
||||||
|
<img :class="$style.img" :src="serverErrorImageUrl" class="_ghost"/>
|
||||||
|
<p :class="$style.text"><i class="ti ti-alert-triangle"></i> {{ i18n.ts.noSuchUser }}</p>
|
||||||
|
</div>
|
||||||
|
</Transition>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { i18n } from '@/i18n.js';
|
||||||
|
import { defaultStore } from '@/store.js';
|
||||||
|
import { serverErrorImageUrl } from '@/instance.js';
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" module>
|
||||||
|
.root {
|
||||||
|
padding: 32px;
|
||||||
|
text-align: center;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.text {
|
||||||
|
margin: 0 0 8px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.button {
|
||||||
|
margin: 0 auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.img {
|
||||||
|
vertical-align: bottom;
|
||||||
|
width: 128px;
|
||||||
|
height: 128px;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
border-radius: 16px;
|
||||||
|
}
|
||||||
|
</style>
|
44
packages/frontend/src/components/MkUserSuspended.vue
Normal file
44
packages/frontend/src/components/MkUserSuspended.vue
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
<!--
|
||||||
|
SPDX-FileCopyrightText: syuilo and misskey-project
|
||||||
|
SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
-->
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<Transition :name="defaultStore.state.animation ? '_transition_zoom' : ''" appear>
|
||||||
|
<div :class="$style.root">
|
||||||
|
<img :class="$style.img" :src="serverErrorImageUrl" class="_ghost"/>
|
||||||
|
<p :class="$style.text"><i class="ti ti-alert-triangle"></i> {{ i18n.ts.userSuspended }}</p>
|
||||||
|
</div>
|
||||||
|
</Transition>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { i18n } from '@/i18n.js';
|
||||||
|
import { defaultStore } from '@/store.js';
|
||||||
|
import { serverErrorImageUrl } from '@/instance.js';
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" module>
|
||||||
|
.root {
|
||||||
|
padding: 32px;
|
||||||
|
text-align: center;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.text {
|
||||||
|
margin: 0 0 8px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.button {
|
||||||
|
margin: 0 auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.img {
|
||||||
|
vertical-align: bottom;
|
||||||
|
width: 128px;
|
||||||
|
height: 128px;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
border-radius: 16px;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -44,6 +44,9 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
<MkButton danger @click="del"><i class="ti ti-trash"></i> {{ i18n.ts.delete }}</MkButton>
|
<MkButton danger @click="del"><i class="ti ti-trash"></i> {{ i18n.ts.delete }}</MkButton>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div v-else-if="tab === 'notes' && info" class="_gaps_m">
|
||||||
|
<XNotes :fileId="fileId"/>
|
||||||
|
</div>
|
||||||
<div v-else-if="tab === 'ip' && info" class="_gaps_m">
|
<div v-else-if="tab === 'ip' && info" class="_gaps_m">
|
||||||
<MkInfo v-if="!iAmAdmin" warn>{{ i18n.ts.requireAdminForView }}</MkInfo>
|
<MkInfo v-if="!iAmAdmin" warn>{{ i18n.ts.requireAdminForView }}</MkInfo>
|
||||||
<MkKeyValue v-if="info.requestIp" class="_monospace" :copy="info.requestIp" oneline>
|
<MkKeyValue v-if="info.requestIp" class="_monospace" :copy="info.requestIp" oneline>
|
||||||
|
@ -67,7 +70,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { computed, ref } from 'vue';
|
import { computed, defineAsyncComponent, ref } from 'vue';
|
||||||
import * as Misskey from 'misskey-js';
|
import * as Misskey from 'misskey-js';
|
||||||
import MkButton from '@/components/MkButton.vue';
|
import MkButton from '@/components/MkButton.vue';
|
||||||
import MkSwitch from '@/components/MkSwitch.vue';
|
import MkSwitch from '@/components/MkSwitch.vue';
|
||||||
|
@ -88,6 +91,7 @@ const tab = ref('overview');
|
||||||
const file = ref<Misskey.entities.DriveFile | null>(null);
|
const file = ref<Misskey.entities.DriveFile | null>(null);
|
||||||
const info = ref<Misskey.entities.AdminDriveShowFileResponse | null>(null);
|
const info = ref<Misskey.entities.AdminDriveShowFileResponse | null>(null);
|
||||||
const isSensitive = ref<boolean>(false);
|
const isSensitive = ref<boolean>(false);
|
||||||
|
const XNotes = defineAsyncComponent(() => import('./drive.file.notes.vue'));
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
fileId: string,
|
fileId: string,
|
||||||
|
@ -131,6 +135,10 @@ const headerTabs = computed(() => [{
|
||||||
title: i18n.ts.overview,
|
title: i18n.ts.overview,
|
||||||
icon: 'ti ti-info-circle',
|
icon: 'ti ti-info-circle',
|
||||||
}, iAmModerator ? {
|
}, iAmModerator ? {
|
||||||
|
key: 'notes',
|
||||||
|
title: i18n.ts._fileViewer.attachedNotes,
|
||||||
|
icon: 'ti ti-pencil',
|
||||||
|
} : null, iAmModerator ? {
|
||||||
key: 'ip',
|
key: 'ip',
|
||||||
title: 'IP',
|
title: 'IP',
|
||||||
icon: 'ti ti-password',
|
icon: 'ti ti-password',
|
||||||
|
|
|
@ -69,6 +69,7 @@ async function search() {
|
||||||
userPagination.value = {
|
userPagination.value = {
|
||||||
endpoint: 'users/search',
|
endpoint: 'users/search',
|
||||||
limit: 10,
|
limit: 10,
|
||||||
|
offsetMode: true,
|
||||||
params: {
|
params: {
|
||||||
query: query,
|
query: query,
|
||||||
origin: searchOrigin.value,
|
origin: searchOrigin.value,
|
||||||
|
|
|
@ -24,7 +24,13 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
<XRaw v-else-if="tab === 'raw'" key="raw" :user="user"/>
|
<XRaw v-else-if="tab === 'raw'" key="raw" :user="user"/>
|
||||||
</MkHorizontalSwipe>
|
</MkHorizontalSwipe>
|
||||||
</div>
|
</div>
|
||||||
<MkError v-else-if="error" @retry="fetchUser()"/>
|
<div v-else-if="error">
|
||||||
|
<MkError @retry="fetchUser()"/>
|
||||||
|
</div>
|
||||||
|
<div v-else-if="userstatus">
|
||||||
|
<MkUserNotFound v-if="userstatus === 'notfound'"/>
|
||||||
|
<MkUserSuspended v-else-if="userstatus === 'suspended'"/>
|
||||||
|
</div>
|
||||||
<MkLoading v-else/>
|
<MkLoading v-else/>
|
||||||
</div>
|
</div>
|
||||||
</MkStickyContainer>
|
</MkStickyContainer>
|
||||||
|
@ -38,6 +44,8 @@ import { misskeyApi } from '@/scripts/misskey-api.js';
|
||||||
import { definePageMetadata } from '@/scripts/page-metadata.js';
|
import { definePageMetadata } from '@/scripts/page-metadata.js';
|
||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
import { $i } from '@/account.js';
|
import { $i } from '@/account.js';
|
||||||
|
import MkUserNotFound from '@/components/MkUserNotFound.vue';
|
||||||
|
import MkUserSuspended from '@/components/MkUserSuspended.vue';
|
||||||
import MkHorizontalSwipe from '@/components/MkHorizontalSwipe.vue';
|
import MkHorizontalSwipe from '@/components/MkHorizontalSwipe.vue';
|
||||||
|
|
||||||
const XHome = defineAsyncComponent(() => import('./home.vue'));
|
const XHome = defineAsyncComponent(() => import('./home.vue'));
|
||||||
|
@ -62,7 +70,8 @@ const props = withDefaults(defineProps<{
|
||||||
const tab = ref(props.page);
|
const tab = ref(props.page);
|
||||||
|
|
||||||
const user = ref<null | Misskey.entities.UserDetailed>(null);
|
const user = ref<null | Misskey.entities.UserDetailed>(null);
|
||||||
const error = ref<any>(null);
|
const error = ref<null | any>(null);
|
||||||
|
const userstatus = ref<null | any>(null);
|
||||||
|
|
||||||
function fetchUser(): void {
|
function fetchUser(): void {
|
||||||
if (props.acct == null) return;
|
if (props.acct == null) return;
|
||||||
|
@ -70,7 +79,13 @@ function fetchUser(): void {
|
||||||
misskeyApi('users/show', Misskey.acct.parse(props.acct)).then(u => {
|
misskeyApi('users/show', Misskey.acct.parse(props.acct)).then(u => {
|
||||||
user.value = u;
|
user.value = u;
|
||||||
}).catch(err => {
|
}).catch(err => {
|
||||||
|
if (err.id && err.id === '4362f8dc-731f-4ad8-a694-be5a88922a24') { // User not found
|
||||||
|
userstatus.value = 'notfound';
|
||||||
|
} else if (err.id && err.id === 'c1e1b0d6-2b7c-4c1d-9f1d-2d3d6e8d7e7f') { // User suspended
|
||||||
|
userstatus.value = 'suspended';
|
||||||
|
} else {
|
||||||
error.value = err;
|
error.value = err;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -52,6 +52,7 @@ const devConfig = {
|
||||||
'/bios': httpUrl,
|
'/bios': httpUrl,
|
||||||
'/cli': httpUrl,
|
'/cli': httpUrl,
|
||||||
'/inbox': httpUrl,
|
'/inbox': httpUrl,
|
||||||
|
'/emoji/': httpUrl,
|
||||||
'/notes': {
|
'/notes': {
|
||||||
target: httpUrl,
|
target: httpUrl,
|
||||||
headers: {
|
headers: {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue