Merged PR 606: 画面修正(Terms画面)

## 概要
[Task3210: 画面修正(Terms画面)](https://paruru.nds-tyo.co.jp:8443/tfs/ReciproCollection/fa4924a4-d079-4fab-9fb5-a9a11eb205f0/_workitems/edit/3210)
[Task3211:API修正(バージョン取得API)](https://paruru.nds-tyo.co.jp:8443/tfs/ReciproCollection/OMDSDictation/_sprints/taskboard/OMDSDictation%20%E3%83%81%E3%83%BC%E3%83%A0/OMDSDictation/%E3%82%B9%E3%83%97%E3%83%AA%E3%83%B3%E3%83%88%2023-1?workitem=3211)
[Task3212:API修正(バージョン更新API))](https://paruru.nds-tyo.co.jp:8443/tfs/ReciproCollection/OMDSDictation/_sprints/taskboard/OMDSDictation%20%E3%83%81%E3%83%BC%E3%83%A0/OMDSDictation/%E3%82%B9%E3%83%97%E3%83%AA%E3%83%B3%E3%83%88%2023-1?workitem=3212)

- このPull Requestでの対象/対象外
Click here to read the terms of use.の文言は多言語対応の対象のため、現在一律同じ文言がでます。
第一~第四階層は
上からEULA,PrivacyNotice,DPAが表示されています
第五階層は、
上から、PrivacyNotice,DPAが表示されています
- 影響範囲(他の機能にも影響があるか)
ユーザアーカイブテーブルにPrivacyNoticeのバージョンを追加

## レビューポイント
同意済みプライバシーポリシーはユーザーアーカイブの対象だと認識しているが正しいか。
termsテーブルのdocument_typeの値をPrivacyNoticeにしているが、PRIVACY_NOTICEにしたほうがよいか。
ユニットテストに不足はないか。

## UIの変更
- Before/Afterのスクショなど
- スクショ置き場
https://ndstokyo.sharepoint.com/sites/Piranha/Shared%20Documents/Forms/AllItems.aspx?csf=1&web=1&e=hzPw9b&cid=7737ed1b%2D0eb4%2D4331%2Da238%2D14dd35b27e18&FolderCTID=0x012000C0DCEE65AC2177479C3C761CD137C9C9&id=%2Fsites%2FPiranha%2FShared%20Documents%2FGeneral%2FOMDS%2F%E3%82%B9%E3%82%AF%E3%83%AA%E3%83%BC%E3%83%B3%E3%82%B7%E3%83%A7%E3%83%83%E3%83%88%2FTask3210&viewid=786a81cf%2Dd15f%2D4dc2%2D9e55%2Dc7a729fbc72f
## 動作確認状況
- ローカルで確認

## 補足
- 相談、参考資料などがあれば
This commit is contained in:
maruyama.t 2023-12-05 09:10:49 +00:00
parent 62a5155ee1
commit 94f34a0fde
33 changed files with 261 additions and 22 deletions

View File

@ -447,6 +447,12 @@ export interface CreateAccountRequest {
* @memberof CreateAccountRequest
*/
'acceptedEulaVersion': string;
/**
*
* @type {string}
* @memberof CreateAccountRequest
*/
'acceptedPrivacyNoticeVersion': string;
/**
* (DPA)
* @type {string}
@ -2000,6 +2006,12 @@ export interface UpdateAcceptedVersionRequest {
* @memberof UpdateAcceptedVersionRequest
*/
'acceptedEULAVersion': string;
/**
* PrivacyNotice
* @type {string}
* @memberof UpdateAcceptedVersionRequest
*/
'acceptedPrivacyNoticeVersion': string;
/**
* DPA
* @type {string}

View File

@ -5,4 +5,5 @@
export const TERMS_DOCUMENT_TYPE = {
DPA: "DPA",
EULA: "EULA",
PRIVACY_NOTICE: "PrivacyNotice",
} as const;

View File

@ -110,6 +110,7 @@ export const updateAcceptedVersionAsync = createAsyncThunk<
updateAccceptVersions: {
acceptedVerDPA: string;
acceptedVerEULA: string;
acceptedVerPrivacyNotice: string;
};
},
{
@ -140,6 +141,8 @@ export const updateAcceptedVersionAsync = createAsyncThunk<
{
idToken,
acceptedEULAVersion: updateAccceptVersions.acceptedVerEULA,
acceptedPrivacyNoticeVersion:
updateAccceptVersions.acceptedVerPrivacyNotice,
acceptedDPAVersion: !(TIERS.TIER5 === tier.toString())
? updateAccceptVersions.acceptedVerDPA
: undefined,

View File

@ -14,7 +14,11 @@ export const selectTermVersions = (state: RootState) => {
(termInfo) => termInfo.documentType === TERMS_DOCUMENT_TYPE.EULA
)?.version || "";
return { acceptedVerDPA, acceptedVerEULA };
const acceptedVerPrivacyNotice =
termsInfo.find(
(termInfo) => termInfo.documentType === TERMS_DOCUMENT_TYPE.PRIVACY_NOTICE
)?.version || "";
return { acceptedVerDPA, acceptedVerEULA, acceptedVerPrivacyNotice };
};
export const selectTier = (state: RootState) => state.terms.domain.tier;

View File

@ -40,6 +40,7 @@ const SignupConfirm: React.FC = (): JSX.Element => {
adminMail,
adminPassword,
acceptedEulaVersion,
acceptedPrivacyNoticeVersion: "",
acceptedDpaVersion: "",
token: "",
})

View File

@ -29,9 +29,12 @@ const TermsPage: React.FC = (): JSX.Element => {
const tier = useSelector(selectTier);
const [isCheckedEula, setIsCheckedEula] = useState(false);
const [isCheckedPrivacyNotice, setIsCheckedPrivacyNotice] = useState(false);
const [isCheckedDpa, setIsCheckedDpa] = useState(false);
const [isClickedEulaLink, setIsClickedEulaLink] = useState(false);
const [isClickedPrivacyNoticeLink, setIsClickedPrivacyNoticeLink] =
useState(false);
const [isClickedDpaLink, setIsClickedDpaLink] = useState(false);
// 画面起動時
@ -52,9 +55,9 @@ const TermsPage: React.FC = (): JSX.Element => {
// ボタン押下可否判定ロジック
const canClickButton = () => {
if (isTier5()) {
return isCheckedEula;
return isCheckedEula && isCheckedPrivacyNotice;
}
return isCheckedEula && isCheckedDpa;
return isCheckedEula && isCheckedPrivacyNotice && isCheckedDpa;
};
// ボタン押下時処理
@ -62,7 +65,8 @@ const TermsPage: React.FC = (): JSX.Element => {
if (
localStorageKeyforIdToken &&
updateAccceptVersions.acceptedVerDPA !== "" &&
updateAccceptVersions.acceptedVerEULA !== ""
updateAccceptVersions.acceptedVerEULA !== "" &&
updateAccceptVersions.acceptedVerPrivacyNotice !== ""
) {
const { meta } = await dispatch(
updateAcceptedVersionAsync({
@ -132,7 +136,42 @@ const TermsPage: React.FC = (): JSX.Element => {
</label>
</p>
</dd>
{/* 第五階層以外の場合はEulaのリンクをあわせて表示する */}
<dd className={`${styles.full} ${styles.alignCenter}`}>
<p>
{/* eslint-disable-next-line jsx-a11y/click-events-have-key-events, jsx-a11y/no-static-element-interactions */}
<a
href="/" /* TODO PrivacyNotice用の利用規約リンクが決定したら設定を行う */
target="_blank"
className={styles.linkTx}
onClick={() => setIsClickedPrivacyNoticeLink(true)}
data-tag="open-pricacy-notice"
>
{t(
getTranslationID("termsPage.label.linkOfPrivacyNotice")
)}
</a>
{` ${t(getTranslationID("termsPage.label.forOdds"))}`}
</p>
<p>
<label>
<input
type="checkbox"
checked={isCheckedPrivacyNotice}
className={styles.formCheck}
value=""
onChange={(e) =>
setIsCheckedPrivacyNotice(e.target.checked)
}
disabled={!isClickedPrivacyNoticeLink}
data-tag="accept-privacy-notice"
/>
{t(
getTranslationID("termsPage.label.checkBoxForConsent")
)}
</label>
</p>
</dd>
{/* 第五階層以外の場合はDPAのリンクをあわせて表示する */}
{!isTier5() && (
<dd className={`${styles.full} ${styles.alignCenter}`}>
<p>

View File

@ -532,6 +532,7 @@
"title": "(de)Terms of Use has updated. Please confirm again.",
"linkOfEula": "(de)Click here to read the terms of use.",
"linkOfDpa": "(de)Click here to read the terms of use.",
"linkOfPrivacyNotice": "(de)Click here to read the terms of use.",
"checkBoxForConsent": "(de)Yes, I agree to the terms of use.",
"forOdds": "(de)for ODDS.",
"button": "(de)Continue",

View File

@ -532,6 +532,7 @@
"title": "Terms of Use has updated. Please confirm again.",
"linkOfEula": "Click here to read the terms of use.",
"linkOfDpa": "Click here to read the terms of use.",
"linkOfPrivacyNotice": "Click here to read the terms of use.",
"checkBoxForConsent": "Yes, I agree to the terms of use.",
"forOdds": "for ODDS.",
"button": "Continue",

View File

@ -532,6 +532,7 @@
"title": "(es)Terms of Use has updated. Please confirm again.",
"linkOfEula": "(es)Click here to read the terms of use.",
"linkOfDpa": "(es)Click here to read the terms of use.",
"linkOfPrivacyNotice": "(es)Click here to read the terms of use.",
"checkBoxForConsent": "(es)Yes, I agree to the terms of use.",
"forOdds": "(es)for ODDS.",
"button": "(es)Continue",

View File

@ -532,6 +532,7 @@
"title": "(fr)Terms of Use has updated. Please confirm again.",
"linkOfEula": "(fr)Click here to read the terms of use.",
"linkOfDpa": "(fr)Click here to read the terms of use.",
"linkOfPrivacyNotice": "(fr)Click here to read the terms of use.",
"checkBoxForConsent": "(fr)Yes, I agree to the terms of use.",
"forOdds": "(fr)for ODDS.",
"button": "(fr)Continue",

View File

@ -3537,6 +3537,10 @@
"type": "string",
"description": "同意済み利用規約のバージョン(EULA)"
},
"acceptedPrivacyNoticeVersion": {
"type": "string",
"description": "同意済みプライバシーポリシーのバージョン"
},
"acceptedDpaVersion": {
"type": "string",
"description": "同意済み利用規約のバージョン(DPA)"
@ -3550,6 +3554,7 @@
"adminMail",
"adminPassword",
"acceptedEulaVersion",
"acceptedPrivacyNoticeVersion",
"acceptedDpaVersion",
"token"
]
@ -4292,12 +4297,20 @@
"type": "string",
"description": "更新バージョンEULA"
},
"acceptedPrivacyNoticeVersion": {
"type": "string",
"description": "更新バージョンPrivacyNotice"
},
"acceptedDPAVersion": {
"type": "string",
"description": "更新バージョンDPA"
}
},
"required": ["idToken", "acceptedEULAVersion"]
"required": [
"idToken",
"acceptedEULAVersion",
"acceptedPrivacyNoticeVersion"
]
},
"UpdateAcceptedVersionResponse": { "type": "object", "properties": {} },
"GetMyUserResponse": {

View File

@ -182,6 +182,8 @@ export const makeTestAccount = async (
role: d?.role ?? 'admin none',
author_id: d?.author_id ?? undefined,
accepted_eula_version: d?.accepted_eula_version ?? '1.0',
accepted_privacy_notice_version:
d?.accepted_privacy_notice_version ?? '1.0',
accepted_dpa_version: d?.accepted_dpa_version ?? '1.0',
email_verified: d?.email_verified ?? true,
auto_renew: d?.auto_renew ?? true,

View File

@ -287,6 +287,7 @@ export const MANUAL_RECOVERY_REQUIRED = '[MANUAL_RECOVERY_REQUIRED]';
export const TERM_TYPE = {
EULA: 'EULA',
DPA: 'DPA',
PRIVACY_NOTICE: 'PrivacyNotice',
} as const;
/**

View File

@ -118,6 +118,7 @@ export class AccountsController {
adminPassword,
adminName,
acceptedEulaVersion,
acceptedPrivacyNoticeVersion,
acceptedDpaVersion,
} = body;
const role = USER_ROLES.NONE;
@ -134,6 +135,7 @@ export class AccountsController {
adminName,
role,
acceptedEulaVersion,
acceptedPrivacyNoticeVersion,
acceptedDpaVersion,
);

View File

@ -112,6 +112,7 @@ describe('createAccount', () => {
const username = 'dummy_username';
const role = 'none';
const acceptedEulaVersion = '1.0.0';
const acceptedPrivacyNoticeVersion = '1.0.0';
const acceptedDpaVersion = '1.0.0';
overrideAdB2cService(service, {
@ -144,6 +145,7 @@ describe('createAccount', () => {
username,
role,
acceptedEulaVersion,
acceptedPrivacyNoticeVersion,
acceptedDpaVersion,
);
// 作成したアカウントのIDが返ってくるか確認
@ -161,6 +163,9 @@ describe('createAccount', () => {
expect(account?.primary_admin_user_id).toBe(user?.id);
expect(account?.secondary_admin_user_id).toBe(null);
expect(user?.accepted_eula_version).toBe(acceptedEulaVersion);
expect(user?.accepted_privacy_notice_version).toBe(
acceptedPrivacyNoticeVersion,
);
expect(user?.accepted_dpa_version).toBe(acceptedDpaVersion);
expect(user?.account_id).toBe(accountId);
expect(user?.role).toBe(role);
@ -195,6 +200,7 @@ describe('createAccount', () => {
const username = 'dummy_username';
const role = 'admin none';
const acceptedEulaVersion = '1.0.0';
const acceptedPrivacyNoticeVersion = '1.0.0';
const acceptedDpaVersion = '1.0.0';
overrideAdB2cService(service, {
@ -216,6 +222,7 @@ describe('createAccount', () => {
username,
role,
acceptedEulaVersion,
acceptedPrivacyNoticeVersion,
acceptedDpaVersion,
);
} catch (e) {
@ -264,6 +271,7 @@ describe('createAccount', () => {
const username = 'dummy_username';
const role = 'admin none';
const acceptedEulaVersion = '1.0.0';
const acceptedPrivacyNoticeVersion = '1.0.0';
const acceptedDpaVersion = '1.0.0';
overrideAdB2cService(service, {
@ -286,6 +294,7 @@ describe('createAccount', () => {
username,
role,
acceptedEulaVersion,
acceptedPrivacyNoticeVersion,
acceptedDpaVersion,
);
} catch (e) {
@ -318,6 +327,7 @@ describe('createAccount', () => {
const username = 'dummy_username';
const role = 'none';
const acceptedEulaVersion = '1.0.0';
const acceptedPrivacyNoticeVersion = '1.0.0';
const acceptedDpaVersion = '1.0.0';
overrideAdB2cService(service, {
@ -345,6 +355,7 @@ describe('createAccount', () => {
username,
role,
acceptedEulaVersion,
acceptedPrivacyNoticeVersion,
acceptedDpaVersion,
);
} catch (e) {
@ -384,6 +395,7 @@ describe('createAccount', () => {
const username = 'dummy_username';
const role = 'none';
const acceptedEulaVersion = '1.0.0';
const acceptedPrivacyNoticeVersion = '1.0.0';
const acceptedDpaVersion = '1.0.0';
overrideAdB2cService(service, {
@ -411,6 +423,7 @@ describe('createAccount', () => {
username,
role,
acceptedEulaVersion,
acceptedPrivacyNoticeVersion,
acceptedDpaVersion,
);
} catch (e) {
@ -452,6 +465,7 @@ describe('createAccount', () => {
const username = 'dummy_username';
const role = 'none';
const acceptedEulaVersion = '1.0.0';
const acceptedPrivacyNoticeVersion = '1.0.0';
const acceptedDpaVersion = '1.0.0';
overrideAdB2cService(service, {
@ -480,6 +494,7 @@ describe('createAccount', () => {
username,
role,
acceptedEulaVersion,
acceptedPrivacyNoticeVersion,
acceptedDpaVersion,
);
} catch (e) {
@ -520,6 +535,7 @@ describe('createAccount', () => {
const username = 'dummy_username';
const role = 'none';
const acceptedEulaVersion = '1.0.0';
const acceptedPrivacyNoticeVersion = '1.0.0';
const acceptedDpaVersion = '1.0.0';
overrideAdB2cService(service, {
@ -551,6 +567,7 @@ describe('createAccount', () => {
username,
role,
acceptedEulaVersion,
acceptedPrivacyNoticeVersion,
acceptedDpaVersion,
);
} catch (e) {
@ -593,6 +610,7 @@ describe('createAccount', () => {
const username = 'dummy_username';
const role = 'none';
const acceptedEulaVersion = '1.0.0';
const acceptedPrivacyNoticeVersion = '1.0.0';
const acceptedDpaVersion = '1.0.0';
overrideAdB2cService(service, {
@ -641,6 +659,7 @@ describe('createAccount', () => {
username,
role,
acceptedEulaVersion,
acceptedPrivacyNoticeVersion,
acceptedDpaVersion,
);
} catch (e) {
@ -689,6 +708,7 @@ describe('createAccount', () => {
const username = 'dummy_username';
const role = 'none';
const acceptedEulaVersion = '1.0.0';
const acceptedPrivacyNoticeVersion = '1.0.0';
const acceptedDpaVersion = '1.0.0';
overrideAdB2cService(service, {
@ -734,6 +754,7 @@ describe('createAccount', () => {
username,
role,
acceptedEulaVersion,
acceptedPrivacyNoticeVersion,
acceptedDpaVersion,
);
} catch (e) {

View File

@ -176,6 +176,7 @@ export class AccountsService {
username: string,
role: string,
acceptedEulaVersion: string,
acceptedPrivacyNoticeVersion: string,
acceptedDpaVersion: string,
): Promise<{ accountId: number; userId: number; externalUserId: string }> {
this.logger.log(
@ -185,6 +186,7 @@ export class AccountsService {
`dealerAccountId: ${dealerAccountId}, ` +
`role: ${role}, ` +
`acceptedEulaVersion: ${acceptedEulaVersion}, ` +
`acceptedPrivacyNoticeVersion: ${acceptedPrivacyNoticeVersion}, ` +
`acceptedDpaVersion: ${acceptedDpaVersion} };`,
);
try {
@ -233,6 +235,7 @@ export class AccountsService {
externalUser.sub,
role,
acceptedEulaVersion,
acceptedPrivacyNoticeVersion,
acceptedDpaVersion,
);
account = newAccount;

View File

@ -45,6 +45,8 @@ export class CreateAccountRequest {
adminPassword: string;
@ApiProperty({ description: '同意済み利用規約のバージョン(EULA)' })
acceptedEulaVersion: string;
@ApiProperty({ description: '同意済みプライバシーポリシーのバージョン' })
acceptedPrivacyNoticeVersion: string;
@ApiProperty({ description: '同意済み利用規約のバージョン(DPA)' })
acceptedDpaVersion: string;
@ApiProperty({ description: 'reCAPTCHA Token' })

View File

@ -196,6 +196,7 @@ describe('checkIsAcceptedLatestVersion', () => {
};
await createTermInfo(source, 'EULA', '1.0');
await createTermInfo(source, 'PrivacyNotice', '1.0');
await createTermInfo(source, 'DPA', '1.0');
const result = await service.isAcceptedLatestVersion(context, idToken);
expect(result).toBe(true);
@ -219,6 +220,7 @@ describe('checkIsAcceptedLatestVersion', () => {
};
await createTermInfo(source, 'EULA', '1.0');
await createTermInfo(source, 'PrivacyNotice', '1.0');
await createTermInfo(source, 'DPA', '1.0');
const result = await service.isAcceptedLatestVersion(context, idToken);
expect(result).toBe(true);
@ -242,6 +244,7 @@ describe('checkIsAcceptedLatestVersion', () => {
};
await createTermInfo(source, 'EULA', '1.1');
await createTermInfo(source, 'PrivacyNotice', '1.0');
await createTermInfo(source, 'DPA', '1.0');
const result = await service.isAcceptedLatestVersion(context, idToken);
expect(result).toBe(false);
@ -265,6 +268,7 @@ describe('checkIsAcceptedLatestVersion', () => {
};
await createTermInfo(source, 'EULA', '1.1');
await createTermInfo(source, 'PrivacyNotice', '1.0');
await createTermInfo(source, 'DPA', '1.0');
const result = await service.isAcceptedLatestVersion(context, idToken);
expect(result).toBe(false);
@ -288,10 +292,35 @@ describe('checkIsAcceptedLatestVersion', () => {
};
await createTermInfo(source, 'EULA', '1.0');
await createTermInfo(source, 'PrivacyNotice', '1.0');
await createTermInfo(source, 'DPA', '1.1');
const result = await service.isAcceptedLatestVersion(context, idToken);
expect(result).toBe(false);
});
it('同意済みプライバシーポリシーが最新でないときにチェックが通らないこと(第一~第四)', async () => {
if (!source) fail();
const module = await makeTestingModule(source);
if (!module) fail();
const service = module.get<AuthService>(AuthService);
const { admin } = await makeTestAccount(source, {
tier: 4,
});
const context = makeContext(uuidv4());
const idToken = {
emails: [],
sub: admin.external_id,
exp: 0,
iat: 0,
};
await createTermInfo(source, 'EULA', '1.0');
await createTermInfo(source, 'PrivacyNotice', '1.1');
await createTermInfo(source, 'DPA', '1.0');
const result = await service.isAcceptedLatestVersion(context, idToken);
expect(result).toBe(false);
});
});
describe('generateDelegationRefreshToken', () => {

View File

@ -689,28 +689,38 @@ export class AuthService {
const {
acceptedEulaVersion,
latestEulaVersion,
acceptedPrivacyNoticeVersion,
latestPrivacyNoticeVersion,
acceptedDpaVersion,
latestDpaVersion,
tier,
} = await this.usersRepository.getAcceptedAndLatestVersion(idToken.sub);
// 第五階層はEULAのみ判定
// 第五階層はEULAとPrivacyNoticeのみ判定
if (tier === TIERS.TIER5) {
if (!acceptedEulaVersion) {
if (!acceptedEulaVersion || !acceptedPrivacyNoticeVersion) {
return false;
}
// 最新バージョンに同意済みか判定
const eulaAccepted = acceptedEulaVersion === latestEulaVersion;
return eulaAccepted;
const privacyNoticeAccepted =
acceptedPrivacyNoticeVersion === latestPrivacyNoticeVersion;
return eulaAccepted && privacyNoticeAccepted;
} else {
// 第一第四階層はEULA、DPAを判定
if (!acceptedEulaVersion || !acceptedDpaVersion) {
// 第一第四階層はEULA、PrivacyNotice、DPAを判定
if (
!acceptedEulaVersion ||
!acceptedPrivacyNoticeVersion ||
!acceptedDpaVersion
) {
return false;
}
// 最新バージョンに同意済みか判定
const eulaAccepted = acceptedEulaVersion === latestEulaVersion;
const privacyNoticeAccepted =
acceptedPrivacyNoticeVersion === latestPrivacyNoticeVersion;
const dpaAccepted = acceptedDpaVersion === latestDpaVersion;
return eulaAccepted && dpaAccepted;
return eulaAccepted && privacyNoticeAccepted && dpaAccepted;
}
} catch (e) {
this.logger.error(`[${context.getTrackingId()}] error=${e}`);

View File

@ -22,8 +22,10 @@ export class AccessTokenRequest {}
export type TermsCheckInfo = {
tier: number;
acceptedEulaVersion?: string;
acceptedPrivacyNoticeVersion?: string;
acceptedDpaVersion?: string;
latestEulaVersion: string;
latestPrivacyNoticeVersion: string;
latestDpaVersion: string;
};

View File

@ -139,6 +139,7 @@ export const makeDefaultUsersRepositoryMockValue =
role: 'none',
author_id: '',
accepted_eula_version: '1.0',
accepted_privacy_notice_version: '1.0',
accepted_dpa_version: '1.0',
email_verified: true,
deleted_at: null,

View File

@ -470,6 +470,7 @@ const defaultTasksRepositoryMockValue: {
external_id: 'userId',
role: 'typist',
accepted_eula_version: '',
accepted_privacy_notice_version: '',
accepted_dpa_version: '',
email_verified: true,
auto_renew: true,

View File

@ -34,6 +34,8 @@ describe('利用規約取得', () => {
await createTermInfo(source, 'EULA', 'v1.0');
await createTermInfo(source, 'EULA', 'v1.1');
await createTermInfo(source, 'PrivacyNotice', 'v1.0');
await createTermInfo(source, 'PrivacyNotice', 'v1.1');
await createTermInfo(source, 'DPA', 'v1.0');
await createTermInfo(source, 'DPA', 'v1.2');
@ -42,8 +44,10 @@ describe('利用規約取得', () => {
expect(result[0].documentType).toBe('EULA');
expect(result[0].version).toBe('v1.1');
expect(result[1].documentType).toBe('DPA');
expect(result[1].version).toBe('v1.2');
expect(result[1].documentType).toBe('PrivacyNotice');
expect(result[1].version).toBe('v1.1');
expect(result[2].documentType).toBe('DPA');
expect(result[2].version).toBe('v1.2');
});
it('利用規約情報(EULA、DPA両方)が存在しない場合エラーとなる', async () => {
@ -75,6 +79,21 @@ describe('利用規約取得', () => {
);
});
it('利用規約情報(PrivacyNoticeのみ)が存在しない場合エラーとなる', async () => {
if (!source) fail();
const module = await makeTestingModule(source);
if (!module) fail();
const service = module.get<TermsService>(TermsService);
await createTermInfo(source, 'PrivacyNotice', 'v1.0');
const context = makeContext(uuidv4());
await expect(service.getTermsInfo(context)).rejects.toEqual(
new HttpException(
makeErrorResponse('E009999'),
HttpStatus.INTERNAL_SERVER_ERROR,
),
);
});
it('利用規約情報(DPAのみ)が存在しない場合エラーとなる', async () => {
if (!source) fail();
const module = await makeTestingModule(source);

View File

@ -19,13 +19,17 @@ export class TermsService {
`[IN] [${context.getTrackingId()}] ${this.getTermsInfo.name}`,
);
try {
const { eulaVersion, dpaVersion } =
const { eulaVersion, privacyNoticeVersion, dpaVersion } =
await this.termsRepository.getLatestTermsInfo();
return [
{
documentType: TERM_TYPE.EULA,
version: eulaVersion,
},
{
documentType: TERM_TYPE.PRIVACY_NOTICE,
version: privacyNoticeVersion,
},
{
documentType: TERM_TYPE.DPA,
version: dpaVersion,

View File

@ -13,5 +13,6 @@ export class GetTermsInfoResponse {
export type TermsVersion = {
eulaVersion: string;
privacyNoticeVersion: string;
dpaVersion: string;
};

View File

@ -263,6 +263,8 @@ export class UpdateAcceptedVersionRequest {
idToken: string;
@ApiProperty({ description: '更新バージョンEULA' })
acceptedEULAVersion: string;
@ApiProperty({ description: '更新バージョンPrivacyNotice' })
acceptedPrivacyNoticeVersion: string;
@ApiProperty({ description: '更新バージョンDPA', required: false })
acceptedDPAVersion?: string;
}

View File

@ -627,7 +627,12 @@ export class UsersController {
async updateAcceptedVersion(
@Body() body: UpdateAcceptedVersionRequest,
): Promise<UpdateAcceptedVersionResponse> {
const { idToken, acceptedEULAVersion, acceptedDPAVersion } = body;
const {
idToken,
acceptedEULAVersion,
acceptedPrivacyNoticeVersion,
acceptedDPAVersion,
} = body;
const context = makeContext(uuidv4());
@ -650,6 +655,7 @@ export class UsersController {
context,
verifiedIdToken.sub,
acceptedEULAVersion,
acceptedPrivacyNoticeVersion,
acceptedDPAVersion,
);
return {};

View File

@ -208,6 +208,7 @@ describe('UsersService.confirmUserAndInitPassword', () => {
account_id: 1,
role: 'None',
accepted_eula_version: 'string',
accepted_privacy_notice_version: 'string',
accepted_dpa_version: 'string',
email_verified: false,
created_by: 'string;',
@ -259,6 +260,7 @@ describe('UsersService.confirmUserAndInitPassword', () => {
account_id: 1,
role: 'None',
accepted_eula_version: 'string',
accepted_privacy_notice_version: 'string',
accepted_dpa_version: 'string',
email_verified: false,
created_by: 'string;',
@ -306,6 +308,7 @@ describe('UsersService.confirmUserAndInitPassword', () => {
account_id: 1,
role: 'None',
accepted_eula_version: 'string',
accepted_privacy_notice_version: 'string',
accepted_dpa_version: 'string',
email_verified: true,
created_by: 'string;',
@ -358,6 +361,7 @@ describe('UsersService.confirmUserAndInitPassword', () => {
account_id: 1,
role: 'None',
accepted_eula_version: 'string',
accepted_privacy_notice_version: 'string',
accepted_dpa_version: 'string',
email_verified: false,
created_by: 'string;',
@ -2617,7 +2621,12 @@ describe('UsersService.updateAcceptedVersion', () => {
const context = makeContext(uuidv4());
const service = module.get<UsersService>(UsersService);
await service.updateAcceptedVersion(context, admin.external_id, 'v2.0');
await service.updateAcceptedVersion(
context,
admin.external_id,
'v2.0',
'v2.0',
);
const user = await getUser(source, admin.id);
expect(user?.accepted_eula_version).toBe('v2.0');
@ -2637,6 +2646,7 @@ describe('UsersService.updateAcceptedVersion', () => {
context,
admin.external_id,
'v2.0',
'v2.0',
'v3.0',
);
const user = await getUser(source, admin.id);
@ -2660,6 +2670,7 @@ describe('UsersService.updateAcceptedVersion', () => {
context,
admin.external_id,
'v2.0',
'v2.0',
undefined,
),
).rejects.toEqual(

View File

@ -403,6 +403,7 @@ export class UsersService {
role,
accepted_dpa_version: null,
accepted_eula_version: null,
accepted_privacy_notice_version: null,
encryption: false,
encryption_password: null,
prompt: false,
@ -422,6 +423,7 @@ export class UsersService {
prompt: prompt ?? false,
accepted_dpa_version: null,
accepted_eula_version: null,
accepted_privacy_notice_version: null,
};
default:
//不正なroleが指定された場合はログを出力してエラーを返す
@ -1044,12 +1046,14 @@ export class UsersService {
* @param context
* @param idToken
* @param eulaVersion
* @param privacyNoticeVersion
* @param dpaVersion
*/
async updateAcceptedVersion(
context: Context,
externalId: string,
eulaVersion: string,
privacyNoticeVersion: string,
dpaVersion?: string,
): Promise<void> {
this.logger.log(
@ -1058,6 +1062,7 @@ export class UsersService {
} | params: { ` +
`externalId: ${externalId}, ` +
`eulaVersion: ${eulaVersion}, ` +
`privacyNoticeVersion: ${privacyNoticeVersion}, ` +
`dpaVersion: ${dpaVersion}, };`,
);
@ -1065,6 +1070,7 @@ export class UsersService {
await this.usersRepository.updateAcceptedTermsVersion(
externalId,
eulaVersion,
privacyNoticeVersion,
dpaVersion,
);
} catch (e) {

View File

@ -127,6 +127,7 @@ export class AccountsRepositoryService {
adminExternalUserId: string,
adminUserRole: string,
adminUserAcceptedEulaVersion?: string,
adminUserAcceptedPrivacyNoticeVersion?: string,
adminUserAcceptedDpaVersion?: string,
): Promise<{ newAccount: Account; adminUser: User }> {
return await this.dataSource.transaction(async (entityManager) => {
@ -148,6 +149,8 @@ export class AccountsRepositoryService {
user.external_id = adminExternalUserId;
user.role = adminUserRole;
user.accepted_eula_version = adminUserAcceptedEulaVersion ?? null;
user.accepted_privacy_notice_version =
adminUserAcceptedPrivacyNoticeVersion ?? null;
user.accepted_dpa_version = adminUserAcceptedDpaVersion ?? null;
}
const usersRepo = entityManager.getRepository(User);

View File

@ -24,6 +24,14 @@ export class TermsRepositoryService {
id: 'DESC',
},
});
const latestPrivacyNoticeInfo = await termRepo.findOne({
where: {
document_type: TERM_TYPE.PRIVACY_NOTICE,
},
order: {
id: 'DESC',
},
});
const latestDpaInfo = await termRepo.findOne({
where: {
document_type: TERM_TYPE.DPA,
@ -33,13 +41,16 @@ export class TermsRepositoryService {
},
});
if (!latestEulaInfo || !latestDpaInfo) {
if (!latestEulaInfo || !latestPrivacyNoticeInfo || !latestDpaInfo) {
throw new TermInfoNotFoundError(
`Terms info is not found. latestEulaInfo: ${latestEulaInfo}, latestDpaInfo: ${latestDpaInfo}`,
`Terms info is not found. latestEulaInfo: ${latestEulaInfo},
latestPrivacyNoticeInfo: ${latestPrivacyNoticeInfo},
latestDpaInfo: ${latestDpaInfo}`,
);
}
return {
eulaVersion: latestEulaInfo.version,
privacyNoticeVersion: latestEulaInfo.version,
dpaVersion: latestDpaInfo.version,
};
});

View File

@ -34,6 +34,9 @@ export class User {
@Column({ nullable: true, type: 'varchar' })
accepted_eula_version: string | null;
@Column({ nullable: true, type: 'varchar' })
accepted_privacy_notice_version: string | null;
@Column({ nullable: true, type: 'varchar' })
accepted_dpa_version: string | null;
@ -112,6 +115,9 @@ export class UserArchive {
@Column({ nullable: true, type: 'varchar' })
accepted_eula_version: string | null;
@Column({ nullable: true, type: 'varchar' })
accepted_privacy_notice_version: string | null;
@Column({ nullable: true, type: 'varchar' })
accepted_dpa_version: string | null;

View File

@ -360,7 +360,7 @@ export class UsersRepositoryService {
},
where: { account_id: accountId },
});
return dbUsers;
});
}
@ -471,6 +471,14 @@ export class UsersRepositoryService {
id: 'DESC',
},
});
const latestPrivacyNoticeInfo = await termRepo.findOne({
where: {
document_type: TERM_TYPE.PRIVACY_NOTICE,
},
order: {
id: 'DESC',
},
});
const latestDpaInfo = await termRepo.findOne({
where: {
document_type: TERM_TYPE.DPA,
@ -479,16 +487,18 @@ export class UsersRepositoryService {
id: 'DESC',
},
});
if (!latestEulaInfo || !latestDpaInfo) {
if (!latestEulaInfo || !latestPrivacyNoticeInfo || !latestDpaInfo) {
throw new TermInfoNotFoundError(`Terms info is not found.`);
}
return {
tier: user.account.tier,
acceptedEulaVersion: user.accepted_eula_version ?? undefined,
acceptedPrivacyNoticeVersion:
user.accepted_privacy_notice_version ?? undefined,
acceptedDpaVersion: user.accepted_dpa_version ?? undefined,
latestEulaVersion: latestEulaInfo.version,
latestPrivacyNoticeVersion: latestPrivacyNoticeInfo.version,
latestDpaVersion: latestDpaInfo.version,
};
});
@ -498,12 +508,14 @@ export class UsersRepositoryService {
*
* @param externalId
* @param eulaVersion
* @param privacyNoticeVersion
* @param dpaVersion
* @returns update
*/
async updateAcceptedTermsVersion(
externalId: string,
eulaVersion: string,
privacyNoticeVersion: string,
dpaVersion: string | undefined,
): Promise<void> {
await this.dataSource.transaction(async (entityManager) => {
@ -531,6 +543,11 @@ export class UsersRepositoryService {
if (!eulaVersion) {
throw new UpdateTermsVersionNotSetError(`EULA version param not set.`);
}
if (!privacyNoticeVersion) {
throw new UpdateTermsVersionNotSetError(
`PrivacyNotice version param not set.`,
);
}
if (user.account.tier !== TIERS.TIER5 && !dpaVersion) {
throw new UpdateTermsVersionNotSetError(
`DPA version param not set. User's tier: ${user.account.tier}`,
@ -538,6 +555,8 @@ export class UsersRepositoryService {
}
user.accepted_eula_version = eulaVersion;
user.accepted_privacy_notice_version =
privacyNoticeVersion ?? user.accepted_privacy_notice_version;
user.accepted_dpa_version = dpaVersion ?? user.accepted_dpa_version;
await userRepo.update({ id: user.id }, user);
});