feat: メールアドレスを使用してユーザー名を割り出す機能

Resolve #10158
This commit is contained in:
syuilo 2023-11-14 07:58:18 +09:00
parent a059dbe41b
commit 2d2eefe3d4
6 changed files with 102 additions and 6 deletions

View file

@ -15,7 +15,7 @@
## 2023.x.x (unreleased) ## 2023.x.x (unreleased)
### General ### General
- - Feat: コントロールパネルの「照会」から、入力されたメールアドレスを持つユーザーを検索できるようになりました
### Client ### Client
- Fix: アイコンデコレーションが複数の場所で見切れている問題を修正 - Fix: アイコンデコレーションが複数の場所で見切れている問題を修正

View file

@ -10,6 +10,7 @@ import * as ep___admin_meta from './endpoints/admin/meta.js';
import * as ep___admin_abuseUserReports from './endpoints/admin/abuse-user-reports.js'; import * as ep___admin_abuseUserReports from './endpoints/admin/abuse-user-reports.js';
import * as ep___admin_accounts_create from './endpoints/admin/accounts/create.js'; import * as ep___admin_accounts_create from './endpoints/admin/accounts/create.js';
import * as ep___admin_accounts_delete from './endpoints/admin/accounts/delete.js'; import * as ep___admin_accounts_delete from './endpoints/admin/accounts/delete.js';
import * as ep___admin_accounts_findByEmail from './endpoints/admin/accounts/find-by-email.js';
import * as ep___admin_ad_create from './endpoints/admin/ad/create.js'; import * as ep___admin_ad_create from './endpoints/admin/ad/create.js';
import * as ep___admin_ad_delete from './endpoints/admin/ad/delete.js'; import * as ep___admin_ad_delete from './endpoints/admin/ad/delete.js';
import * as ep___admin_ad_list from './endpoints/admin/ad/list.js'; import * as ep___admin_ad_list from './endpoints/admin/ad/list.js';
@ -368,6 +369,7 @@ const $admin_meta: Provider = { provide: 'ep:admin/meta', useClass: ep___admin_m
const $admin_abuseUserReports: Provider = { provide: 'ep:admin/abuse-user-reports', useClass: ep___admin_abuseUserReports.default }; const $admin_abuseUserReports: Provider = { provide: 'ep:admin/abuse-user-reports', useClass: ep___admin_abuseUserReports.default };
const $admin_accounts_create: Provider = { provide: 'ep:admin/accounts/create', useClass: ep___admin_accounts_create.default }; const $admin_accounts_create: Provider = { provide: 'ep:admin/accounts/create', useClass: ep___admin_accounts_create.default };
const $admin_accounts_delete: Provider = { provide: 'ep:admin/accounts/delete', useClass: ep___admin_accounts_delete.default }; const $admin_accounts_delete: Provider = { provide: 'ep:admin/accounts/delete', useClass: ep___admin_accounts_delete.default };
const $admin_accounts_findByEmail: Provider = { provide: 'ep:admin/accounts/find-by-email', useClass: ep___admin_accounts_findByEmail.default };
const $admin_ad_create: Provider = { provide: 'ep:admin/ad/create', useClass: ep___admin_ad_create.default }; const $admin_ad_create: Provider = { provide: 'ep:admin/ad/create', useClass: ep___admin_ad_create.default };
const $admin_ad_delete: Provider = { provide: 'ep:admin/ad/delete', useClass: ep___admin_ad_delete.default }; const $admin_ad_delete: Provider = { provide: 'ep:admin/ad/delete', useClass: ep___admin_ad_delete.default };
const $admin_ad_list: Provider = { provide: 'ep:admin/ad/list', useClass: ep___admin_ad_list.default }; const $admin_ad_list: Provider = { provide: 'ep:admin/ad/list', useClass: ep___admin_ad_list.default };
@ -730,6 +732,7 @@ const $retention: Provider = { provide: 'ep:retention', useClass: ep___retention
$admin_abuseUserReports, $admin_abuseUserReports,
$admin_accounts_create, $admin_accounts_create,
$admin_accounts_delete, $admin_accounts_delete,
$admin_accounts_findByEmail,
$admin_ad_create, $admin_ad_create,
$admin_ad_delete, $admin_ad_delete,
$admin_ad_list, $admin_ad_list,
@ -1086,6 +1089,7 @@ const $retention: Provider = { provide: 'ep:retention', useClass: ep___retention
$admin_abuseUserReports, $admin_abuseUserReports,
$admin_accounts_create, $admin_accounts_create,
$admin_accounts_delete, $admin_accounts_delete,
$admin_accounts_findByEmail,
$admin_ad_create, $admin_ad_create,
$admin_ad_delete, $admin_ad_delete,
$admin_ad_list, $admin_ad_list,

View file

@ -10,6 +10,7 @@ import * as ep___admin_meta from './endpoints/admin/meta.js';
import * as ep___admin_abuseUserReports from './endpoints/admin/abuse-user-reports.js'; import * as ep___admin_abuseUserReports from './endpoints/admin/abuse-user-reports.js';
import * as ep___admin_accounts_create from './endpoints/admin/accounts/create.js'; import * as ep___admin_accounts_create from './endpoints/admin/accounts/create.js';
import * as ep___admin_accounts_delete from './endpoints/admin/accounts/delete.js'; import * as ep___admin_accounts_delete from './endpoints/admin/accounts/delete.js';
import * as ep___admin_accounts_findByEmail from './endpoints/admin/accounts/find-by-email.js';
import * as ep___admin_ad_create from './endpoints/admin/ad/create.js'; import * as ep___admin_ad_create from './endpoints/admin/ad/create.js';
import * as ep___admin_ad_delete from './endpoints/admin/ad/delete.js'; import * as ep___admin_ad_delete from './endpoints/admin/ad/delete.js';
import * as ep___admin_ad_list from './endpoints/admin/ad/list.js'; import * as ep___admin_ad_list from './endpoints/admin/ad/list.js';
@ -366,6 +367,7 @@ const eps = [
['admin/abuse-user-reports', ep___admin_abuseUserReports], ['admin/abuse-user-reports', ep___admin_abuseUserReports],
['admin/accounts/create', ep___admin_accounts_create], ['admin/accounts/create', ep___admin_accounts_create],
['admin/accounts/delete', ep___admin_accounts_delete], ['admin/accounts/delete', ep___admin_accounts_delete],
['admin/accounts/find-by-email', ep___admin_accounts_findByEmail],
['admin/ad/create', ep___admin_ad_create], ['admin/ad/create', ep___admin_ad_create],
['admin/ad/delete', ep___admin_ad_delete], ['admin/ad/delete', ep___admin_ad_delete],
['admin/ad/list', ep___admin_ad_list], ['admin/ad/list', ep___admin_ad_list],

View file

@ -0,0 +1,61 @@
/*
* SPDX-FileCopyrightText: syuilo and other misskey contributors
* SPDX-License-Identifier: AGPL-3.0-only
*/
import { Inject, Injectable } from '@nestjs/common';
import { Endpoint } from '@/server/api/endpoint-base.js';
import type { UserProfilesRepository } from '@/models/_.js';
import { DI } from '@/di-symbols.js';
import { UserEntityService } from '@/core/entities/UserEntityService.js';
import { ApiError } from '@/server/api/error.js';
export const meta = {
tags: ['admin'],
requireCredential: true,
requireAdmin: true,
errors: {
userNotFound: {
message: 'No such user who has the email address.',
code: 'USER_NOT_FOUND',
id: 'cb865949-8af5-4062-a88c-ef55e8786d1d',
},
},
} as const;
export const paramDef = {
type: 'object',
properties: {
email: { type: 'string' },
},
required: ['email'],
} as const;
@Injectable()
export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-disable-line import/no-default-export
constructor(
@Inject(DI.userProfilesRepository)
private userProfilesRepository: UserProfilesRepository,
private userEntityService: UserEntityService,
) {
super(meta, paramDef, async (ps, me) => {
const profile = await this.userProfilesRepository.findOne({
where: { email: ps.email },
relations: ['user'],
});
if (profile == null) {
throw new ApiError(meta.errors.userNotFound);
}
const res = await this.userEntityService.pack(profile.user!, null, {
detail: true,
});
return res;
});
}
}

View file

@ -34,7 +34,7 @@ import MkSuperMenu from '@/components/MkSuperMenu.vue';
import MkInfo from '@/components/MkInfo.vue'; import MkInfo from '@/components/MkInfo.vue';
import { instance } from '@/instance.js'; import { instance } from '@/instance.js';
import * as os from '@/os.js'; import * as os from '@/os.js';
import { lookupUser } from '@/scripts/lookup-user.js'; import { lookupUser, lookupUserByEmail } from '@/scripts/lookup-user.js';
import { useRouter } from '@/router.js'; import { useRouter } from '@/router.js';
import { definePageMetadata, provideMetadataReceiver } from '@/scripts/page-metadata.js'; import { definePageMetadata, provideMetadataReceiver } from '@/scripts/page-metadata.js';
@ -264,7 +264,7 @@ provideMetadataReceiver((info) => {
} }
}); });
const invite = () => { function invite() {
os.api('admin/invite/create').then(x => { os.api('admin/invite/create').then(x => {
os.alert({ os.alert({
type: 'info', type: 'info',
@ -276,15 +276,21 @@ const invite = () => {
text: err, text: err,
}); });
}); });
}; }
const lookup = (ev) => { function lookup(ev: MouseEvent) {
os.popupMenu([{ os.popupMenu([{
text: i18n.ts.user, text: i18n.ts.user,
icon: 'ti ti-user', icon: 'ti ti-user',
action: () => { action: () => {
lookupUser(); lookupUser();
}, },
}, {
text: `${i18n.ts.user} (${i18n.ts.email})`,
icon: 'ti ti-user',
action: () => {
lookupUserByEmail();
},
}, { }, {
text: i18n.ts.note, text: i18n.ts.note,
icon: 'ti ti-pencil', icon: 'ti ti-pencil',
@ -304,7 +310,7 @@ const lookup = (ev) => {
alert('TODO'); alert('TODO');
}, },
}], ev.currentTarget ?? ev.target); }], ev.currentTarget ?? ev.target);
}; }
const headerActions = $computed(() => []); const headerActions = $computed(() => []);

View file

@ -39,3 +39,26 @@ export async function lookupUser() {
notFound(); notFound();
}); });
} }
export async function lookupUserByEmail() {
const { canceled, result } = await os.inputText({
title: i18n.ts.emailAddress,
type: 'email',
});
if (canceled) return;
try {
const user = await os.apiWithDialog('admin/accounts/find-by-email', { email: result });
os.pageWindow(`/admin/user/${user.id}`);
} catch (err) {
if (err.code === 'USER_NOT_FOUND') {
os.alert({
type: 'error',
text: i18n.ts.noSuchUser,
});
} else {
throw err;
}
}
}