Merged PR 63: API実装(メール認証)
## 概要 [Task1497: API実装(メール認証)](https://paruru.nds-tyo.co.jp:8443/tfs/ReciproCollection/fa4924a4-d079-4fab-9fb5-a9a11eb205f0/_workitems/edit/1497) - メール認証APIとテストを実装しました。 - IDトークンの型を現状と合わせて修正しました - `family_name`と`given_name`を削除しました。 - auth.serviceのテストも併せて修正しました。 - テストケースのIDトークンを環境変数の鍵で生成するように修正しました。 ## レビューポイント - DBのユーザを検証済みにする処理について、トランザクション内で取得と更新をしていますがトランザクションの使い方として問題ないでしょうか? - 本APIで使用するカスタムエラーを`common/error/types`に暫定的においていますがどこに配置するのが適切でしょうか? - `common/error/types`に配置する、もしくは`common`配下にカスタムエラー用のフォルダを作成してその下に配置するのが良いかと考えています。 - テストのモックでエラーを発生させる際に、テストケース内でエラーを設定していますがモックファイル内でエラー用のモックを設定するべきでしょうか? ## UIの変更 - なし ## 動作確認状況 - ローカルで確認 - テストが通ることを確認
This commit is contained in:
parent
ee2e8dbd5d
commit
bd4aaa8ae1
@ -14,6 +14,7 @@
|
||||
"start:dev": "nest start --watch",
|
||||
"start:debug": "nest start --debug --watch",
|
||||
"start:prod": "node dist/main",
|
||||
"tc": "tsc --noEmit",
|
||||
"lint": "eslint \"{src,apps,libs,test}/**/*.ts\"",
|
||||
"lint:fix": "eslint \"{src,apps,libs,test}/**/*.ts\" --fix",
|
||||
"test": "jest",
|
||||
|
||||
@ -21,5 +21,6 @@ export const ErrorCodes = [
|
||||
'E000105', // トークン発行元エラー
|
||||
'E000106', // トークンアルゴリズムエラー
|
||||
'E010201', // 未認証ユーザエラー
|
||||
'E010202', // 認証済ユーザエラー
|
||||
'E010301', // メールアドレス登録済みエラー
|
||||
] as const;
|
||||
|
||||
@ -10,5 +10,6 @@ export const errors: Errors = {
|
||||
E000105: 'Token invalid issuer Error.',
|
||||
E000106: 'Token invalid algorithm Error.',
|
||||
E010201: 'Email not verified user Error.',
|
||||
E010202: 'Email already verified user Error.',
|
||||
E010301: 'This email user already created Error',
|
||||
};
|
||||
|
||||
@ -10,8 +10,6 @@ export const isIDToken = (
|
||||
if (token.emails === undefined) return false;
|
||||
if (token.exp === undefined) return false;
|
||||
if (token.iat === undefined) return false;
|
||||
if (token.family_name === undefined) return false;
|
||||
if (token.given_name === undefined) return false;
|
||||
if (token.nonce === undefined) return false;
|
||||
|
||||
return true;
|
||||
|
||||
@ -10,8 +10,6 @@ export type AccessToken = {
|
||||
|
||||
export type IDToken = {
|
||||
emails: string[];
|
||||
family_name: string;
|
||||
given_name: string;
|
||||
nonce: string;
|
||||
sub: string; // AzureAD B2C ID
|
||||
exp: number; // 有効期限
|
||||
|
||||
@ -1,13 +1,19 @@
|
||||
import { Test, TestingModule } from '@nestjs/testing';
|
||||
import { AccountsController } from './accounts.controller';
|
||||
import { AccountsService } from './accounts.service';
|
||||
|
||||
describe('AccountsController', () => {
|
||||
let controller: AccountsController;
|
||||
const mockAccountService = {};
|
||||
|
||||
beforeEach(async () => {
|
||||
const module: TestingModule = await Test.createTestingModule({
|
||||
controllers: [AccountsController],
|
||||
}).compile();
|
||||
providers: [AccountsService],
|
||||
})
|
||||
.overrideProvider(AccountsService)
|
||||
.useValue(mockAccountService)
|
||||
.compile();
|
||||
|
||||
controller = module.get<AccountsController>(AccountsController);
|
||||
});
|
||||
|
||||
@ -7,7 +7,14 @@ describe('AccountsService', () => {
|
||||
beforeEach(async () => {
|
||||
const module: TestingModule = await Test.createTestingModule({
|
||||
providers: [AccountsService],
|
||||
}).compile();
|
||||
})
|
||||
.useMocker(() => {
|
||||
return {
|
||||
createAccount: undefined,
|
||||
update: undefined,
|
||||
};
|
||||
})
|
||||
.compile();
|
||||
|
||||
service = module.get<AccountsService>(AccountsService);
|
||||
});
|
||||
|
||||
@ -1,7 +1,6 @@
|
||||
import { HttpException, HttpStatus } from '@nestjs/common';
|
||||
import { makeErrorResponse } from '../../common/error/makeErrorResponse';
|
||||
import {
|
||||
makeAdB2cServiceMock,
|
||||
makeAuthServiceMock,
|
||||
makeDefaultAdB2cMockValue,
|
||||
makeDefaultCryptoMockValue,
|
||||
@ -13,7 +12,7 @@ describe('AuthService', () => {
|
||||
const cryptoParam = makeDefaultCryptoMockValue();
|
||||
const service = await makeAuthServiceMock(adb2cParam, cryptoParam);
|
||||
const token =
|
||||
'eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImtpZCI6ImtpZCJ9.eyJleHAiOjkwMDAwMDAwMDAsIm5iZiI6MTAwMDAwMDAwMCwiaXNzIjoiaXNzdXNlciJ9.dURTqFfUc94qYNFS65xMqMT3tJi-uH8weJ5GU74F-UvhLKJmqVoNIbXCm-ASg2mZ5SxeX683q2MMrlzxNcNel-QIFTj0zWem4eLKuarsYRMTU8x27jMss0b_JkFtiy5KE2052_fLeW2aZBb4AjieIW34-c0Ol1rrih-W9Pk6ZEOwf14Ju0IAgdUw66-HuLOUprZjavvFp2rwuAC7gqEujg3wtjO7VR82NNoVv2dxByTdrzG_eOk8QKTJYBoM50ztT6WFs-qWetZIoQDxMJRA9ObfEVyJ4Bq2b4qelfuhAqbQWRNfCvqhoRPMJI6Y7-R94FuO1zg4d4Gm3J0qHj7r8Q';
|
||||
'eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6ImtpZCJ9.eyJleHAiOjkwMDAwMDAwMDAsIm5iZiI6MTAwMDAwMDAwMCwidmVyIjoiMS4wIiwiaXNzIjoiaXNzdWVyIiwic3ViIjoic3ViIiwiYXVkIjoiYXVkIiwibm9uY2UiOiJkZWZhdWx0Tm9uY2UiLCJpYXQiOjEwMDAwMDAwMDAsImF1dGhfdGltZSI6MTAwMDAwMDAwMCwiZW1haWxzIjpbInh4eEB4eC5jb20iXSwidGZwIjoic2lnbmluX3VzZXJmbG93In0.RyieW-VHsHPQOjXbbhRc307AYJOc1sq2hrcu4SW1-K0pvLlkplepxvx02a3vCwQrnBYrIP5w6HExG-S_JgW5nYyWr6DeY11mA484n9KA8GeAcAXV37StH1gfWUJvfGb4C8BaMbMM9Ix4Z9NGwKA9vjNwevfmBZnz9lQUePgv6BJNmyvCt8ElJ01O-1WODbZuojJ4xXymA1OqluzfbphPOsqWTSNmTn0emkLjjnlMQf1iwM4C_kvvr8dUCFg0_UGDfQVJnzPEKB38UqnhLnC5WacrddDwQ0kBuGKZgZ_63Q_7fOvqAZivqLK7BPmbPxi6mx3R1S9Eq2ugzpY1LfJOjA';
|
||||
|
||||
expect(await service.getVerifiedIdToken(token)).toEqual(idTokenPayload);
|
||||
});
|
||||
@ -34,7 +33,7 @@ describe('AuthService', () => {
|
||||
const cryptoParam = makeDefaultCryptoMockValue();
|
||||
const service = await makeAuthServiceMock(adb2cParam, cryptoParam);
|
||||
const token =
|
||||
'eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImtpZCI6ImtpZCJ9.eyJleHAiOjEwMDAwMDAwMDAsIm5iZiI6MTAwMDAwMDAwMCwiaXNzIjoiaXNzdWVyIn0.pk9-POXmo3ie7wfqizRr2NSX7YGEJed3krdMImzKp5qeRfsEJwM6zTSzjL_gbLQyMEDg3IoyWzVVUha4sdPcummtt8gJ6N25s_H9taFY-xJjx_-wmttGQvXD44apyUF_c_Xg0l7MzNQEqpnzsLdDcBITSN-Rk-bT_n9U4dxhYaWukOPfAPf7DzSxT9TCpTaCTPIAKp2JXVU41J9uv5WklhNjMSv9L5jWT-IstEC71-DO6jD6yFpAOLIG6Aq-C7rQolt_Cny9qKugu6hd7_Aj-YrW9773khUOyFotJ7Qs9g-qSEMy7M9ljvai2eu5Otfja3hlS5wF1VH_ENsXye6C0A';
|
||||
'eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6ImtpZCJ9.eyJleHAiOjEwMDAwMDAwMDAsIm5iZiI6MTAwMDAwMDAwMCwidmVyIjoiMS4wIiwiaXNzIjoiaXNzdWVyIiwic3ViIjoic3ViIiwiYXVkIjoiYXVkIiwibm9uY2UiOiJkZWZhdWx0Tm9uY2UiLCJpYXQiOjEwMDAwMDAwMDAsImF1dGhfdGltZSI6MTAwMDAwMDAwMCwiZW1haWxzIjpbInh4eEB4eC5jb20iXSwidGZwIjoic2lnbmluX3VzZXJmbG93In0.r9x61Mf1S2qFgU_QDKB6tRFBmTQXyOEtpoacOlL_bQzFz1t3GsxMy6SJIvQQ-LtDgylQ1UCdMFiRuy4V8nyLuME0fR-9IkKsboGvwllHB_Isai3XFoja0jpDHMVby1m0B3Z9xOTb7YsaQGyEH-qs1TtnRm6Ny98h4Po80nK8HGefQZHBOlfQN_B1LiHwI3nLXV18NL-4olKXj2NloNRYtnWM0PaqDQcGvZFaSNvtrSYpo9ddD906QWDGVOQ7WvGSUgdNCoxX8Lb3r2-VSj6n84jpb-Y1Fz-GhLluNglAsBhasnJfUIvCIO3iG5pRyTYjHFAVHmzjr8xMOmhS3s41Jw';
|
||||
|
||||
await expect(service.getVerifiedIdToken(token)).rejects.toEqual(
|
||||
new HttpException(makeErrorResponse('E000102'), HttpStatus.UNAUTHORIZED),
|
||||
@ -46,7 +45,7 @@ describe('AuthService', () => {
|
||||
const cryptoParam = makeDefaultCryptoMockValue();
|
||||
const service = await makeAuthServiceMock(adb2cParam, cryptoParam);
|
||||
const token =
|
||||
'eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImtpZCI6ImtpZCJ9.eyJleHAiOjkwMDAwMDAwMDAsIm5iZiI6OTAwMDAwMDAwMCwiaXNzIjoiaXNzdWVyIn0.pSk3U8Wn_XTm6KxvdQpqQuGROjanLxLGsnRGg35jO4iPVysHKVWya7Leik3aTtK8lGCSoapodQoV4EXbP5CzBf5O83l9tKaF2pwEO_C9QePlLJIJMaCmqRFrr1ozcVFQNwYAr81KNmXBuEEG5duT36Fk2A9-PLDtwg816J4nMEnd1umgCSRTKOdxh265ybDxX1Pe8KDtzlCi8Wjj-lhFwxskpKD3xlFl2plhW9_P7eq-DJXtm1fvLk27zxwOq8uaaxu6sfXoeu1D4qi4aZ0MF-5eaOezc8KH-aYgU9o5yQCZH6tJJDrZvzi7GAFTd-c952V9jgPZpifEoDMRJXS5zA';
|
||||
'eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6ImtpZCJ9.eyJleHAiOjkwMDAwMDAwMDAsIm5iZiI6OTAwMDAwMDAwMCwidmVyIjoiMS4wIiwiaXNzIjoiaXNzdWVyIiwic3ViIjoic3ViIiwiYXVkIjoiYXVkIiwibm9uY2UiOiJkZWZhdWx0Tm9uY2UiLCJpYXQiOjEwMDAwMDAwMDAsImF1dGhfdGltZSI6MTAwMDAwMDAwMCwiZW1haWxzIjpbInh4eEB4eC5jb20iXSwidGZwIjoic2lnbmluX3VzZXJmbG93In0.fX2Gbd7fDPNE3Lw-xbum_5CVqQYqEmMhv_v5u8A-U81pmPD2P5rsJEJx66ns1taFLVaE3j9_OzotxrqjqqQqbACkagGcN5wvA3_ZIxyqmhrKYFJc53ZcO7d0pFWiQlluNBI_pnFNDlSMB2Ut8Th5aiPy2uamBM9wC99bcjo7HkHvTKBf6ljU6rPKoD51qGDWqNxjoH-hdSJ29wprvyxyk_yX6dp-cxXUj5DIgXYQuIZF71rdiPtGlAiyTBns8rS2QlEEXapZVlvYrK4mkpUXVDA7ifD8q6gAC2BStqHeys7CGp2MbV4ZwKCVbAUbMs6Tboh8rADZvQhuTEq7qlhZ-w';
|
||||
|
||||
await expect(service.getVerifiedIdToken(token)).rejects.toEqual(
|
||||
new HttpException(makeErrorResponse('E000103'), HttpStatus.UNAUTHORIZED),
|
||||
@ -58,7 +57,7 @@ describe('AuthService', () => {
|
||||
const cryptoParam = makeDefaultCryptoMockValue();
|
||||
const service = await makeAuthServiceMock(adb2cParam, cryptoParam);
|
||||
const token =
|
||||
'eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImtpZCI6ImtpZCJ9.eyJleHAiOjkwMDAwMDAwMDAsIm5iZiI6MTAwMDAwMDAwMCwiaXNzIjoiaXNzdWVyIn0.sign';
|
||||
'eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6ImtpZCJ9.eyJleHAiOjkwMDAwMDAwMDAsIm5iZiI6MTAwMDAwMDAwMCwidmVyIjoiMS4wIiwiaXNzIjoiaXNzdXNlciIsInN1YiI6InN1YiIsImF1ZCI6ImF1ZCIsIm5vbmNlIjoiZGVmYXVsdE5vbmNlIiwiaWF0IjoxMDAwMDAwMDAwLCJhdXRoX3RpbWUiOjEwMDAwMDAwMDAsImVtYWlscyI6WyJ4eHhAeHguY29tIl0sInRmcCI6InNpZ25pbl91c2VyZmxvdyJ9.sign';
|
||||
|
||||
await expect(service.getVerifiedIdToken(token)).rejects.toEqual(
|
||||
new HttpException(makeErrorResponse('E000104'), HttpStatus.UNAUTHORIZED),
|
||||
@ -70,7 +69,7 @@ describe('AuthService', () => {
|
||||
const cryptoParam = makeDefaultCryptoMockValue();
|
||||
const service = await makeAuthServiceMock(adb2cParam, cryptoParam);
|
||||
const token =
|
||||
'eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImtpZCI6ImtpZCJ9.eyJleHAiOjkwMDAwMDAwMDAsIm5iZiI6MTAwMDAwMDAwMCwiaXNzIjoiaW52YWxpZCJ9.jmwBBc2r55YOr88W_4aRzFccmtmQfQRLob7YGM4bOPMGK-ExXJQG24CiMpODZEvVTtQKucEd2cBB6zzLYGCiKRHig8iM_EV57klMwKrczdL2ov8Hc3IyA407idDxDi0KyyveEctxEUdl3PgbY54CVc6URhUAzGdcQ2mKMRVe-Zxb7CrFYqwiHUCmCnSRFUYj_9kkI3epkdsXPsLyDApDEbLEeD1ztnoyYrbfmdce6flpf-h1r2VK4dMz8m4GMOLQHM9gWSzRUkUsN3hGOKTofUxCKC4CArfSP1vZ5k9FZrjqOZn1m6bxKalCox2n96GqLtuFV3-sOTnCqgHj0fQEJA';
|
||||
'eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6ImtpZCJ9.eyJleHAiOjkwMDAwMDAwMDAsIm5iZiI6MTAwMDAwMDAwMCwidmVyIjoiMS4wIiwiaXNzIjoiaW52bGlkX2lzc3VlciIsInN1YiI6InN1YiIsImF1ZCI6ImF1ZCIsIm5vbmNlIjoiZGVmYXVsdE5vbmNlIiwiaWF0IjoxMDAwMDAwMDAwLCJhdXRoX3RpbWUiOjEwMDAwMDAwMDAsImVtYWlscyI6WyJ4eHhAeHguY29tIl0sInRmcCI6InNpZ25pbl91c2VyZmxvdyJ9.0bp3e1mDG78PX3lo8zgOLXGenIqG_Vi6kw7CbwauAQM-cnUZ_aVCoJ_dAv_QmPElOQKcCkRrAvAZ91FwuHDlBGuuDqx8OwqN0VaD-4NPouoAswj-9HNvBm8gUn-pGaXkvWt_72UdCJavZJjDj_RHur8y8kFt5Qeab3mUP2x-uNcV2Q2x3M_IIfcRiIZkRZm_azKfiVIy7tzoUFLDss97y938aR8imMVxazoSQvj7RWIWylgeRr9yVt7qYl18cnEVL0IGtslFbqhfNsiEmRCMsttm5kXs7E9B0bhhUe_xbJW9VumQ6G7dgMrswevp_jRgbpWJoZsgErtqIRl9Tc9ikA';
|
||||
|
||||
await expect(service.getVerifiedIdToken(token)).rejects.toEqual(
|
||||
new HttpException(makeErrorResponse('E000105'), HttpStatus.UNAUTHORIZED),
|
||||
@ -83,7 +82,7 @@ describe('AuthService', () => {
|
||||
const cryptoParam = makeDefaultCryptoMockValue();
|
||||
const service = await makeAuthServiceMock(adb2cParam, cryptoParam);
|
||||
const token =
|
||||
'eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImtpZCI6ImtpZCJ9.eyJleHAiOjkwMDAwMDAwMDAsIm5iZiI6MTAwMDAwMDAwMCwiaXNzIjoiaXNzdXNlciJ9.dURTqFfUc94qYNFS65xMqMT3tJi-uH8weJ5GU74F-UvhLKJmqVoNIbXCm-ASg2mZ5SxeX683q2MMrlzxNcNel-QIFTj0zWem4eLKuarsYRMTU8x27jMss0b_JkFtiy5KE2052_fLeW2aZBb4AjieIW34-c0Ol1rrih-W9Pk6ZEOwf14Ju0IAgdUw66-HuLOUprZjavvFp2rwuAC7gqEujg3wtjO7VR82NNoVv2dxByTdrzG_eOk8QKTJYBoM50ztT6WFs-qWetZIoQDxMJRA9ObfEVyJ4Bq2b4qelfuhAqbQWRNfCvqhoRPMJI6Y7-R94FuO1zg4d4Gm3J0qHj7r8Q';
|
||||
'eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6ImtpZCJ9.eyJleHAiOjkwMDAwMDAwMDAsIm5iZiI6MTAwMDAwMDAwMCwidmVyIjoiMS4wIiwiaXNzIjoiaXNzdWVyIiwic3ViIjoic3ViIiwiYXVkIjoiYXVkIiwibm9uY2UiOiJkZWZhdWx0Tm9uY2UiLCJpYXQiOjEwMDAwMDAwMDAsImF1dGhfdGltZSI6MTAwMDAwMDAwMCwiZW1haWxzIjpbInh4eEB4eC5jb20iXSwidGZwIjoic2lnbmluX3VzZXJmbG93In0.RyieW-VHsHPQOjXbbhRc307AYJOc1sq2hrcu4SW1-K0pvLlkplepxvx02a3vCwQrnBYrIP5w6HExG-S_JgW5nYyWr6DeY11mA484n9KA8GeAcAXV37StH1gfWUJvfGb4C8BaMbMM9Ix4Z9NGwKA9vjNwevfmBZnz9lQUePgv6BJNmyvCt8ElJ01O-1WODbZuojJ4xXymA1OqluzfbphPOsqWTSNmTn0emkLjjnlMQf1iwM4C_kvvr8dUCFg0_UGDfQVJnzPEKB38UqnhLnC5WacrddDwQ0kBuGKZgZ_63Q_7fOvqAZivqLK7BPmbPxi6mx3R1S9Eq2ugzpY1LfJOjA';
|
||||
|
||||
await expect(service.getVerifiedIdToken(token)).rejects.toEqual(
|
||||
new HttpException(
|
||||
@ -98,7 +97,7 @@ describe('AuthService', () => {
|
||||
const cryptoParam = makeDefaultCryptoMockValue();
|
||||
const service = await makeAuthServiceMock(adb2cParam, cryptoParam);
|
||||
const token =
|
||||
'eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImtpZCI6ImtpZCJ9.eyJleHAiOjkwMDAwMDAwMDAsIm5iZiI6MTAwMDAwMDAwMCwiaXNzIjoiaXNzdXNlciJ9.dURTqFfUc94qYNFS65xMqMT3tJi-uH8weJ5GU74F-UvhLKJmqVoNIbXCm-ASg2mZ5SxeX683q2MMrlzxNcNel-QIFTj0zWem4eLKuarsYRMTU8x27jMss0b_JkFtiy5KE2052_fLeW2aZBb4AjieIW34-c0Ol1rrih-W9Pk6ZEOwf14Ju0IAgdUw66-HuLOUprZjavvFp2rwuAC7gqEujg3wtjO7VR82NNoVv2dxByTdrzG_eOk8QKTJYBoM50ztT6WFs-qWetZIoQDxMJRA9ObfEVyJ4Bq2b4qelfuhAqbQWRNfCvqhoRPMJI6Y7-R94FuO1zg4d4Gm3J0qHj7r8Q';
|
||||
'eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6ImtpZCJ9.eyJleHAiOjkwMDAwMDAwMDAsIm5iZiI6MTAwMDAwMDAwMCwidmVyIjoiMS4wIiwiaXNzIjoiaXNzdWVyIiwic3ViIjoic3ViIiwiYXVkIjoiYXVkIiwibm9uY2UiOiJkZWZhdWx0Tm9uY2UiLCJpYXQiOjEwMDAwMDAwMDAsImF1dGhfdGltZSI6MTAwMDAwMDAwMCwiZW1haWxzIjpbInh4eEB4eC5jb20iXSwidGZwIjoic2lnbmluX3VzZXJmbG93In0.RyieW-VHsHPQOjXbbhRc307AYJOc1sq2hrcu4SW1-K0pvLlkplepxvx02a3vCwQrnBYrIP5w6HExG-S_JgW5nYyWr6DeY11mA484n9KA8GeAcAXV37StH1gfWUJvfGb4C8BaMbMM9Ix4Z9NGwKA9vjNwevfmBZnz9lQUePgv6BJNmyvCt8ElJ01O-1WODbZuojJ4xXymA1OqluzfbphPOsqWTSNmTn0emkLjjnlMQf1iwM4C_kvvr8dUCFg0_UGDfQVJnzPEKB38UqnhLnC5WacrddDwQ0kBuGKZgZ_63Q_7fOvqAZivqLK7BPmbPxi6mx3R1S9Eq2ugzpY1LfJOjA';
|
||||
|
||||
await expect(service.getVerifiedIdToken(token)).rejects.toEqual(
|
||||
new HttpException(
|
||||
@ -116,7 +115,7 @@ describe('AuthService', () => {
|
||||
const cryptoParam = makeDefaultCryptoMockValue();
|
||||
const service = await makeAuthServiceMock(adb2cParam, cryptoParam);
|
||||
const token =
|
||||
'eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImtpZCI6ImtpZCJ9.eyJleHAiOjkwMDAwMDAwMDAsIm5iZiI6MTAwMDAwMDAwMCwiaXNzIjoiaXNzdXNlciJ9.dURTqFfUc94qYNFS65xMqMT3tJi-uH8weJ5GU74F-UvhLKJmqVoNIbXCm-ASg2mZ5SxeX683q2MMrlzxNcNel-QIFTj0zWem4eLKuarsYRMTU8x27jMss0b_JkFtiy5KE2052_fLeW2aZBb4AjieIW34-c0Ol1rrih-W9Pk6ZEOwf14Ju0IAgdUw66-HuLOUprZjavvFp2rwuAC7gqEujg3wtjO7VR82NNoVv2dxByTdrzG_eOk8QKTJYBoM50ztT6WFs-qWetZIoQDxMJRA9ObfEVyJ4Bq2b4qelfuhAqbQWRNfCvqhoRPMJI6Y7-R94FuO1zg4d4Gm3J0qHj7r8Q';
|
||||
'eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6ImtpZCJ9.eyJleHAiOjkwMDAwMDAwMDAsIm5iZiI6MTAwMDAwMDAwMCwidmVyIjoiMS4wIiwiaXNzIjoiaXNzdWVyIiwic3ViIjoic3ViIiwiYXVkIjoiYXVkIiwibm9uY2UiOiJkZWZhdWx0Tm9uY2UiLCJpYXQiOjEwMDAwMDAwMDAsImF1dGhfdGltZSI6MTAwMDAwMDAwMCwiZW1haWxzIjpbInh4eEB4eC5jb20iXSwidGZwIjoic2lnbmluX3VzZXJmbG93In0.RyieW-VHsHPQOjXbbhRc307AYJOc1sq2hrcu4SW1-K0pvLlkplepxvx02a3vCwQrnBYrIP5w6HExG-S_JgW5nYyWr6DeY11mA484n9KA8GeAcAXV37StH1gfWUJvfGb4C8BaMbMM9Ix4Z9NGwKA9vjNwevfmBZnz9lQUePgv6BJNmyvCt8ElJ01O-1WODbZuojJ4xXymA1OqluzfbphPOsqWTSNmTn0emkLjjnlMQf1iwM4C_kvvr8dUCFg0_UGDfQVJnzPEKB38UqnhLnC5WacrddDwQ0kBuGKZgZ_63Q_7fOvqAZivqLK7BPmbPxi6mx3R1S9Eq2ugzpY1LfJOjA';
|
||||
|
||||
await expect(service.getVerifiedIdToken(token)).rejects.toEqual(
|
||||
new HttpException(
|
||||
@ -130,5 +129,13 @@ describe('AuthService', () => {
|
||||
const idTokenPayload = {
|
||||
exp: 9000000000,
|
||||
nbf: 1000000000,
|
||||
iss: 'issuser',
|
||||
ver: '1.0',
|
||||
iss: 'issuer',
|
||||
sub: 'sub',
|
||||
aud: 'aud',
|
||||
nonce: 'defaultNonce',
|
||||
iat: 1000000000,
|
||||
auth_time: 1000000000,
|
||||
emails: ['xxx@xx.com'],
|
||||
tfp: 'signin_userflow',
|
||||
};
|
||||
|
||||
@ -3,6 +3,8 @@ import { AdB2cService } from '../../../gateways/adb2c/adb2c.service';
|
||||
import { CryptoService } from '../../../gateways/crypto/crypto.service';
|
||||
import { JwkSignKey, B2cMetadata } from '../../../common/token';
|
||||
import { AuthService } from '../auth.service';
|
||||
import { ConfigService } from '@nestjs/config';
|
||||
import { UsersRepositoryService } from '../../../repositories/users/users.repository.service';
|
||||
|
||||
export type AdB2cMockValue = {
|
||||
getMetaData: B2cMetadata | Error;
|
||||
@ -26,6 +28,10 @@ export const makeAuthServiceMock = async (
|
||||
return makeAdB2cServiceMock(adB2cMockValue);
|
||||
case CryptoService:
|
||||
return makeCryptoServiceMock(cryptoMockValue);
|
||||
case ConfigService:
|
||||
return {};
|
||||
case UsersRepositoryService:
|
||||
return {};
|
||||
}
|
||||
})
|
||||
.compile();
|
||||
@ -36,7 +42,7 @@ export const makeAuthServiceMock = async (
|
||||
export const makeDefaultAdB2cMockValue = (): AdB2cMockValue => {
|
||||
return {
|
||||
getMetaData: {
|
||||
issuer: 'issuser',
|
||||
issuer: 'issuer',
|
||||
},
|
||||
getSignKeySets: [
|
||||
{
|
||||
@ -72,13 +78,13 @@ export const makeDefaultCryptoMockValue = (): CryptoMockValue => {
|
||||
return {
|
||||
getPublicKeyFromJwk: [
|
||||
'-----BEGIN PUBLIC KEY-----',
|
||||
'MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsTVLNpW0/FzVCU7qo1DD',
|
||||
'jOkYWx6s/jE56YOOc3UzaaG/zb1FGyfRoUUgS4DnQxPNz9oM63RpQlhvG6UCwx23',
|
||||
'tL7p3PS0ZCsLeggcyLctbJAzLy/afF9ABoreorqp/AaEs+Vdwbykb+M+nB2Sxsc5',
|
||||
'7Tli2x8NiOZr5dafs3vMuIIKNsBaFAugFrd2ApxXR04jBRAorZRRFPtECE7D+hxD',
|
||||
'alw5DCd0mmdY0vrbRsgkbej0ZzzqzukJVXTMjy1YScqi3I9gLx2hLVmpK76Gtxn2',
|
||||
'1AIcn8P3rKZmDyPH+9KNfWC8+ubF+VuY6nItlCgiSyTKErAp6M9pyRHKbPpdUM3a',
|
||||
'IQIDAQAB',
|
||||
'MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA5IZZNgDew9eGmuFTezwd',
|
||||
'HYLSaJvUPPIKYoiOeVLD1paWNI517Vkaoh0ngprcKOdv6T1N07V4igK7mOim2zY3',
|
||||
'yCTR6wcWR3PfFJrl9vh5SOo79koZoJb27YiM4jtxfx2dezzp0T2GoNR5rRolPUbW',
|
||||
'FJXnDe0DVXYXpJLb4LAlF2XAyYX0SYKUVUsJnzm5k4xbXtnwPwVbpm0EdswBE6qS',
|
||||
'fiL9zWk9dvHoKzSnfSDzDFoFcEoVchawzYXf/MM1YR4wo5XyzECc6Q5Ah4z522//',
|
||||
'mBNNaDHv83Yuw3mGShT73iJ0JQdkTturshv2Ecma38r6ftrIwNYXw4VVatJM8+GO',
|
||||
'OQIDAQAB',
|
||||
'-----END PUBLIC KEY-----',
|
||||
].join('\n'),
|
||||
};
|
||||
|
||||
@ -0,0 +1,78 @@
|
||||
import { Test, TestingModule } from '@nestjs/testing';
|
||||
import { UsersService } from '../users.service';
|
||||
import { UsersRepositoryService } from '../../../repositories/users/users.repository.service';
|
||||
import { CryptoService } from '../../../gateways/crypto/crypto.service';
|
||||
|
||||
export type CryptoMockValue = {
|
||||
getPublicKey: string | Error;
|
||||
};
|
||||
|
||||
export type UsersRepositoryMockValue = {
|
||||
updateUserVerified: undefined | Error;
|
||||
};
|
||||
|
||||
export const makeUsersServiceMock = async (
|
||||
cryptoMockValue: CryptoMockValue,
|
||||
usersRepositoryMockValue: UsersRepositoryMockValue,
|
||||
): Promise<UsersService> => {
|
||||
const module: TestingModule = await Test.createTestingModule({
|
||||
providers: [UsersService],
|
||||
})
|
||||
.useMocker((token) => {
|
||||
switch (token) {
|
||||
case CryptoService:
|
||||
return makeCryptoServiceMock(cryptoMockValue);
|
||||
case UsersRepositoryService:
|
||||
return makeUsersRepositoryMock(usersRepositoryMockValue);
|
||||
}
|
||||
})
|
||||
.compile();
|
||||
|
||||
return module.get<UsersService>(UsersService);
|
||||
};
|
||||
|
||||
export const makeCryptoServiceMock = (value: CryptoMockValue) => {
|
||||
const { getPublicKey } = value;
|
||||
|
||||
return {
|
||||
getPublicKey:
|
||||
getPublicKey instanceof Error
|
||||
? jest.fn<Promise<void>, []>().mockRejectedValue(getPublicKey)
|
||||
: jest.fn<Promise<string>, []>().mockResolvedValue(getPublicKey),
|
||||
};
|
||||
};
|
||||
|
||||
export const makeUsersRepositoryMock = (value: UsersRepositoryMockValue) => {
|
||||
const { updateUserVerified } = value;
|
||||
|
||||
return {
|
||||
updateUserVerified:
|
||||
updateUserVerified instanceof Error
|
||||
? jest.fn<Promise<void>, []>().mockRejectedValue(updateUserVerified)
|
||||
: jest.fn<Promise<void>, []>().mockResolvedValue(updateUserVerified),
|
||||
};
|
||||
};
|
||||
|
||||
export const makeDefaultCryptoMockValue = (): CryptoMockValue => {
|
||||
return {
|
||||
getPublicKey: [
|
||||
'-----BEGIN PUBLIC KEY-----',
|
||||
'MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA5IZZNgDew9eGmuFTezwd',
|
||||
'HYLSaJvUPPIKYoiOeVLD1paWNI517Vkaoh0ngprcKOdv6T1N07V4igK7mOim2zY3',
|
||||
'yCTR6wcWR3PfFJrl9vh5SOo79koZoJb27YiM4jtxfx2dezzp0T2GoNR5rRolPUbW',
|
||||
'FJXnDe0DVXYXpJLb4LAlF2XAyYX0SYKUVUsJnzm5k4xbXtnwPwVbpm0EdswBE6qS',
|
||||
'fiL9zWk9dvHoKzSnfSDzDFoFcEoVchawzYXf/MM1YR4wo5XyzECc6Q5Ah4z522//',
|
||||
'mBNNaDHv83Yuw3mGShT73iJ0JQdkTturshv2Ecma38r6ftrIwNYXw4VVatJM8+GO',
|
||||
'OQIDAQAB',
|
||||
'-----END PUBLIC KEY-----',
|
||||
].join('\n'),
|
||||
};
|
||||
};
|
||||
|
||||
// 個別のテストケースに対応してそれぞれのMockを用意するのは無駄が多いのでテストケース内で個別の値を設定する
|
||||
export const makeDefaultUsersRepositoryMockValue =
|
||||
(): UsersRepositoryMockValue => {
|
||||
return {
|
||||
updateUserVerified: undefined,
|
||||
};
|
||||
};
|
||||
@ -1,13 +1,19 @@
|
||||
import { Test, TestingModule } from '@nestjs/testing';
|
||||
import { UsersController } from './users.controller';
|
||||
import { UsersService } from './users.service';
|
||||
|
||||
describe('UsersController', () => {
|
||||
let controller: UsersController;
|
||||
const mockUserService = {};
|
||||
|
||||
beforeEach(async () => {
|
||||
const module: TestingModule = await Test.createTestingModule({
|
||||
controllers: [UsersController],
|
||||
}).compile();
|
||||
providers: [UsersService],
|
||||
})
|
||||
.overrideProvider(UsersService)
|
||||
.useValue(mockUserService)
|
||||
.compile();
|
||||
|
||||
controller = module.get<UsersController>(UsersController);
|
||||
});
|
||||
|
||||
@ -27,8 +27,7 @@ export class UsersController {
|
||||
})
|
||||
@ApiOperation({ operationId: 'confirmUser' })
|
||||
async confirmUser(@Body() body: ConfirmRequest): Promise<ConfirmResponse> {
|
||||
console.log(JSON.stringify(body));
|
||||
|
||||
await this.usersService.confirmUser(body.token);
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
@ -2,9 +2,10 @@ import { Module } from '@nestjs/common';
|
||||
import { CryptoModule } from '../../gateways/crypto/crypto.module';
|
||||
import { UsersController } from './users.controller';
|
||||
import { UsersService } from './users.service';
|
||||
import { UsersRepositoryModule } from '../../repositories/users/users.repository.module';
|
||||
|
||||
@Module({
|
||||
imports: [CryptoModule],
|
||||
imports: [CryptoModule, UsersRepositoryModule],
|
||||
controllers: [UsersController],
|
||||
providers: [UsersService],
|
||||
})
|
||||
|
||||
@ -1,18 +1,72 @@
|
||||
import { Test, TestingModule } from '@nestjs/testing';
|
||||
import { UsersService } from './users.service';
|
||||
import { HttpException, HttpStatus } from '@nestjs/common';
|
||||
import { makeErrorResponse } from '../../common/error/makeErrorResponse';
|
||||
import {
|
||||
makeDefaultCryptoMockValue,
|
||||
makeDefaultUsersRepositoryMockValue,
|
||||
makeUsersServiceMock,
|
||||
} from './test/users.service.mock';
|
||||
import { EmailAlreadyVerifiedError } from '../../repositories/users/users.repository.service';
|
||||
|
||||
describe('UsersService', () => {
|
||||
let service: UsersService;
|
||||
|
||||
beforeEach(async () => {
|
||||
const module: TestingModule = await Test.createTestingModule({
|
||||
providers: [UsersService],
|
||||
}).compile();
|
||||
|
||||
service = module.get<UsersService>(UsersService);
|
||||
it('ユーザの仮登録時に払い出されるトークンにより、未認証のユーザが認証済みになる', async () => {
|
||||
const cryptoMockValue = makeDefaultCryptoMockValue();
|
||||
const usersRepositoryMockValue = makeDefaultUsersRepositoryMockValue();
|
||||
const service = await makeUsersServiceMock(
|
||||
cryptoMockValue,
|
||||
usersRepositoryMockValue,
|
||||
);
|
||||
const token =
|
||||
'eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJhY2NvdW50SWQiOjEsInVzZXJJZCI6MiwiZW1haWwiOiJ4eHhAeHh4Lnh4eCIsImlhdCI6MTAwMDAwMDAwMCwiZXhwIjo5MDAwMDAwMDAwfQ.26L6BdNg-3TbyKT62PswlJ6RPMkcTtHzlDXW2Uo9XbMPVSrl2ObcuS6EcXjFFN2DEfNTKbqX_zevIWMpHOAdLNgGhk528nLrBrNvPASqtTjvW9muxMXpjUdjRVkmVbOylBHWW3YpWL9JEbJQ7rAzWDfaIdPhMovdaxumnZt_UwnlnrdaVPLACW7tkH_laEcAU507iSiM4mqxxG8FuTs34t6PEdwRuzZAQPN2IOPYNSvGNdJYryPacSeSNZ_z1xeBYXLOLQfOBZzyTReYDOhXdikhrNUbxjgnZQlSXBCVMlZ9PH42bHfp-LJIeJzW0yqnF6oLklvJP-fo8eW0k5iDOw';
|
||||
expect(await service.confirmUser(token)).toEqual(undefined);
|
||||
});
|
||||
|
||||
it('should be defined', () => {
|
||||
expect(service).toBeDefined();
|
||||
it('トークンの形式が不正な場合、形式不正エラーとなる。', async () => {
|
||||
const cryptoMockValue = makeDefaultCryptoMockValue();
|
||||
const usersRepositoryMockValue = makeDefaultUsersRepositoryMockValue();
|
||||
const service = await makeUsersServiceMock(
|
||||
cryptoMockValue,
|
||||
usersRepositoryMockValue,
|
||||
);
|
||||
const token = 'invalid.id.token';
|
||||
await expect(service.confirmUser(token)).rejects.toEqual(
|
||||
new HttpException(makeErrorResponse('E000101'), HttpStatus.BAD_REQUEST),
|
||||
);
|
||||
});
|
||||
|
||||
it('ユーザが既に認証済みだった場合、認証済みユーザエラーとなる。', async () => {
|
||||
const cryptoMockValue = makeDefaultCryptoMockValue();
|
||||
const usersRepositoryMockValue = makeDefaultUsersRepositoryMockValue();
|
||||
|
||||
usersRepositoryMockValue.updateUserVerified =
|
||||
new EmailAlreadyVerifiedError();
|
||||
|
||||
const service = await makeUsersServiceMock(
|
||||
cryptoMockValue,
|
||||
usersRepositoryMockValue,
|
||||
);
|
||||
const token =
|
||||
'eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJhY2NvdW50SWQiOjEsInVzZXJJZCI6MiwiZW1haWwiOiJ4eHhAeHh4Lnh4eCIsImlhdCI6MTAwMDAwMDAwMCwiZXhwIjo5MDAwMDAwMDAwfQ.26L6BdNg-3TbyKT62PswlJ6RPMkcTtHzlDXW2Uo9XbMPVSrl2ObcuS6EcXjFFN2DEfNTKbqX_zevIWMpHOAdLNgGhk528nLrBrNvPASqtTjvW9muxMXpjUdjRVkmVbOylBHWW3YpWL9JEbJQ7rAzWDfaIdPhMovdaxumnZt_UwnlnrdaVPLACW7tkH_laEcAU507iSiM4mqxxG8FuTs34t6PEdwRuzZAQPN2IOPYNSvGNdJYryPacSeSNZ_z1xeBYXLOLQfOBZzyTReYDOhXdikhrNUbxjgnZQlSXBCVMlZ9PH42bHfp-LJIeJzW0yqnF6oLklvJP-fo8eW0k5iDOw';
|
||||
await expect(service.confirmUser(token)).rejects.toEqual(
|
||||
new HttpException(makeErrorResponse('E010202'), HttpStatus.BAD_REQUEST),
|
||||
);
|
||||
});
|
||||
|
||||
it('DBネットワークエラーとなる場合、エラーとなる。', async () => {
|
||||
const cryptoMockValue = makeDefaultCryptoMockValue();
|
||||
const usersRepositoryMockValue = makeDefaultUsersRepositoryMockValue();
|
||||
usersRepositoryMockValue.updateUserVerified = new Error('DB error');
|
||||
|
||||
const service = await makeUsersServiceMock(
|
||||
cryptoMockValue,
|
||||
usersRepositoryMockValue,
|
||||
);
|
||||
const token =
|
||||
'eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJhY2NvdW50SWQiOjEsInVzZXJJZCI6MiwiZW1haWwiOiJ4eHhAeHh4Lnh4eCIsImlhdCI6MTAwMDAwMDAwMCwiZXhwIjo5MDAwMDAwMDAwfQ.26L6BdNg-3TbyKT62PswlJ6RPMkcTtHzlDXW2Uo9XbMPVSrl2ObcuS6EcXjFFN2DEfNTKbqX_zevIWMpHOAdLNgGhk528nLrBrNvPASqtTjvW9muxMXpjUdjRVkmVbOylBHWW3YpWL9JEbJQ7rAzWDfaIdPhMovdaxumnZt_UwnlnrdaVPLACW7tkH_laEcAU507iSiM4mqxxG8FuTs34t6PEdwRuzZAQPN2IOPYNSvGNdJYryPacSeSNZ_z1xeBYXLOLQfOBZzyTReYDOhXdikhrNUbxjgnZQlSXBCVMlZ9PH42bHfp-LJIeJzW0yqnF6oLklvJP-fo8eW0k5iDOw';
|
||||
await expect(service.confirmUser(token)).rejects.toEqual(
|
||||
new HttpException(
|
||||
makeErrorResponse('E009999'),
|
||||
HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
),
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
@ -1,4 +1,67 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { HttpException, HttpStatus, Injectable, Logger } from '@nestjs/common';
|
||||
import { isVerifyError, verify } from '../../common/jwt';
|
||||
import { CryptoService } from '../../gateways/crypto/crypto.service';
|
||||
import {
|
||||
UsersRepositoryService,
|
||||
EmailAlreadyVerifiedError,
|
||||
} from '../../repositories/users/users.repository.service';
|
||||
import { makeErrorResponse } from '../../common/error/makeErrorResponse';
|
||||
|
||||
@Injectable()
|
||||
export class UsersService {}
|
||||
export class UsersService {
|
||||
constructor(
|
||||
private readonly cryptoService: CryptoService,
|
||||
private readonly usersRepository: UsersRepositoryService,
|
||||
) {}
|
||||
private readonly logger = new Logger(UsersService.name);
|
||||
|
||||
/**
|
||||
* Confirms user
|
||||
* @param token ユーザ仮登録時に払いだされるトークン
|
||||
*/
|
||||
async confirmUser(token: string): Promise<void> {
|
||||
this.logger.log(`[IN] ${this.confirmUser.name}`);
|
||||
|
||||
const pubKey = await this.cryptoService.getPublicKey();
|
||||
|
||||
const decodedToken = verify<{
|
||||
accountId: number;
|
||||
userId: number;
|
||||
email: string;
|
||||
}>(token, pubKey);
|
||||
if (isVerifyError(decodedToken)) {
|
||||
throw new HttpException(
|
||||
makeErrorResponse('E000101'),
|
||||
HttpStatus.BAD_REQUEST,
|
||||
);
|
||||
}
|
||||
|
||||
try {
|
||||
// トランザクションで取得と更新をまとめる
|
||||
const userId = decodedToken.userId;
|
||||
await this.usersRepository.updateUserVerified(userId);
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
if (e instanceof Error) {
|
||||
switch (e.constructor) {
|
||||
case EmailAlreadyVerifiedError:
|
||||
throw new HttpException(
|
||||
makeErrorResponse('E010202'),
|
||||
HttpStatus.BAD_REQUEST,
|
||||
);
|
||||
default:
|
||||
throw new HttpException(
|
||||
makeErrorResponse('E009999'),
|
||||
HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
this.logger.error(`error=${e}`);
|
||||
throw new HttpException(
|
||||
makeErrorResponse('E009999'),
|
||||
HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,7 +1,11 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { DataSource } from 'typeorm';
|
||||
import { DataSource, UpdateResult } from 'typeorm';
|
||||
import { User } from './entity/user.entity';
|
||||
|
||||
// UsersRepositoryServiceで発生するエラーを定義
|
||||
export class EmailAlreadyVerifiedError extends Error {}
|
||||
export class UserNotFoundError extends Error {}
|
||||
|
||||
@Injectable()
|
||||
export class UsersRepositoryService {
|
||||
constructor(private dataSource: DataSource) {}
|
||||
@ -44,4 +48,58 @@ export class UsersRepositoryService {
|
||||
}
|
||||
return user;
|
||||
}
|
||||
|
||||
async findUserById(id: number): Promise<User | undefined> {
|
||||
const user = await this.dataSource.getRepository(User).findOne({
|
||||
where: {
|
||||
id: id,
|
||||
},
|
||||
});
|
||||
|
||||
if (!user) {
|
||||
return undefined;
|
||||
}
|
||||
return user;
|
||||
}
|
||||
|
||||
/**
|
||||
* 特定の情報でユーザーを更新する
|
||||
* @param user
|
||||
* @returns update
|
||||
*/
|
||||
async update(user: User): Promise<UpdateResult> {
|
||||
return await this.dataSource.transaction(async (entityManager) => {
|
||||
const repo = entityManager.getRepository(User);
|
||||
return await repo.update({ id: user.id }, user);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 管理ユーザーがメール認証済みなら認証情報を更新する
|
||||
* @param user
|
||||
* @returns update
|
||||
*/
|
||||
async updateUserVerified(id: number): Promise<UpdateResult> {
|
||||
return await this.dataSource.transaction(async (entityManager) => {
|
||||
const repo = entityManager.getRepository(User);
|
||||
const targetUser = await repo.findOne({
|
||||
where: {
|
||||
id: id,
|
||||
},
|
||||
});
|
||||
|
||||
// 運用上ユーザがいないことはあり得ないが、プログラム上発生しうるのでエラーとして処理
|
||||
if (!targetUser) {
|
||||
throw new UserNotFoundError();
|
||||
}
|
||||
|
||||
if (targetUser.email_verified) {
|
||||
throw new EmailAlreadyVerifiedError();
|
||||
}
|
||||
|
||||
targetUser.email_verified = true;
|
||||
|
||||
return await repo.update({ id: targetUser.id }, targetUser);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user