password process of login is modified

This commit is contained in:
병준 박 2019-11-28 15:48:36 +09:00
parent 3fd92b2df5
commit c5d61417f3
19 changed files with 372 additions and 11 deletions

View File

@ -0,0 +1 @@
<ucap-account-change-password></ucap-account-change-password>

View File

@ -0,0 +1,27 @@
/* tslint:disable:no-unused-variable */
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { By } from '@angular/platform-browser';
import { DebugElement } from '@angular/core';
import { ChangePasswordDialogComponent } from './change-password.dialog.component';
describe('ChangePasswordDialogComponent', () => {
let component: ChangePasswordDialogComponent;
let fixture: ComponentFixture<ChangePasswordDialogComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ChangePasswordDialogComponent]
}).compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(ChangePasswordDialogComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@ -0,0 +1,56 @@
import { Component, OnInit, Inject, OnDestroy } from '@angular/core';
import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material';
import { KEY_LOGIN_RES_INFO } from '@app/types/login-res-info.type';
import { KEY_VER_INFO } from '@app/types/ver-info.type';
import { SessionStorageService } from '@ucap-webmessenger/web-storage';
import { Store } from '@ngrx/store';
import { UserInfo } from '@ucap-webmessenger/protocol-sync';
import {
UserInfoSS,
UserInfoF,
UserInfoDN
} from '@ucap-webmessenger/protocol-query';
import { DialogService } from '@ucap-webmessenger/ui';
import { VersionInfo2Response } from '@ucap-webmessenger/api-public';
import { LoginResponse } from '@ucap-webmessenger/protocol-authentication';
export interface ChangePasswordDialogData {}
export interface ChangePasswordDialogResult {
choice: boolean;
}
@Component({
selector: 'app-change-password.dialog',
templateUrl: './change-password.dialog.component.html',
styleUrls: ['./change-password.dialog.component.scss']
})
export class ChangePasswordDialogComponent implements OnInit, OnDestroy {
loginRes: LoginResponse;
sessionVerinfo: VersionInfo2Response;
isMe: boolean;
constructor(
public dialogRef: MatDialogRef<
ChangePasswordDialogData,
ChangePasswordDialogResult
>,
@Inject(MAT_DIALOG_DATA) public data: ChangePasswordDialogData,
private dialogService: DialogService,
private sessionStorageService: SessionStorageService,
private store: Store<any>
) {
this.sessionVerinfo = this.sessionStorageService.get<VersionInfo2Response>(
KEY_VER_INFO
);
this.loginRes = this.sessionStorageService.get<LoginResponse>(
KEY_LOGIN_RES_INFO
);
}
ngOnInit() {}
ngOnDestroy(): void {}
}

View File

@ -0,0 +1,3 @@
import { ChangePasswordDialogComponent } from './change-password.dialog.component';
export const DIALOGS = [ChangePasswordDialogComponent];

View File

@ -1,3 +1,4 @@
import { DIALOGS as ACCOUNT_DIALOGS } from './account';
import { DIALOGS as CHAT_DIALOGS } from './chat'; import { DIALOGS as CHAT_DIALOGS } from './chat';
import { DIALOGS as GROUP_DIALOGS } from './group'; import { DIALOGS as GROUP_DIALOGS } from './group';
import { DIALOGS as MESSAGE_DIALOGS } from './message'; import { DIALOGS as MESSAGE_DIALOGS } from './message';
@ -5,6 +6,7 @@ import { DIALOGS as PROFILE_DIALOGS } from './profile';
import { DIALOGS as SETTINGS_DIALOGS } from './settings'; import { DIALOGS as SETTINGS_DIALOGS } from './settings';
export const DIALOGS = [ export const DIALOGS = [
...ACCOUNT_DIALOGS,
...CHAT_DIALOGS, ...CHAT_DIALOGS,
...GROUP_DIALOGS, ...GROUP_DIALOGS,
...MESSAGE_DIALOGS, ...MESSAGE_DIALOGS,

View File

@ -39,6 +39,7 @@ import { OverlayModule } from '@angular/cdk/overlay';
import { PerfectScrollbarModule } from 'ngx-perfect-scrollbar'; import { PerfectScrollbarModule } from 'ngx-perfect-scrollbar';
import { UCapUiModule } from '@ucap-webmessenger/ui'; import { UCapUiModule } from '@ucap-webmessenger/ui';
import { UCapUiAccountModule } from '@ucap-webmessenger/ui-account';
import { UCapUiChatModule } from '@ucap-webmessenger/ui-chat'; import { UCapUiChatModule } from '@ucap-webmessenger/ui-chat';
import { UCapUiRoomModule } from '@ucap-webmessenger/ui-room'; import { UCapUiRoomModule } from '@ucap-webmessenger/ui-room';
import { UCapUiProfileModule } from '@ucap-webmessenger/ui-profile'; import { UCapUiProfileModule } from '@ucap-webmessenger/ui-profile';
@ -87,6 +88,7 @@ import { DIALOGS } from './dialogs';
PerfectScrollbarModule, PerfectScrollbarModule,
UCapUiModule, UCapUiModule,
UCapUiAccountModule,
UCapUiChatModule, UCapUiChatModule,
UCapUiRoomModule, UCapUiRoomModule,
UCapUiProfileModule, UCapUiProfileModule,

View File

@ -32,6 +32,7 @@ export class AppAuthenticationService {
this.sessionStorageService.set<LoginInfo>(KEY_LOGIN_INFO, { this.sessionStorageService.set<LoginInfo>(KEY_LOGIN_INFO, {
...loginInfo, ...loginInfo,
initPw: loginInfo.loginId === loginInfo.loginPw,
loginPw: CryptoJS.enc.Hex.stringify(CryptoJS.SHA256(loginInfo.loginPw)) loginPw: CryptoJS.enc.Hex.stringify(CryptoJS.SHA256(loginInfo.loginPw))
}); });

View File

@ -61,6 +61,11 @@ import { KEY_LOGIN_RES_INFO } from '@app/types/login-res-info.type';
import { ProtocolService } from '@ucap-webmessenger/protocol'; import { ProtocolService } from '@ucap-webmessenger/protocol';
import { environment } from '../../../../environments/environment'; import { environment } from '../../../../environments/environment';
import {
ChangePasswordDialogComponent,
ChangePasswordDialogData,
ChangePasswordDialogResult
} from '@app/layouts/messenger/dialogs/account/change-password.dialog.component';
@Injectable() @Injectable()
export class Effects { export class Effects {
@ -133,10 +138,9 @@ export class Effects {
tap(authed => { tap(authed => {
// this.ngZone.run(() => { // this.ngZone.run(() => {
// location.href = this.router.parseUrl('/account/login').toString(); // location.href = this.router.parseUrl('/account/login').toString();
this.router.navigate(['/account/login']);
this.appAuthenticationService.logout(); this.appAuthenticationService.logout();
this.store.dispatch(logoutInitialize()); this.store.dispatch(logoutInitialize());
this.router.navigate(['/account/login']);
// }); // });
}) })
), ),
@ -239,7 +243,13 @@ export class Effects {
} }
} }
if (!!loginRes.passwordExpired) { if (loginInfo.initPw) {
this.store.dispatch(logout());
const passwordInitStep1Url = this.piService.passwordInitStep1Url({
localeCode: loginInfo.localeCode
});
const result = await this.dialogService.open< const result = await this.dialogService.open<
ConfirmDialogComponent, ConfirmDialogComponent,
ConfirmDialogData, ConfirmDialogData,
@ -249,8 +259,8 @@ export class Effects {
height: '500px', height: '500px',
disableClose: true, disableClose: true,
data: { data: {
title: '패스워드 만료', title: '패스워드 초기화',
message: '' html: `<iframe id="ifm_privacy" src="${passwordInitStep1Url}" style="width: 100%;height: 300px;" />`
} }
}); });
@ -259,6 +269,24 @@ export class Effects {
return; return;
} }
} }
if (!!loginRes.passwordExpired) {
const result = await this.dialogService.open<
ChangePasswordDialogComponent,
ChangePasswordDialogData,
ChangePasswordDialogResult
>(ChangePasswordDialogComponent, {
width: '500px',
height: '500px',
disableClose: false,
data: {}
});
if (!!result && result.choice) {
} else {
return;
}
}
}) })
), ),
{ dispatch: false } { dispatch: false }

View File

@ -5,6 +5,7 @@ export const KEY_LOGIN_INFO = 'ucap::LOGIN_INFO';
export interface LoginInfo { export interface LoginInfo {
loginId?: string; loginId?: string;
loginPw?: string; loginPw?: string;
initPw?: boolean;
companyCode?: string; companyCode?: string;
companyGroupType?: string; companyGroupType?: string;
localeCode?: LocaleCode; localeCode?: LocaleCode;

View File

@ -0,0 +1,17 @@
import { PIRequest } from './pi';
import { LocaleCode } from '@ucap-webmessenger/core';
import { APIEncoder, ParameterUtil } from '@ucap-webmessenger/api';
export interface PasswordInitStep1Request extends PIRequest {
localeCode: LocaleCode;
}
const passwordInitStep1EncodeMap = {
localeCode: 'locale'
};
export const encodePasswordInitStep1: APIEncoder<PasswordInitStep1Request> = (
req: PasswordInitStep1Request
) => {
return ParameterUtil.encode(passwordInitStep1EncodeMap, req);
};

View File

@ -8,7 +8,7 @@ import {
Login2Request, Login2Request,
Login2Response, Login2Response,
encodeLogin2, encodeLogin2,
decodeLogin2, decodeLogin2
} from '../apis/login2'; } from '../apis/login2';
import { PrivacyTotalRequest, encodePrivacyTotal } from '../apis/privacy-total'; import { PrivacyTotalRequest, encodePrivacyTotal } from '../apis/privacy-total';
import { UrlUtil, Parameter } from '@ucap-webmessenger/api'; import { UrlUtil, Parameter } from '@ucap-webmessenger/api';
@ -16,8 +16,12 @@ import {
UserTermsActionRequest, UserTermsActionRequest,
UserTermsActionResponse, UserTermsActionResponse,
encodeUserTermsAction, encodeUserTermsAction,
decodeUserTermsAction, decodeUserTermsAction
} from '../apis/user-terms-action'; } from '../apis/user-terms-action';
import {
PasswordInitStep1Request,
encodePasswordInitStep1
} from '../apis/password-init-step1';
import { _MODULE_CONFIG } from '../config/token'; import { _MODULE_CONFIG } from '../config/token';
import { ModuleConfig } from '../config/module-config'; import { ModuleConfig } from '../config/module-config';
@ -25,7 +29,7 @@ import { Urls } from '../config/urls';
import { UrlConfig } from '@ucap-webmessenger/core'; import { UrlConfig } from '@ucap-webmessenger/core';
@Injectable({ @Injectable({
providedIn: 'root', providedIn: 'root'
}) })
export class PiService { export class PiService {
readonly urls: Urls; readonly urls: Urls;
@ -46,7 +50,7 @@ export class PiService {
this.urls.login2, this.urls.login2,
{}, {},
{ {
params: encodeLogin2(req), params: encodeLogin2(req)
} }
) )
.pipe(map(res => decodeLogin2(res))); .pipe(map(res => decodeLogin2(res)));
@ -60,7 +64,7 @@ export class PiService {
this.urls.userTermsAction, this.urls.userTermsAction,
{}, {},
{ {
params: encodeUserTermsAction(req), params: encodeUserTermsAction(req)
} }
) )
.pipe(map(res => decodeUserTermsAction(res))); .pipe(map(res => decodeUserTermsAction(res)));
@ -75,4 +79,14 @@ export class PiService {
encodePrivacyTotal(req) as Parameter encodePrivacyTotal(req) as Parameter
); );
} }
/**
* passwordInitStep1Url
*/
public passwordInitStep1Url(req: PasswordInitStep1Request): string {
return UrlUtil.format(
this.urls.passwordInitStep1,
encodePasswordInitStep1(req) as Parameter
);
}
} }

View File

@ -6,6 +6,7 @@ export * from './lib/apis/pi';
export * from './lib/apis/login2'; export * from './lib/apis/login2';
export * from './lib/apis/privacy-total'; export * from './lib/apis/privacy-total';
export * from './lib/apis/user-terms-action'; export * from './lib/apis/user-terms-action';
export * from './lib/apis/password-init-step1';
export * from './lib/types/response-status.type'; export * from './lib/types/response-status.type';

View File

@ -0,0 +1,52 @@
<div class="change-password-form">
<div class="mat-title">비밀번호 변경</div>
<form name="changePasswordForm" [formGroup]="changePasswordForm" novalidate>
<mat-form-field>
<mat-label>현재 패스워드</mat-label>
<input
matInput
type="password"
formControlName="currentLoginPw"
#currentLoginPw
/>
<mat-error>
현재 패스워드를 입력해 주세요
</mat-error>
</mat-form-field>
<mat-form-field>
<mat-label>신규 패스워드</mat-label>
<input
matInput
type="password"
formControlName="newLoginPw"
#newLoginPw
/>
<mat-error>
신규 패스워드를 입력해 주세요
</mat-error>
</mat-form-field>
<mat-form-field>
<mat-label>신규 패스워드 확인</mat-label>
<input
matInput
type="password"
formControlName="newConfirmLoginPw"
#newConfirmLoginPw
/>
<mat-error>
신규 패스워드 확인을 입력해 주세요
</mat-error>
</mat-form-field>
<button
mat-raised-button
class="submit-button bg-accent-dark"
aria-label="패스워드 변경"
[disabled]="changePasswordForm.invalid || !changePasswordBtnEnable"
(click)="onClickLogin()"
>
패스워드 변경
</button>
</form>
</div>

View File

@ -0,0 +1,63 @@
.change-password-form {
position: relative;
width: 384px;
max-width: 384px;
padding: 50px;
text-align: center;
background-color: rgba(255, 255, 255, 0.8);
border-radius: 0px;
box-shadow: 4px 4px 0px rgba(0, 0, 0, 0.1);
.mat-title {
margin: 16px 0 32px 0;
}
form {
width: 100%;
text-align: left;
mat-form-field {
width: 100%;
}
.submit-button {
width: 100%;
margin: 0 auto;
display: block;
}
}
.separator {
font-size: 15px;
font-weight: 600;
margin: 24px auto;
position: relative;
overflow: hidden;
width: 100px;
.text {
display: inline-flex;
position: relative;
padding: 0 8px;
z-index: 9999;
&:before,
&:after {
content: '';
display: block;
width: 30px;
position: absolute;
top: 10px;
border-top: 1px solid;
}
&:before {
right: 100%;
}
&:after {
left: 100%;
}
}
}
}

View File

@ -0,0 +1,24 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { ChangePasswordComponent } from './change-password.component';
describe('Account::ChangePasswordComponent', () => {
let component: ChangePasswordComponent;
let fixture: ComponentFixture<ChangePasswordComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ChangePasswordComponent]
}).compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(ChangePasswordComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@ -0,0 +1,67 @@
import {
Component,
OnInit,
Input,
Output,
EventEmitter,
ViewChild,
ElementRef,
ChangeDetectorRef
} from '@angular/core';
import { FormGroup, FormBuilder, Validators } from '@angular/forms';
import { Company } from '@ucap-webmessenger/api-external';
import { LocalStorageService } from '@ucap-webmessenger/web-storage';
import { LoginInfo, KEY_LOGIN_INFO } from '@app/types';
@Component({
selector: 'ucap-account-change-password',
templateUrl: './change-password.component.html',
styleUrls: ['./change-password.component.scss']
})
export class ChangePasswordComponent implements OnInit {
@Input()
changePasswordBtnEnable: boolean;
@Output()
changePassword = new EventEmitter<{
currentLoginPw: string;
newLoginPw: string;
newConfirmLoginPw: string;
notValid: () => void;
}>();
@ViewChild('currentLoginPw', { static: true })
currentLoginPwElementRef: ElementRef;
@ViewChild('newLoginPw', { static: true })
newLoginPwElementRef: ElementRef;
changePasswordForm: FormGroup;
constructor(
private formBuilder: FormBuilder,
private changeDetectorRef: ChangeDetectorRef,
private localStorageService: LocalStorageService
) {}
ngOnInit() {
const loginInfo: LoginInfo = this.localStorageService.get<LoginInfo>(
KEY_LOGIN_INFO
);
this.changePasswordForm = this.formBuilder.group({
currentLoginPw: ['', Validators.required],
newLoginPw: ['', Validators.required],
newConfirmLoginPw: ['', Validators.required]
});
}
onClickLogin() {
this.changePassword.emit({
currentLoginPw: this.changePasswordForm.get('currentLoginPw').value,
newLoginPw: this.changePasswordForm.get('newLoginPw').value,
newConfirmLoginPw: this.changePasswordForm.get('newConfirmLoginPw').value,
notValid: () => {
this.currentLoginPwElementRef.nativeElement.focus();
}
});
}
}

View File

@ -11,11 +11,12 @@ import { MatIconModule } from '@angular/material/icon';
import { MatInputModule } from '@angular/material/input'; import { MatInputModule } from '@angular/material/input';
import { MatSelectModule } from '@angular/material/select'; import { MatSelectModule } from '@angular/material/select';
import { ChangePasswordComponent } from './components/change-password.component';
import { LoginComponent } from './components/login.component'; import { LoginComponent } from './components/login.component';
import { AccountService } from './services/account.service'; import { AccountService } from './services/account.service';
const COMPONENTS = [LoginComponent]; const COMPONENTS = [ChangePasswordComponent, LoginComponent];
const SERVICES = [AccountService]; const SERVICES = [AccountService];
@NgModule({ @NgModule({

View File

@ -3,5 +3,6 @@
*/ */
export * from './lib/services/account.service'; export * from './lib/services/account.service';
export * from './lib/components/change-password.component';
export * from './lib/components/login.component'; export * from './lib/components/login.component';
export * from './lib/ucap-ui-account.module'; export * from './lib/ucap-ui-account.module';