agree of privacy is modified

This commit is contained in:
병준 박 2019-09-24 14:53:22 +09:00
parent e1260bff47
commit c49e7e5931
29 changed files with 426 additions and 20 deletions

View File

@ -0,0 +1,16 @@
import { Parameter } from './parameter.util';
import { HttpParams } from '@angular/common/http';
export class UrlUtil {
public static format(href: string, param: Parameter): string {
const params = new HttpParams({ fromObject: param }).toString();
if (params.length === 0) {
return href;
} else {
const qIdx = href.indexOf('?');
const sep: string = qIdx === -1 ? '?' : qIdx < href.length - 1 ? '&' : '';
return href + sep + params;
}
}
}

View File

@ -7,3 +7,4 @@ export * from './lib/models/api';
export * from './lib/types/status-code.type'; export * from './lib/types/status-code.type';
export * from './lib/utils/parameter.util'; export * from './lib/utils/parameter.util';
export * from './lib/utils/url.util';

View File

@ -68,7 +68,7 @@ export class AppMessengerResolver implements Resolve<void> {
deviceType: loginInfo.deviceType, deviceType: loginInfo.deviceType,
deviceId: ' ', deviceId: ' ',
token: '', token: '',
localeCode: LocaleCode.Korean, localeCode: loginInfo.localeCode,
pushId: ' ', pushId: ' ',
companyCode: loginInfo.companyCode, companyCode: loginInfo.companyCode,
passwordEncodingType: 1, passwordEncodingType: 1,

View File

@ -7,7 +7,7 @@ import {
LocalStorageService LocalStorageService
} from '@ucap-webmessenger/web-storage'; } from '@ucap-webmessenger/web-storage';
import { EnviromentUtilService } from '@ucap-webmessenger/util'; import { EnviromentUtilService } from '@ucap-webmessenger/util';
import { DeviceType } from '@ucap-webmessenger/core'; import { DeviceType, LocaleCode } from '@ucap-webmessenger/core';
import { LoginInfo, KEY_LOGIN_INFO } from '../types'; import { LoginInfo, KEY_LOGIN_INFO } from '../types';
@Injectable({ @Injectable({
@ -30,6 +30,8 @@ export class AppAuthenticationService {
login(loginInfo: LoginInfo, rememberMe: boolean) { login(loginInfo: LoginInfo, rememberMe: boolean) {
let deviceType: DeviceType; let deviceType: DeviceType;
loginInfo = { ...loginInfo, localeCode: LocaleCode.Korean };
if (this.enviromentUtilService.nodeWebkit()) { if (this.enviromentUtilService.nodeWebkit()) {
deviceType = DeviceType.PC; deviceType = DeviceType.PC;
} else if (this.enviromentUtilService.android()) { } else if (this.enviromentUtilService.android()) {

View File

@ -48,7 +48,7 @@ export class Effects {
}) })
.pipe( .pipe(
map((res: Login2Response) => { map((res: Login2Response) => {
if (res.status === ResponseStatus.Fail) { if ('success' !== res.status.toLowerCase()) {
return webLoginFailure({ error: 'Failed' }); return webLoginFailure({ error: 'Failed' });
} else { } else {
return webLoginSuccess({ return webLoginSuccess({

View File

@ -2,16 +2,22 @@ import { Type } from '@angular/core';
import { Action, combineReducers, Selector, createSelector } from '@ngrx/store'; import { Action, combineReducers, Selector, createSelector } from '@ngrx/store';
import * as AuthenticationStore from './authentication'; import * as AuthenticationStore from './authentication';
import * as PrivacyStore from './privacy';
export interface State { export interface State {
authentication: AuthenticationStore.State; authentication: AuthenticationStore.State;
privacy: PrivacyStore.State;
} }
export const effects: Type<any>[] = [AuthenticationStore.Effects]; export const effects: Type<any>[] = [
AuthenticationStore.Effects,
PrivacyStore.Effects
];
export function reducers(state: State | undefined, action: Action) { export function reducers(state: State | undefined, action: Action) {
return combineReducers({ return combineReducers({
authentication: AuthenticationStore.reducer authentication: AuthenticationStore.reducer,
privacy: PrivacyStore.reducer
})(state, action); })(state, action);
} }
@ -22,6 +28,12 @@ export function selectors<S>(selector: Selector<any, State>) {
selector, selector,
(state: State) => state.authentication (state: State) => state.authentication
) )
),
PrivacySelector: PrivacyStore.selectors(
createSelector(
selector,
(state: State) => state.privacy
)
) )
}; };
} }

View File

@ -0,0 +1,25 @@
import { createAction, props } from '@ngrx/store';
import { LoginResponse } from '@ucap-webmessenger/protocol-authentication';
export const agreeConfirmationNotNeeded = createAction(
'[Account::Privacy] Agree Confirmation not needed'
);
export const agreeConfirmationYes = createAction(
'[Account::Privacy] Agree Confirmation Yes',
props<{
loginInfo: LoginResponse;
}>()
);
export const agreeConfirmationNo = createAction(
'[Account::Privacy] Agree Confirmation No'
);
export const agreeSuccess = createAction('[Account::Privacy] Agree Success');
export const agreeFailure = createAction(
'[Account::Privacy] Agree Failure',
props<{ error: any }>()
);

View File

@ -0,0 +1,145 @@
import { Injectable } from '@angular/core';
import { Router } from '@angular/router';
import { Actions, ofType, createEffect } from '@ngrx/effects';
import { of } from 'rxjs';
import { catchError, exhaustMap, map } from 'rxjs/operators';
import {
PiService,
UserTermsActionResponse,
ResponseStatus
} from '@ucap-webmessenger/pi';
import {
DialogService,
ConfirmDialogComponent,
ConfirmDialogData,
ConfirmDialogResult
} from '@ucap-webmessenger/ui';
import { AppAuthenticationService } from '@app/services/authentication.service';
import { loginSuccess, logout } from '../authentication';
import {
agreeConfirmationYes,
agreeConfirmationNo,
agreeConfirmationNotNeeded,
agreeSuccess,
agreeFailure
} from './actions';
import { SessionStorageService } from '@ucap-webmessenger/web-storage';
import { LoginInfo, KEY_LOGIN_INFO } from '@app/types';
import { initSettings } from '@app/store/setting/init';
@Injectable()
export class Effects {
agreeConfirmation$ = createEffect(() =>
this.actions$.pipe(
ofType(loginSuccess),
exhaustMap(async params => {
if (params.loginInfo.privateInformationAgree) {
return null;
}
const loginInfo = this.sessionStorageService.get<LoginInfo>(
KEY_LOGIN_INFO
);
const privacyTotalUrl = this.piService.privacyTotalUrl({
companyCode: params.loginInfo.companyCode,
userSeq: params.loginInfo.userSeq,
token: params.loginInfo.tokenString,
deviceType: loginInfo.deviceType,
localeCode: loginInfo.localeCode,
textOnly: 'true'
});
const result = await this.dialogService.open<
ConfirmDialogComponent,
ConfirmDialogData,
ConfirmDialogResult
>(ConfirmDialogComponent, {
width: '100%',
height: '500px',
disableClose: true,
data: {
title: '개인정보 동의',
html: `<iframe id="ifm_privacy" src="${privacyTotalUrl}" style="width: 100%;height: 300px;" />`
}
});
return {
loginInfo: params.loginInfo,
choice: result.choice
};
}),
map(params => {
if (!params) {
return agreeConfirmationNotNeeded();
}
return params.choice
? agreeConfirmationYes({ loginInfo: params.loginInfo })
: agreeConfirmationNo();
})
)
);
agreeConfirmationYes$ = createEffect(() =>
this.actions$.pipe(
ofType(agreeConfirmationYes),
map(action => {
const loginInfo = this.sessionStorageService.get<LoginInfo>(
KEY_LOGIN_INFO
);
return {
loginInfo,
loginResponse: action.loginInfo
};
}),
exhaustMap(params =>
this.piService
.userTermsAction({
userSeq: params.loginResponse.userSeq,
token: params.loginResponse.tokenString,
deviceType: params.loginInfo.deviceType
})
.pipe(
map((res: UserTermsActionResponse) => {
if ('00' !== res.responseCode) {
return agreeFailure({ error: 'Failed' });
} else {
return agreeSuccess();
}
}),
catchError(error => of(agreeFailure({ error })))
)
)
)
);
agreeSuccess$ = createEffect(() =>
this.actions$.pipe(
ofType(agreeSuccess),
map(() => initSettings())
)
);
agreeFailure$ = createEffect(() =>
this.actions$.pipe(
ofType(agreeFailure),
map(action => action),
map(() => logout())
)
);
constructor(
private actions$: Actions,
private router: Router,
private piService: PiService,
private sessionStorageService: SessionStorageService,
private appAuthenticationService: AppAuthenticationService,
private dialogService: DialogService
) {}
}

View File

@ -0,0 +1,4 @@
export * from './actions';
export * from './effects';
export * from './reducers';
export * from './state';

View File

@ -0,0 +1,4 @@
import { Action, combineReducers, createReducer, on } from '@ngrx/store';
import { State, initialState } from './state';
export const reducer = createReducer(initialState);

View File

@ -0,0 +1,11 @@
import { Selector, createSelector } from '@ngrx/store';
import { LoginResponse } from '@ucap-webmessenger/protocol-authentication';
// tslint:disable-next-line: no-empty-interface
export interface State {}
export const initialState: State = {};
export function selectors<S>(selector: Selector<any, State>) {
return {};
}

View File

@ -1,9 +1,11 @@
import { Type } from '@angular/core'; import { Type } from '@angular/core';
import { Action, combineReducers, Selector, createSelector } from '@ngrx/store'; import { Action, combineReducers, Selector, createSelector } from '@ngrx/store';
import * as InitStore from './init';
import * as VersionInfoStore from './version-info'; import * as VersionInfoStore from './version-info';
export interface State { export interface State {
init: InitStore.State;
versionInfo: VersionInfoStore.State; versionInfo: VersionInfoStore.State;
} }
@ -11,12 +13,19 @@ export const effects: Type<any>[] = [VersionInfoStore.Effects];
export function reducers(state: State | undefined, action: Action) { export function reducers(state: State | undefined, action: Action) {
return combineReducers({ return combineReducers({
init: InitStore.reducer,
versionInfo: VersionInfoStore.reducer versionInfo: VersionInfoStore.reducer
})(state, action); })(state, action);
} }
export function selectors<S>(selector: Selector<any, State>) { export function selectors<S>(selector: Selector<any, State>) {
return { return {
InitSelector: InitStore.selectors(
createSelector(
selector,
(state: State) => state.init
)
),
VersionInfoSelector: VersionInfoStore.selectors( VersionInfoSelector: VersionInfoStore.selectors(
createSelector( createSelector(
selector, selector,

View File

@ -0,0 +1,3 @@
import { createAction } from '@ngrx/store';
export const initSettings = createAction('[Setting::Init] initSettings');

View File

@ -0,0 +1,6 @@
import { Injectable } from '@angular/core';
@Injectable()
export class Effects {
constructor() {}
}

View File

@ -0,0 +1,4 @@
export * from './actions';
export * from './effects';
export * from './reducers';
export * from './state';

View File

@ -0,0 +1,4 @@
import { createReducer, on } from '@ngrx/store';
import { initialState } from './state';
export const reducer = createReducer(initialState);

View File

@ -0,0 +1,10 @@
import { Selector, createSelector } from '@ngrx/store';
// tslint:disable-next-line: no-empty-interface
export interface State {}
export const initialState: State = {};
export function selectors<S>(selector: Selector<any, State>) {
return {};
}

View File

@ -1,4 +1,4 @@
import { DeviceType } from '@ucap-webmessenger/core'; import { DeviceType, LocaleCode } from '@ucap-webmessenger/core';
export const KEY_LOGIN_INFO = 'ucap::LOGIN_INFO'; export const KEY_LOGIN_INFO = 'ucap::LOGIN_INFO';
@ -7,6 +7,6 @@ export interface LoginInfo {
loginPw?: string; loginPw?: string;
companyCode?: string; companyCode?: string;
deviceType?: DeviceType; deviceType?: DeviceType;
lang?: string; localeCode?: LocaleCode;
encData?: string; encData?: string;
} }

View File

@ -153,6 +153,12 @@ export class PiUrlConfig extends UrlConfig {
}); });
} }
public get userTermsAction(): string {
return this.getUrl({
pathname: '/uCapPi/user/terms.action'
});
}
public get passwordInitStep1(): string { public get passwordInitStep1(): string {
return this.getUrl({ return this.getUrl({
pathname: '/uCapPi/password/initStep1' pathname: '/uCapPi/password/initStep1'

View File

@ -9,6 +9,7 @@ export interface Login2Request extends PIRequest {
} }
export interface Login2Response extends PIResponse { export interface Login2Response extends PIResponse {
status: string;
version: string; version: string;
passwordHc: string; passwordHc: string;
personalInfoAgreeYn: string; personalInfoAgreeYn: string;

View File

@ -6,5 +6,4 @@ export interface PIRequest {
export interface PIResponse { export interface PIResponse {
_Id?: string; _Id?: string;
status?: ResponseStatus;
} }

View File

@ -0,0 +1,27 @@
import { PIRequest } from './pi';
import { DeviceType, LocaleCode } from '@ucap-webmessenger/core';
import { APIEncoder, ParameterUtil } from '@ucap-webmessenger/api';
export interface PrivacyTotalRequest extends PIRequest {
companyCode: string;
userSeq: number;
token: string;
deviceType: DeviceType;
localeCode: LocaleCode;
textOnly: string;
}
const privacyTotalEncodeMap = {
companyCode: 'companyCode',
userSeq: 'userSeq',
token: 'tokenKey',
deviceType: 'deviceType',
localeCode: 'locale',
textOnly: 'textOnly'
};
export const encodePrivacyTotal: APIEncoder<PrivacyTotalRequest> = (
req: PrivacyTotalRequest
) => {
return ParameterUtil.encode(privacyTotalEncodeMap, req);
};

View File

@ -0,0 +1,37 @@
import { ParameterUtil, APIEncoder, APIDecoder } from '@ucap-webmessenger/api';
import { PIRequest, PIResponse } from './pi';
import { DeviceType } from '@ucap-webmessenger/core';
export interface UserTermsActionRequest extends PIRequest {
userSeq: number;
token: string;
deviceType: DeviceType;
}
// tslint:disable-next-line: no-empty-interface
export interface UserTermsActionResponse extends PIResponse {
responseCode?: string;
responseMsg?: string;
}
const userTermsActionEncodeMap = {
userSeq: 'userSeq',
token: 'tokenKey',
deviceType: 'deviceType'
};
export const encodeUserTermsAction: APIEncoder<UserTermsActionRequest> = (
req: UserTermsActionRequest
) => {
return ParameterUtil.encode(userTermsActionEncodeMap, req);
};
export const decodeUserTermsAction: APIDecoder<UserTermsActionResponse> = (
res: any
) => {
return {
responseCode: res.responseCode,
responseMsg: res.responseMsg
} as UserTermsActionResponse;
};

View File

@ -5,13 +5,24 @@ import { Observable } from 'rxjs';
import { map } from 'rxjs/operators'; import { map } from 'rxjs/operators';
import { _MODULE_CONFIG } from '../types/token'; import { _MODULE_CONFIG } from '../types/token';
import { ModuleConfig } from '../types/module-config'; import { ModuleConfig, PiUrls } from '../types/module-config';
import { import {
Login2Request, Login2Request,
Login2Response, Login2Response,
encodeLogin2, encodeLogin2,
decodeLogin2 decodeLogin2
} from '../models/login2'; } from '../models/login2';
import {
PrivacyTotalRequest,
encodePrivacyTotal
} from '../models/privacy-total';
import { UrlUtil, Parameter } from '@ucap-webmessenger/api';
import {
UserTermsActionRequest,
UserTermsActionResponse,
encodeUserTermsAction,
decodeUserTermsAction
} from '../models/user-terms-action';
@Injectable({ @Injectable({
providedIn: 'root' providedIn: 'root'
@ -33,4 +44,32 @@ export class PiService {
) )
.pipe(map(res => decodeLogin2(res))); .pipe(map(res => decodeLogin2(res)));
} }
public userTermsAction(
req: UserTermsActionRequest
): Observable<UserTermsActionResponse> {
return this.httpClient
.post<any>(
this.moduleConfig.urls.userTermsAction,
{},
{
params: encodeUserTermsAction(req)
}
)
.pipe(map(res => decodeUserTermsAction(res)));
}
/**
* privacyTotalUrl
*/
public privacyTotalUrl(req: PrivacyTotalRequest): string {
return UrlUtil.format(
this.moduleConfig.urls.policyTotal,
encodePrivacyTotal(req) as Parameter
);
}
public get urls(): PiUrls {
return this.moduleConfig.urls;
}
} }

View File

@ -1,5 +1,24 @@
export interface ModuleConfig { export interface PiUrls {
urls: {
login2: string; login2: string;
}; userTermsAction: string;
passwordInitStep1: string;
passwordChange: string;
policyTotal: string;
policyService: string;
policyPrivacy: string;
tokenCheck: string;
userMobileAuth: string;
userUserAuth: string;
userCall: string;
userMoblieCallAuth: string;
eventSendEventMail: string;
userMobileInitial1: string;
eventSendInvite: string;
userRoom: string;
scheduleRetrieveScheduleList: string;
userScreenCapture: string;
}
export interface ModuleConfig {
urls: PiUrls;
} }

View File

@ -6,6 +6,8 @@ export * from './lib/types/module-config';
export * from './lib/models/pi'; export * from './lib/models/pi';
export * from './lib/models/login2'; export * from './lib/models/login2';
export * from './lib/models/privacy-total';
export * from './lib/models/user-terms-action';
export * from './lib/types/response-status.type'; export * from './lib/types/response-status.type';

View File

@ -1,12 +1,12 @@
<mat-card class="confirm-card"> <mat-card class="confirm-card">
<mat-card-header> <mat-card-header cdkDrag cdkDragRootElement=".cdk-overlay-pane" cdkDragHandle>
<mat-card-title>{{ data.title }}</mat-card-title> <mat-card-title>{{ data.title }}</mat-card-title>
<!-- <mat-card-subtitle>Confirm</mat-card-subtitle> --> <!-- <mat-card-subtitle>Confirm</mat-card-subtitle> -->
</mat-card-header> </mat-card-header>
<mat-card-content> <mat-card-content>
<p class="notice"> <div #messageContainer class="notice">
{{ data.message }} {{ data.message }}
</p> </div>
</mat-card-content> </mat-card-content>
<mat-card-actions class="button-farm flex-row"> <mat-card-actions class="button-farm flex-row">
<button <button

View File

@ -1,9 +1,16 @@
import { Component, OnInit, Inject } from '@angular/core'; import {
Component,
OnInit,
Inject,
ViewChild,
ElementRef
} from '@angular/core';
import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material'; import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material';
export interface ConfirmDialogData { export interface ConfirmDialogData {
title: string; title: string;
message?: string; message?: string;
html?: string;
} }
export interface ConfirmDialogResult { export interface ConfirmDialogResult {
@ -16,14 +23,19 @@ export interface ConfirmDialogResult {
styleUrls: ['./confirm.dialog.component.scss'] styleUrls: ['./confirm.dialog.component.scss']
}) })
export class ConfirmDialogComponent implements OnInit { export class ConfirmDialogComponent implements OnInit {
tempAgeLimits = []; @ViewChild('messageContainer', { static: true })
messageContainer: ElementRef;
constructor( constructor(
public dialogRef: MatDialogRef<ConfirmDialogComponent, ConfirmDialogResult>, public dialogRef: MatDialogRef<ConfirmDialogComponent, ConfirmDialogResult>,
@Inject(MAT_DIALOG_DATA) public data: ConfirmDialogData @Inject(MAT_DIALOG_DATA) public data: ConfirmDialogData
) {} ) {}
ngOnInit(): void {} ngOnInit(): void {
if (!!this.data.html) {
this.messageContainer.nativeElement.innerHTML = this.data.html;
}
}
onClickChoice(choice: boolean): void { onClickChoice(choice: boolean): void {
this.dialogRef.close({ this.dialogRef.close({

View File

@ -5,6 +5,8 @@ import { MatButtonModule } from '@angular/material/button';
import { MatCardModule } from '@angular/material/card'; import { MatCardModule } from '@angular/material/card';
import { MatDialogModule } from '@angular/material/dialog'; import { MatDialogModule } from '@angular/material/dialog';
import { DragDropModule } from '@angular/cdk/drag-drop';
import { BottomSheetService } from './services/bottom-sheet.service'; import { BottomSheetService } from './services/bottom-sheet.service';
import { DialogService } from './services/dialog.service'; import { DialogService } from './services/dialog.service';
const SERVICES = [BottomSheetService, DialogService]; const SERVICES = [BottomSheetService, DialogService];
@ -14,7 +16,13 @@ import { ConfirmDialogComponent } from './dialogs/confirm.dialog.component';
const DIALOGS = [AlertDialogComponent, ConfirmDialogComponent]; const DIALOGS = [AlertDialogComponent, ConfirmDialogComponent];
@NgModule({ @NgModule({
imports: [CommonModule, MatButtonModule, MatCardModule, MatDialogModule], imports: [
CommonModule,
MatButtonModule,
MatCardModule,
MatDialogModule,
DragDropModule
],
exports: [], exports: [],
declarations: [...DIALOGS], declarations: [...DIALOGS],
entryComponents: [...DIALOGS] entryComponents: [...DIALOGS]