Merged PR 299: ユーザー編集API実装

## 概要
[Task2317: ユーザー編集API実装](https://paruru.nds-tyo.co.jp:8443/tfs/ReciproCollection/fa4924a4-d079-4fab-9fb5-a9a11eb205f0/_workitems/edit/2317)

- ユーザー編集APIとテストを実装しました。

## レビューポイント
- リポジトリでのチェックは適切か
- バリデータの適用は適切か
- テストケースは十分か

## UIの変更
- なし

## 動作確認状況
- ローカルで確認
This commit is contained in:
makabe.t 2023-08-04 05:39:33 +00:00
parent 34ad2e489d
commit 338d6b88a9
12 changed files with 869 additions and 11 deletions

View File

@ -30,6 +30,8 @@ export const ErrorCodes = [
'E010204', // ユーザ不在エラー
'E010205', // DBのRoleが想定外の値エラー
'E010206', // DBのTierが想定外の値エラー
'E010207', // ユーザーのRole変更不可エラー
'E010208', // ユーザーの暗号化パスワード不足エラー
'E010301', // メールアドレス登録済みエラー
'E010302', // authorId重複エラー
'E010401', // PONumber重複エラー

View File

@ -19,6 +19,8 @@ export const errors: Errors = {
E010204: 'User not Found Error.',
E010205: 'Role from DB is unexpected value Error.',
E010206: 'Tier from DB is unexpected value Error.',
E010207: 'User role change not allowed Error.',
E010208: 'User encryption password not found Error.',
E010301: 'This email user already created Error',
E010302: 'This AuthorId already used Error',
E010401: 'This PoNumber already used Error',

View File

@ -0,0 +1,32 @@
import { registerDecorator, ValidationOptions } from 'class-validator';
export const IsPasswordvalid = (validationOptions?: ValidationOptions) => {
return (object: any, propertyName: string) => {
registerDecorator({
name: 'IsPasswordvalid',
target: object.constructor,
propertyName: propertyName,
constraints: [],
options: validationOptions,
validator: {
validate: (value: string | undefined) => {
// passwordが設定されていない場合はチェックしない
if (value === undefined) {
return true;
}
// 正規表現でパスワードのチェックを行う
// 416文字の半角英数字と記号のみ
const regex = /^[!-~]{4,16}$/;
if (!regex.test(value)) {
return false;
}
return true;
},
defaultMessage: () => {
return 'EncryptionPassword rule not satisfied';
},
},
});
};
};

View File

@ -0,0 +1,39 @@
import {
registerDecorator,
ValidationOptions,
ValidationArguments,
} from 'class-validator';
import { USER_ROLES } from '../../constants';
import {
SignupRequest,
PostUpdateUserRequest,
} from '../../features/users/types/types';
export const IsRoleAuthorDataValid = <
T extends SignupRequest | PostUpdateUserRequest,
>(
validationOptions?: ValidationOptions,
) => {
return (object: T, propertyName: string) => {
registerDecorator({
name: 'IsRoleAuthorDataValid',
target: object.constructor,
propertyName: propertyName,
constraints: [],
options: validationOptions,
validator: {
validate: (value: boolean | undefined, args: ValidationArguments) => {
const request = args.object as T;
const { role } = request;
if (role === USER_ROLES.AUTHOR && value === undefined) {
return false;
}
return true;
},
defaultMessage: () => {
return `When role is author, ${propertyName} cannot be undefined`;
},
},
});
};
};

View File

@ -65,6 +65,9 @@ export const createUser = async (
role: string,
author_id?: string | undefined,
auto_renew?: boolean,
encryption?: boolean | undefined,
encryption_password?: string | undefined,
prompt?: boolean | undefined,
): Promise<{ userId: number; externalId: string }> => {
const { identifiers } = await datasource.getRepository(User).insert({
account_id: accountId,
@ -76,8 +79,9 @@ export const createUser = async (
auto_renew: auto_renew,
license_alert: true,
notification: true,
encryption: false,
prompt: false,
encryption: encryption ?? false,
encryption_password: encryption_password,
prompt: prompt ?? false,
created_by: 'test_runner',
created_at: new Date(),
updated_by: 'updater',
@ -87,6 +91,18 @@ export const createUser = async (
return { userId: user.id, externalId: external_id };
};
export const getUser = async (
datasource: DataSource,
id: number,
): Promise<User> => {
const user = await datasource.getRepository(User).findOne({
where: {
id: id,
},
});
return user;
};
/**
*
* @param datasource

View File

@ -5,6 +5,8 @@ import {
USER_LICENSE_STATUS,
} from '../../../constants';
import { USER_ROLES } from '../../../constants';
import { IsRoleAuthorDataValid } from '../../../common/validators/roleAuthor.validator';
import { IsPasswordvalid } from '../../../common/validators/encryptionPassword.validator';
export class ConfirmRequest {
@ApiProperty()
@ -197,6 +199,7 @@ export class PostUpdateUserRequest {
role: string;
@ApiProperty({ required: false })
@IsRoleAuthorDataValid()
authorId?: string | undefined;
@ApiProperty()
@ -209,12 +212,15 @@ export class PostUpdateUserRequest {
notification: boolean;
@ApiProperty({ required: false })
@IsRoleAuthorDataValid()
encryption?: boolean | undefined;
@ApiProperty({ required: false })
@IsPasswordvalid()
encryptionPassword?: string | undefined;
@ApiProperty({ required: false })
@IsRoleAuthorDataValid()
prompt?: boolean | undefined;
}

View File

@ -335,11 +335,36 @@ export class UsersController {
@Body() body: PostUpdateUserRequest,
@Req() req: Request,
): Promise<PostUpdateUserResponse> {
const accessToken = retrieveAuthorizationToken(req);
const decodedToken = jwt.decode(accessToken, { json: true }) as AccessToken;
const {
id,
role,
authorId,
autoRenew,
licenseAlart,
notification,
encryption,
encryptionPassword,
prompt,
} = body;
console.log(body);
console.log(decodedToken);
const accessToken = retrieveAuthorizationToken(req);
const { userId } = jwt.decode(accessToken, { json: true }) as AccessToken;
const context = makeContext(userId);
await this.usersService.updateUser(
context,
userId,
id,
role,
authorId,
autoRenew,
licenseAlart,
notification,
encryption,
encryptionPassword,
prompt,
);
return {};
}
}

View File

@ -15,6 +15,7 @@ import {
createLicense,
createUser,
createUserGroup,
getUser,
makeTestingModuleWithAdb2c,
} from './test/utility';
import { DataSource } from 'typeorm';
@ -22,7 +23,9 @@ import { UsersService } from './users.service';
import {
LICENSE_EXPIRATION_THRESHOLD_DAYS,
USER_LICENSE_STATUS,
USER_ROLES,
} from '../../constants';
import { makeTestingModule } from '../../common/test/modules';
describe('UsersService.confirmUser', () => {
it('ユーザの仮登録時に払い出されるトークンにより、未認証のユーザが認証済みになる', async () => {
@ -1016,3 +1019,539 @@ describe('UsersService.getSortCriteria', () => {
);
});
});
describe('UsersService.updateUser', () => {
let source: DataSource = null;
beforeEach(async () => {
source = new DataSource({
type: 'sqlite',
database: ':memory:',
logging: false,
entities: [__dirname + '/../../**/*.entity{.ts,.js}'],
synchronize: true, // trueにすると自動的にmigrationが行われるため注意
});
return source.initialize();
});
afterEach(async () => {
await source.destroy();
source = null;
});
it('ユーザー情報を更新できるNone', async () => {
const module = await makeTestingModule(source);
const { accountId } = await createAccount(source);
const { externalId: external_id } = await createUser(
source,
accountId,
'external_id',
USER_ROLES.NONE,
undefined,
true,
);
const { userId: user1 } = await createUser(
source,
accountId,
'external_id1',
USER_ROLES.NONE,
undefined,
true,
);
const service = module.get<UsersService>(UsersService);
expect(
await service.updateUser(
{ trackingId: 'trackingId' },
external_id,
user1,
USER_ROLES.NONE,
undefined,
false,
false,
false,
undefined,
undefined,
undefined,
),
).toEqual(undefined);
const createdUser = await getUser(source, user1);
expect(createdUser.id).toBe(user1);
expect(createdUser.role).toBe(USER_ROLES.NONE);
expect(createdUser.author_id).toBeNull();
expect(createdUser.auto_renew).toBe(false);
expect(createdUser.license_alert).toBe(false);
expect(createdUser.notification).toBe(false);
expect(createdUser.encryption).toBe(false);
expect(createdUser.encryption_password).toBeNull();
expect(createdUser.prompt).toBe(false);
});
it('ユーザー情報を更新できるTypist', async () => {
const module = await makeTestingModule(source);
const { accountId } = await createAccount(source);
const { externalId: external_id } = await createUser(
source,
accountId,
'external_id',
USER_ROLES.NONE,
undefined,
true,
);
const { userId: user1 } = await createUser(
source,
accountId,
'external_id1',
USER_ROLES.TYPIST,
undefined,
true,
);
const service = module.get<UsersService>(UsersService);
expect(
await service.updateUser(
{ trackingId: 'trackingId' },
external_id,
user1,
USER_ROLES.TYPIST,
undefined,
false,
false,
false,
undefined,
undefined,
undefined,
),
).toEqual(undefined);
const createdUser = await getUser(source, user1);
expect(createdUser.id).toBe(user1);
expect(createdUser.role).toBe(USER_ROLES.TYPIST);
expect(createdUser.author_id).toBeNull();
expect(createdUser.auto_renew).toBe(false);
expect(createdUser.license_alert).toBe(false);
expect(createdUser.notification).toBe(false);
expect(createdUser.encryption).toBe(false);
expect(createdUser.encryption_password).toBeNull();
expect(createdUser.prompt).toBe(false);
});
it('ユーザー情報を更新できるAuthor', async () => {
const module = await makeTestingModule(source);
const { accountId } = await createAccount(source);
const { externalId: external_id } = await createUser(
source,
accountId,
'external_id',
USER_ROLES.NONE,
undefined,
true,
);
const { userId: user1 } = await createUser(
source,
accountId,
'external_id1',
USER_ROLES.AUTHOR,
undefined,
true,
true,
'password',
true,
);
const service = module.get<UsersService>(UsersService);
expect(
await service.updateUser(
{ trackingId: 'trackingId' },
external_id,
user1,
USER_ROLES.AUTHOR,
'AUTHOR_ID',
false,
false,
false,
true,
'new_password',
true,
),
).toEqual(undefined);
const createdUser = await getUser(source, user1);
expect(createdUser.id).toBe(user1);
expect(createdUser.role).toBe(USER_ROLES.AUTHOR);
expect(createdUser.author_id).toBe('AUTHOR_ID');
expect(createdUser.auto_renew).toBe(false);
expect(createdUser.license_alert).toBe(false);
expect(createdUser.notification).toBe(false);
expect(createdUser.encryption).toBe(true);
expect(createdUser.encryption_password).toBe('new_password');
expect(createdUser.prompt).toBe(true);
});
it('ユーザーのRoleを更新できるNone⇒Typist', async () => {
const module = await makeTestingModule(source);
const { accountId } = await createAccount(source);
const { externalId: external_id } = await createUser(
source,
accountId,
'external_id',
USER_ROLES.NONE,
undefined,
true,
);
const { userId: user1 } = await createUser(
source,
accountId,
'external_id1',
USER_ROLES.NONE,
undefined,
true,
);
const service = module.get<UsersService>(UsersService);
expect(
await service.updateUser(
{ trackingId: 'trackingId' },
external_id,
user1,
USER_ROLES.TYPIST,
undefined,
false,
false,
false,
undefined,
undefined,
undefined,
),
).toEqual(undefined);
const createdUser = await getUser(source, user1);
expect(createdUser.id).toBe(user1);
expect(createdUser.role).toBe(USER_ROLES.TYPIST);
expect(createdUser.author_id).toBeNull();
expect(createdUser.auto_renew).toBe(false);
expect(createdUser.license_alert).toBe(false);
expect(createdUser.notification).toBe(false);
expect(createdUser.encryption).toBe(false);
expect(createdUser.encryption_password).toBeNull();
expect(createdUser.prompt).toBe(false);
});
it('ユーザーのRoleを更新できるNone⇒Author', async () => {
const module = await makeTestingModule(source);
const { accountId } = await createAccount(source);
const { externalId: external_id } = await createUser(
source,
accountId,
'external_id',
USER_ROLES.NONE,
undefined,
true,
);
const { userId: user1 } = await createUser(
source,
accountId,
'external_id1',
USER_ROLES.NONE,
undefined,
true,
);
const service = module.get<UsersService>(UsersService);
expect(
await service.updateUser(
{ trackingId: 'trackingId' },
external_id,
user1,
USER_ROLES.AUTHOR,
'AUTHOR_ID',
false,
false,
false,
false,
undefined,
false,
),
).toEqual(undefined);
const createdUser = await getUser(source, user1);
expect(createdUser.id).toBe(user1);
expect(createdUser.role).toBe(USER_ROLES.AUTHOR);
expect(createdUser.author_id).toBe('AUTHOR_ID');
expect(createdUser.auto_renew).toBe(false);
expect(createdUser.license_alert).toBe(false);
expect(createdUser.notification).toBe(false);
expect(createdUser.encryption).toBe(false);
expect(createdUser.encryption_password).toBeNull();
expect(createdUser.prompt).toBe(false);
});
it('None以外からRoleを変更した場合、エラーとなるTypist⇒None', async () => {
const module = await makeTestingModule(source);
const { accountId } = await createAccount(source);
const { externalId: external_id } = await createUser(
source,
accountId,
'external_id',
USER_ROLES.NONE,
undefined,
true,
);
const { userId: user1 } = await createUser(
source,
accountId,
'external_id1',
USER_ROLES.TYPIST,
undefined,
true,
);
const service = module.get<UsersService>(UsersService);
await expect(
service.updateUser(
{ trackingId: 'trackingId' },
external_id,
user1,
USER_ROLES.NONE,
undefined,
false,
false,
false,
undefined,
undefined,
undefined,
),
).rejects.toEqual(
new HttpException(makeErrorResponse('E010207'), HttpStatus.BAD_REQUEST),
);
});
it('Authorがパスワードundefinedで渡されたとき、元のパスワードを維持するEncryptionがtrue', async () => {
const module = await makeTestingModule(source);
const { accountId } = await createAccount(source);
const { externalId: external_id } = await createUser(
source,
accountId,
'external_id',
USER_ROLES.NONE,
undefined,
true,
);
const { userId: user1 } = await createUser(
source,
accountId,
'external_id1',
USER_ROLES.AUTHOR,
'AUTHOR_ID',
true,
true,
'password',
true,
);
const service = module.get<UsersService>(UsersService);
expect(
await service.updateUser(
{ trackingId: 'trackingId' },
external_id,
user1,
USER_ROLES.AUTHOR,
'AUTHOR_ID',
false,
false,
false,
true,
undefined,
true,
),
).toEqual(undefined);
const createdUser = await getUser(source, user1);
expect(createdUser.id).toBe(user1);
expect(createdUser.role).toBe(USER_ROLES.AUTHOR);
expect(createdUser.author_id).toBe('AUTHOR_ID');
expect(createdUser.auto_renew).toBe(false);
expect(createdUser.license_alert).toBe(false);
expect(createdUser.notification).toBe(false);
expect(createdUser.encryption).toBe(true);
expect(createdUser.encryption_password).toBe('password');
expect(createdUser.prompt).toBe(true);
});
it('Authorが暗号化なしで更新した場合、パスワードをNULLにするEncryptionがfalse', async () => {
const module = await makeTestingModule(source);
const { accountId } = await createAccount(source);
const { externalId: external_id } = await createUser(
source,
accountId,
'external_id',
USER_ROLES.NONE,
undefined,
true,
);
const { userId: user1 } = await createUser(
source,
accountId,
'external_id1',
USER_ROLES.AUTHOR,
'AUTHOR_ID',
true,
false,
'password',
true,
);
const service = module.get<UsersService>(UsersService);
expect(
await service.updateUser(
{ trackingId: 'trackingId' },
external_id,
user1,
USER_ROLES.AUTHOR,
'AUTHOR_ID',
false,
false,
false,
false,
'password',
true,
),
).toEqual(undefined);
const createdUser = await getUser(source, user1);
expect(createdUser.id).toBe(user1);
expect(createdUser.role).toBe(USER_ROLES.AUTHOR);
expect(createdUser.author_id).toBe('AUTHOR_ID');
expect(createdUser.auto_renew).toBe(false);
expect(createdUser.license_alert).toBe(false);
expect(createdUser.notification).toBe(false);
expect(createdUser.encryption).toBe(false);
expect(createdUser.encryption_password).toBeNull();
expect(createdUser.prompt).toBe(true);
});
it('AuthorのDBにパスワードが設定されていない場合、パスワードundefinedでわたすとエラーとなるEncryptionがtrue', async () => {
const module = await makeTestingModule(source);
const { accountId } = await createAccount(source);
const { externalId: external_id } = await createUser(
source,
accountId,
'external_id',
USER_ROLES.NONE,
undefined,
true,
);
const { userId: user1 } = await createUser(
source,
accountId,
'external_id1',
USER_ROLES.AUTHOR,
'AUTHOR_ID',
true,
true,
undefined,
true,
);
const service = module.get<UsersService>(UsersService);
await expect(
service.updateUser(
{ trackingId: 'trackingId' },
external_id,
user1,
USER_ROLES.AUTHOR,
'AUTHOR_ID',
false,
false,
false,
true,
undefined,
true,
),
).rejects.toEqual(
new HttpException(makeErrorResponse('E010208'), HttpStatus.BAD_REQUEST),
);
});
it('AuthorIdが既存のユーザーと重複した場合、エラーとなる', async () => {
const module = await makeTestingModule(source);
const { accountId } = await createAccount(source);
const { externalId: external_id } = await createUser(
source,
accountId,
'external_id',
USER_ROLES.NONE,
undefined,
true,
);
const { userId: user1 } = await createUser(
source,
accountId,
'external_id1',
USER_ROLES.AUTHOR,
'AUTHOR_ID1',
true,
true,
'password',
true,
);
const { userId: user2 } = await createUser(
source,
accountId,
'external_id2',
USER_ROLES.AUTHOR,
'AUTHOR_ID2',
true,
true,
'password',
true,
);
const service = module.get<UsersService>(UsersService);
await expect(
service.updateUser(
{ trackingId: 'trackingId' },
external_id,
user1,
USER_ROLES.AUTHOR,
'AUTHOR_ID2',
false,
false,
false,
true,
undefined,
true,
),
).rejects.toEqual(
new HttpException(makeErrorResponse('E010302'), HttpStatus.BAD_REQUEST),
);
});
});

View File

@ -21,7 +21,13 @@ import { SortCriteriaRepositoryService } from '../../repositories/sort_criteria/
import { User as EntityUser } from '../../repositories/users/entity/user.entity';
import { UsersRepositoryService } from '../../repositories/users/users.repository.service';
import { GetRelationsResponse, User } from './types/types';
import { EmailAlreadyVerifiedError } from '../../repositories/users/errors/types';
import {
AuthorIdAlreadyExistsError,
EmailAlreadyVerifiedError,
EncryptionPasswordNeedError,
InvalidRoleChangeError,
UserNotFoundError,
} from '../../repositories/users/errors/types';
import {
LICENSE_EXPIRATION_THRESHOLD_DAYS,
USER_LICENSE_STATUS,
@ -628,4 +634,103 @@ export class UsersService {
);
}
}
/**
*
* @param context
* @param extarnalId
* @param id
* @param role
* @param authorId
* @param autoRenew
* @param licenseAlart
* @param notification
* @param encryption
* @param encryptionPassword
* @param prompt
* @returns user
*/
async updateUser(
context: Context,
extarnalId: string,
id: number,
role: string,
authorId: string | undefined,
autoRenew: boolean,
licenseAlart: boolean,
notification: boolean,
encryption: boolean | undefined,
encryptionPassword: string | undefined,
prompt: boolean | undefined,
): Promise<void> {
try {
this.logger.log(
`[IN] [${context.trackingId}] ${this.updateUser.name} | params: { ` +
`role: ${role}, ` +
`authorId: ${authorId}, ` +
`autoRenew: ${autoRenew}, ` +
`licenseAlart: ${licenseAlart}, ` +
`notification: ${notification}, ` +
`encryption: ${encryption}, ` +
`encryptionPassword: ********, ` +
`prompt: ${prompt} }`,
);
// 実行ユーザーのアカウントIDを取得
const accountId = (
await this.usersRepository.findUserByExternalId(extarnalId)
).account_id;
// ユーザー情報を更新
await this.usersRepository.update(
accountId,
id,
role,
authorId,
autoRenew,
licenseAlart,
notification,
encryption,
encryptionPassword,
prompt,
);
} catch (e) {
this.logger.error(`error=${e}`);
if (e instanceof Error) {
switch (e.constructor) {
case UserNotFoundError:
throw new HttpException(
makeErrorResponse('E010204'),
HttpStatus.BAD_REQUEST,
);
case AuthorIdAlreadyExistsError:
throw new HttpException(
makeErrorResponse('E010302'),
HttpStatus.BAD_REQUEST,
);
case InvalidRoleChangeError:
throw new HttpException(
makeErrorResponse('E010207'),
HttpStatus.BAD_REQUEST,
);
case EncryptionPasswordNeedError:
throw new HttpException(
makeErrorResponse('E010208'),
HttpStatus.BAD_REQUEST,
);
default:
throw new HttpException(
makeErrorResponse('E009999'),
HttpStatus.INTERNAL_SERVER_ERROR,
);
}
}
throw new HttpException(
makeErrorResponse('E009999'),
HttpStatus.INTERNAL_SERVER_ERROR,
);
} finally {
this.logger.log(`[OUT] [${context.trackingId}] ${this.updateUser.name}`);
}
}
}

View File

@ -48,6 +48,9 @@ export class User {
@Column()
encryption: boolean;
@Column({ nullable: true })
encryption_password?: string;
@Column()
prompt: boolean;

View File

@ -2,3 +2,9 @@
export class EmailAlreadyVerifiedError extends Error {}
// ユーザー未発見エラー
export class UserNotFoundError extends Error {}
// AuthorID重複エラー
export class AuthorIdAlreadyExistsError extends Error {}
// 不正なRole変更エラー
export class InvalidRoleChangeError extends Error {}
// 暗号化パスワード不足エラー
export class EncryptionPasswordNeedError extends Error {}

View File

@ -1,12 +1,18 @@
import { Injectable } from '@nestjs/common';
import { DataSource, IsNull, UpdateResult } from 'typeorm';
import { DataSource, IsNull, Not, UpdateResult } from 'typeorm';
import { User } from './entity/user.entity';
import { SortCriteria } from '../sort_criteria/entity/sort_criteria.entity';
import {
getDirection,
getTaskListSortableAttribute,
} from '../../common/types/sort/util';
import { UserNotFoundError, EmailAlreadyVerifiedError } from './errors/types';
import {
UserNotFoundError,
EmailAlreadyVerifiedError,
AuthorIdAlreadyExistsError,
InvalidRoleChangeError,
EncryptionPasswordNeedError,
} from './errors/types';
import { USER_ROLES } from '../../constants';
@Injectable()
@ -165,10 +171,87 @@ export class UsersRepositoryService {
* @param user
* @returns update
*/
async update(user: User): Promise<UpdateResult> {
async update(
accountId: number,
id: number,
role: string,
authorId: string | undefined,
autoRenew: boolean,
licenseAlart: boolean,
notification: boolean,
encryption: boolean | undefined,
encryptionPassword: string | undefined,
prompt: boolean | undefined,
): Promise<UpdateResult> {
return await this.dataSource.transaction(async (entityManager) => {
const repo = entityManager.getRepository(User);
return await repo.update({ id: user.id }, user);
// 変更対象のユーザーを取得
const targetUser = await repo.findOne({
where: { id: id, account_id: accountId },
});
// 運用上ユーザがいないことはあり得ないが、プログラム上発生しうるのでエラーとして処理
if (!targetUser) {
throw new UserNotFoundError();
}
// ユーザーのロールがNoneの場合以外はロールを変更できない
if (targetUser.role !== USER_ROLES.NONE && targetUser.role !== role) {
throw new InvalidRoleChangeError('Not None user cannot change role.');
}
if (role === USER_ROLES.AUTHOR) {
// ユーザーのロールがAuthorの場合はAuthorIDの重複チェックを行う
const authorIdDuplicatedUser = await repo.findOne({
where: { account_id: accountId, id: Not(id), author_id: authorId },
});
// 重複したAuthorIDがあった場合はエラー
if (authorIdDuplicatedUser) {
throw new AuthorIdAlreadyExistsError('authorId already exists.');
}
// 暗号化を有効にする場合はパスワードを設定する
if (encryption) {
// 暗号化パスワードが設定されている場合は更新するundefinedの場合は変更なしとして元のパスワードを維持
if (encryptionPassword) {
targetUser.encryption_password = encryptionPassword;
} else if (!targetUser.encryption_password) {
// DBにパスワードが設定されていない場合にはパスワードを設定しないとエラー
throw new EncryptionPasswordNeedError(
'encryption_password need to set value.',
);
}
} else {
targetUser.encryption_password = null;
}
// Author用項目を更新
targetUser.author_id = authorId;
targetUser.encryption = encryption;
targetUser.prompt = prompt;
} else {
// ユーザーのロールがAuthor以外の場合はAuthor用項目はundefinedにする
targetUser.author_id = null;
targetUser.encryption = false;
targetUser.encryption_password = null;
targetUser.prompt = false;
}
// 共通項目を更新
targetUser.role = role;
targetUser.auto_renew = autoRenew;
targetUser.license_alert = licenseAlart;
targetUser.notification = notification;
const result = await repo.update({ id: id }, targetUser);
// 想定外の更新が行われた場合はロールバックを行った上でエラー送出
if (result.affected !== 1) {
throw new Error(`invalid update. result.affected=${result.affected}`);
}
return result;
});
}