ing
This commit is contained in:
parent
2cce12ea37
commit
869fcf4e72
|
@ -1,19 +1,21 @@
|
||||||
import { ProfileComponent } from './profile/profile.component';
|
import { MemberSigninComponent } from './member-signin.component';
|
||||||
import { SigninComponent } from './signin/signin.component';
|
import { MemberSignupComponent } from './member-signup.component';
|
||||||
import { SignupComponent } from './signup/signup.component';
|
import { MemberTermsComponent } from './member-terms.component';
|
||||||
import { ResetPasswordComponent } from './reset-password/reset-password.component';
|
import { MemberResetPasswordComponent } from './member-reset-password.component';
|
||||||
|
import { MemberModifyPasswordComponent } from './member-modify-password.component';
|
||||||
|
import { MemberProfileComponent } from './member-profile.component';
|
||||||
|
import { MemberPolicyComponent } from './member-policy.component';
|
||||||
|
|
||||||
import { SETTINGS_COMPONENTS } from './settings';
|
import { SETTINGS_COMPONENTS } from './settings';
|
||||||
import { PolicyComponent } from './policy/policy.component';
|
|
||||||
import { TermsComponent } from './terms/terms.component';
|
|
||||||
import { ModifyPasswordComponent } from './reset-password/modify-password.component';
|
|
||||||
|
|
||||||
export const COMPONENTS = [
|
export const COMPONENTS = [
|
||||||
ProfileComponent,
|
MemberSigninComponent,
|
||||||
SigninComponent,
|
MemberSignupComponent,
|
||||||
SignupComponent,
|
MemberTermsComponent,
|
||||||
ResetPasswordComponent,
|
MemberResetPasswordComponent,
|
||||||
ModifyPasswordComponent,
|
MemberProfileComponent,
|
||||||
PolicyComponent,
|
MemberModifyPasswordComponent,
|
||||||
TermsComponent,
|
MemberPolicyComponent,
|
||||||
|
|
||||||
SETTINGS_COMPONENTS,
|
SETTINGS_COMPONENTS,
|
||||||
];
|
];
|
||||||
|
|
|
@ -0,0 +1,72 @@
|
||||||
|
<div class="ui-g">
|
||||||
|
<div class="ui-g-12 ui-md-9 ui-lg-7">
|
||||||
|
<form [formGroup]="modifyPasswordForm" (ngSubmit)="modifyPasswordFormSubmit()">
|
||||||
|
<table class="login-table">
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<div class="login-panel ui-fluid">
|
||||||
|
<div class="ui-g">
|
||||||
|
<div class="ui-g-12">
|
||||||
|
<img src="assets/layout/images/overFlow_CI_blue_185.png">
|
||||||
|
</div>
|
||||||
|
<div class="ui-g-12">
|
||||||
|
<span class="md-inputfield">
|
||||||
|
<input type="password"
|
||||||
|
id="pw"
|
||||||
|
autocomplete="off" placeholder="password"
|
||||||
|
formControlName="pw"
|
||||||
|
required class="ui-inputtext ui-corner-all ui-state-default ui-widget">
|
||||||
|
</span>
|
||||||
|
<div *ngIf="formErrors.pw" class="help is-danger">
|
||||||
|
{{ formErrors.pw }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="ui-g-12">
|
||||||
|
<span class="md-inputfield">
|
||||||
|
<input type="password"
|
||||||
|
id="confirmPw"
|
||||||
|
autocomplete="off" placeholder="confirm password"
|
||||||
|
formControlName="confirmPw"
|
||||||
|
required class="ui-inputtext ui-corner-all ui-state-default ui-widget">
|
||||||
|
</span>
|
||||||
|
<div *ngIf="formErrors.confirmPw" class="help is-danger">
|
||||||
|
{{ formErrors.confirmPw }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="ui-g-12">
|
||||||
|
<button type="submit" class="ui-button ui-widget ui-state-default ui-corner-all ui-button-text-icon-left">
|
||||||
|
<span class="ui-button-icon-left ui-c fa fa-fw ui-icon-person"></span>
|
||||||
|
<span class="ui-button-text ui-c">Confirm</span>
|
||||||
|
</button>
|
||||||
|
<a href="javascript:void(0)" (click)="signin.emit()">Signin</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
<div class="ui-g-12 ui-md-3 ui-lg-5 login-descript">
|
||||||
|
<table class="login-table">
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<div class="login-panel ui-fluid">
|
||||||
|
<div class="ui-g">
|
||||||
|
<div class="ui-g-12">
|
||||||
|
<img src="assets/layout/images/login/login_img_01.png">
|
||||||
|
<p><br>
|
||||||
|
overFlow는 여러분의 서버에 발생하는<br>
|
||||||
|
변화를 항상 지켜보고 있습니다.<br><br>
|
||||||
|
|
||||||
|
서버에 발생하는 모든 변화를 세분화 하여<br>
|
||||||
|
실시간으로 알려 드립니다.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
|
@ -0,0 +1,25 @@
|
||||||
|
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { MemberModifyPasswordComponent } from './member-modify-password.component';
|
||||||
|
|
||||||
|
describe('MemberModifyPasswordComponent', () => {
|
||||||
|
let component: MemberModifyPasswordComponent;
|
||||||
|
let fixture: ComponentFixture<MemberModifyPasswordComponent>;
|
||||||
|
|
||||||
|
beforeEach(async(() => {
|
||||||
|
TestBed.configureTestingModule({
|
||||||
|
declarations: [ MemberModifyPasswordComponent ]
|
||||||
|
})
|
||||||
|
.compileComponents();
|
||||||
|
}));
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
fixture = TestBed.createComponent(MemberModifyPasswordComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
|
@ -0,0 +1,51 @@
|
||||||
|
import { Component, OnInit, Output, EventEmitter, Input } from '@angular/core';
|
||||||
|
import { FormGroup, FormBuilder, Validators } from '@angular/forms';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'of-member-modify-password',
|
||||||
|
templateUrl: './member-modify-password.component.html',
|
||||||
|
})
|
||||||
|
export class MemberModifyPasswordComponent implements OnInit {
|
||||||
|
@Input() token: string;
|
||||||
|
@Output() resetPassword = new EventEmitter<{token: string, password: string, confirmPassword: string}>();
|
||||||
|
@Output() signin = new EventEmitter();
|
||||||
|
|
||||||
|
modifyPasswordForm: FormGroup;
|
||||||
|
formErrors = {
|
||||||
|
'pw': '',
|
||||||
|
'confirmPw': ''
|
||||||
|
};
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private formBuilder: FormBuilder,
|
||||||
|
) { }
|
||||||
|
|
||||||
|
ngOnInit() {
|
||||||
|
this.initForm();
|
||||||
|
}
|
||||||
|
|
||||||
|
initForm() {
|
||||||
|
this.modifyPasswordForm = this.formBuilder.group({
|
||||||
|
'pw': [
|
||||||
|
'',
|
||||||
|
[
|
||||||
|
// Validators.required,
|
||||||
|
]
|
||||||
|
],
|
||||||
|
'confirmPw': [
|
||||||
|
'',
|
||||||
|
[
|
||||||
|
// Validators.pattern('^(?=.*[0-9])(?=.*[a-zA-Z])([a-zA-Z0-9]+)$'),
|
||||||
|
// Validators.minLength(6),
|
||||||
|
// Validators.maxLength(25)
|
||||||
|
]
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
modifyPasswordFormSubmit() {
|
||||||
|
const formValue = Object.assign({}, this.modifyPasswordForm.value);
|
||||||
|
this.resetPassword.emit({token: this.token, password: formValue.pw, confirmPassword: formValue.confirmPw});
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,20 +1,20 @@
|
||||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
import { SigninComponent } from './signin.component';
|
import { MemberPolicyComponent } from './member-policy.component';
|
||||||
|
|
||||||
describe('SigninComponent', () => {
|
describe('MemberPolicyComponent', () => {
|
||||||
let component: SigninComponent;
|
let component: MemberPolicyComponent;
|
||||||
let fixture: ComponentFixture<SigninComponent>;
|
let fixture: ComponentFixture<MemberPolicyComponent>;
|
||||||
|
|
||||||
beforeEach(async(() => {
|
beforeEach(async(() => {
|
||||||
TestBed.configureTestingModule({
|
TestBed.configureTestingModule({
|
||||||
declarations: [ SigninComponent ]
|
declarations: [ MemberPolicyComponent ]
|
||||||
})
|
})
|
||||||
.compileComponents();
|
.compileComponents();
|
||||||
}));
|
}));
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
fixture = TestBed.createComponent(SigninComponent);
|
fixture = TestBed.createComponent(MemberPolicyComponent);
|
||||||
component = fixture.componentInstance;
|
component = fixture.componentInstance;
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
});
|
});
|
27
@overflow/member/component/member-policy.component.ts
Normal file
27
@overflow/member/component/member-policy.component.ts
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
import {Component, OnInit, OnDestroy, EventEmitter, Input, Output} from '@angular/core';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'of-member-policy',
|
||||||
|
templateUrl: './member-policy.component.html',
|
||||||
|
})
|
||||||
|
export class MemberPolicyComponent implements OnInit, OnDestroy {
|
||||||
|
|
||||||
|
@Input() policyDisplay;
|
||||||
|
@Output() close = new EventEmitter();
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ngOnInit() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnDestroy() {
|
||||||
|
}
|
||||||
|
|
||||||
|
onTermsClose() {
|
||||||
|
this.policyDisplay = false;
|
||||||
|
}
|
||||||
|
}
|
47
@overflow/member/component/member-profile.component.html
Normal file
47
@overflow/member/component/member-profile.component.html
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
<form [formGroup]="form" *ngIf="member" (ngSubmit)="onSubmit()">
|
||||||
|
<div class="ui-g">
|
||||||
|
<div class="ui-g-12 ui-md-4 ui-img-profile">
|
||||||
|
<div class="ui-img-profile-box">
|
||||||
|
<div class="ui-g">
|
||||||
|
<img class="profile-image " src="assets/layout/images/avatar.png" />
|
||||||
|
</div>
|
||||||
|
<button type="button" class="ui-button-photo-add" pButton icon="ui-icon-account-box" (click)="onAddSensorWithTarget(item.target)"></button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="ui-g-12 ui-md-8">
|
||||||
|
<div class="ui-g form-group">
|
||||||
|
<div class="ui-g-12">
|
||||||
|
<span class="md-inputfield">
|
||||||
|
<input type="text" pInputText formControlName="email" readonly value="{{email}}">
|
||||||
|
<label>Email</label>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div class="ui-g-12">
|
||||||
|
<span class="md-inputfield">
|
||||||
|
<input type="text" pInputText formControlName="name" value="{{name}}" >
|
||||||
|
<label>Name</label>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div class="ui-g-12">
|
||||||
|
<span class="md-inputfield">
|
||||||
|
<input type="text" pInputText formControlName="companyName" value="{{companyName}}" >
|
||||||
|
<label>Company Name</label>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div class="ui-g-12">
|
||||||
|
<span class="md-inputfield">
|
||||||
|
<input type="text" pInputText formControlName="phone" value="{{phone}}" >
|
||||||
|
<label>Phone</label>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="ui-g-12" dir="rtl">
|
||||||
|
<button type="submit" [disabled]="selected" class="ui-button ui-button-text-icon-left ui-button-width-fit">
|
||||||
|
<span class="ui-button-icon-left ui-c fa fa-fw ui-icon-person"></span>
|
||||||
|
<span class="ui-button-text ui-c">Save</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
|
@ -1,20 +1,20 @@
|
||||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
import { ListContainerComponent } from './list-container.component';
|
import { MemberProfileComponent } from './member-profile.component';
|
||||||
|
|
||||||
describe('ListContainerComponent', () => {
|
describe('MemberProfileComponent', () => {
|
||||||
let component: ListContainerComponent;
|
let component: MemberProfileComponent;
|
||||||
let fixture: ComponentFixture<ListContainerComponent>;
|
let fixture: ComponentFixture<MemberProfileComponent>;
|
||||||
|
|
||||||
beforeEach(async(() => {
|
beforeEach(async(() => {
|
||||||
TestBed.configureTestingModule({
|
TestBed.configureTestingModule({
|
||||||
declarations: [ ListContainerComponent ]
|
declarations: [ MemberProfileComponent ]
|
||||||
})
|
})
|
||||||
.compileComponents();
|
.compileComponents();
|
||||||
}));
|
}));
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
fixture = TestBed.createComponent(ListContainerComponent);
|
fixture = TestBed.createComponent(MemberProfileComponent);
|
||||||
component = fixture.componentInstance;
|
component = fixture.componentInstance;
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
});
|
});
|
52
@overflow/member/component/member-profile.component.ts
Normal file
52
@overflow/member/component/member-profile.component.ts
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
import { Component, OnInit, OnDestroy, Input, Output, EventEmitter } from '@angular/core';
|
||||||
|
import { Member } from '@overflow/commons-typescript/model/member';
|
||||||
|
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'of-member-profile',
|
||||||
|
templateUrl: './member-profile.component.html',
|
||||||
|
})
|
||||||
|
export class MemberProfileComponent implements OnInit, OnDestroy {
|
||||||
|
@Input() member: Member;
|
||||||
|
@Output() modify = new EventEmitter<Member>();
|
||||||
|
|
||||||
|
form: FormGroup;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private formBuilder: FormBuilder,
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ngOnInit() {
|
||||||
|
this.initForm();
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnDestroy() {
|
||||||
|
}
|
||||||
|
|
||||||
|
initForm() {
|
||||||
|
this.form = this.formBuilder.group({
|
||||||
|
'email': [this.member.email,
|
||||||
|
[
|
||||||
|
Validators.required,
|
||||||
|
Validators.email
|
||||||
|
]],
|
||||||
|
'name': [this.member.name, []],
|
||||||
|
'companyName': [this.member.companyName, []],
|
||||||
|
'phone': [this.member.phone, []],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
onSubmit() {
|
||||||
|
const formValue = Object.assign({}, this.form.value);
|
||||||
|
const member: Member = {
|
||||||
|
email: this.member.email,
|
||||||
|
name: formValue.name,
|
||||||
|
phone: formValue.phone,
|
||||||
|
companyName: formValue.companyName,
|
||||||
|
};
|
||||||
|
this.modify.emit(member);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -1,32 +1,33 @@
|
||||||
<div class="ui-g">
|
<div class="ui-g">
|
||||||
<div class="ui-g-12 ui-md-9 ui-lg-7">
|
<div class="ui-g-12 ui-md-9 ui-lg-7">
|
||||||
<form [formGroup]="signinForm" (ngSubmit)="signin()">
|
<form [formGroup]="resetPasswordForm" (ngSubmit)="resetPasswordFormSubmit()">
|
||||||
<table class="login-table">
|
<table class="login-table">
|
||||||
<tr>
|
<tr>
|
||||||
<td>
|
<td>
|
||||||
<div class="login-panel ui-fluid">
|
<div class="login-panel ui-fluid">
|
||||||
<div class="ui-g">
|
<div class="ui-g">
|
||||||
<div class="ui-g-12">
|
<div class="ui-g-12">
|
||||||
|
<!--img src="assets/layout/images/logo-ultima.svg" -->
|
||||||
<img src="assets/layout/images/overFlow_CI_blue_185.png">
|
<img src="assets/layout/images/overFlow_CI_blue_185.png">
|
||||||
</div>
|
</div>
|
||||||
<div class="ui-g-12">
|
<div class="ui-g-12">
|
||||||
<span class="md-inputfield">
|
<span class="md-inputfield">
|
||||||
<input type="email" id="email" autocomplete="off" placeholder="email" formControlName="email" required class="ui-inputtext ui-corner-all ui-state-default ui-widget">
|
<input type="email" id="email" autocomplete="off" placeholder="Please enter your email" formControlName="email" required class="ui-inputtext ui-corner-all ui-state-default ui-widget">
|
||||||
</span>
|
</span>
|
||||||
|
<div *ngIf="formErrors.email" class="help is-danger">
|
||||||
|
{{ formErrors.email }}
|
||||||
</div>
|
</div>
|
||||||
<div class="ui-g-12">
|
|
||||||
<span class="md-inputfield">
|
|
||||||
<input type="password" id="password" autocomplete="off" placeholder="password" formControlName="password" required class="ui-inputtext ui-corner-all ui-state-default ui-widget">
|
|
||||||
</span>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="ui-g-12">
|
<div class="ui-g-12">
|
||||||
<button type="submit" class="ui-button ui-widget ui-state-default ui-corner-all ui-button-text-icon-left">
|
<button type="submit" class="ui-button ui-widget ui-state-default ui-corner-all ui-button-text-icon-left">
|
||||||
<span class="ui-button-icon-left ui-c fa fa-fw ui-icon-person"></span>
|
<span class="ui-button-icon-left ui-c fa fa-fw ui-icon-cached"></span>
|
||||||
<span class="ui-button-text ui-c">Sign In</span>
|
<span class="ui-button-text ui-c">Reset Password</span>
|
||||||
</button>
|
</button>
|
||||||
<a href="javascript:void(0)" (click)="resetPasswordBtnClick()">Forgot Password</a>
|
|
||||||
|
<a href="/auth/signin" >Sign In</a>
|
||||||
|
|
|
|
||||||
<a href="javascript:void(0)" (click)="signupBtnClick()">Sign Up</a>
|
<a href="/auth/signup" >Sign Up</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
|
@ -0,0 +1,25 @@
|
||||||
|
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { MemberResetPasswordComponent } from './member-reset-password.component';
|
||||||
|
|
||||||
|
describe('MemberResetPasswordComponent', () => {
|
||||||
|
let component: MemberResetPasswordComponent;
|
||||||
|
let fixture: ComponentFixture<MemberResetPasswordComponent>;
|
||||||
|
|
||||||
|
beforeEach(async(() => {
|
||||||
|
TestBed.configureTestingModule({
|
||||||
|
declarations: [ MemberResetPasswordComponent ]
|
||||||
|
})
|
||||||
|
.compileComponents();
|
||||||
|
}));
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
fixture = TestBed.createComponent(MemberResetPasswordComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
|
@ -0,0 +1,36 @@
|
||||||
|
import { Component, OnInit, Output, EventEmitter } from '@angular/core';
|
||||||
|
import { FormGroup, FormBuilder, Validators } from '@angular/forms';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'of-member-reset-password',
|
||||||
|
templateUrl: './member-reset-password.component.html',
|
||||||
|
})
|
||||||
|
export class MemberResetPasswordComponent implements OnInit {
|
||||||
|
@Output() resetPassword = new EventEmitter<string>();
|
||||||
|
|
||||||
|
resetPasswordForm: FormGroup;
|
||||||
|
formErrors = {
|
||||||
|
'email': ''
|
||||||
|
};
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private formBuilder: FormBuilder
|
||||||
|
) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit() {
|
||||||
|
this.resetPasswordForm = this.formBuilder.group({
|
||||||
|
'email': ['', [
|
||||||
|
Validators.required,
|
||||||
|
Validators.email
|
||||||
|
]
|
||||||
|
]
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
resetPasswordFormSubmit() {
|
||||||
|
const formValue = Object.assign({}, this.resetPasswordForm.value);
|
||||||
|
this.resetPassword.emit(formValue.email);
|
||||||
|
}
|
||||||
|
}
|
34
@overflow/member/component/member-signin.component.html
Normal file
34
@overflow/member/component/member-signin.component.html
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
<form [formGroup]="signinForm" (ngSubmit)="signinFormSubmit()">
|
||||||
|
<table class="login-table">
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<div class="login-panel ui-fluid">
|
||||||
|
<div class="ui-g">
|
||||||
|
<div class="ui-g-12">
|
||||||
|
<img src="assets/layout/images/overFlow_CI_blue_185.png">
|
||||||
|
</div>
|
||||||
|
<div class="ui-g-12">
|
||||||
|
<span class="md-inputfield">
|
||||||
|
<input type="email" id="email" autocomplete="off" placeholder="email" formControlName="email" required class="ui-inputtext ui-corner-all ui-state-default ui-widget">
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div class="ui-g-12">
|
||||||
|
<span class="md-inputfield">
|
||||||
|
<input type="password" id="password" autocomplete="off" placeholder="password" formControlName="password" required class="ui-inputtext ui-corner-all ui-state-default ui-widget">
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div class="ui-g-12">
|
||||||
|
<button type="submit" class="ui-button ui-widget ui-state-default ui-corner-all ui-button-text-icon-left">
|
||||||
|
<span class="ui-button-icon-left ui-c fa fa-fw ui-icon-person"></span>
|
||||||
|
<span class="ui-button-text ui-c">Sign In</span>
|
||||||
|
</button>
|
||||||
|
<a href="javascript:void(0)" (click)="resetPassword.emit()">Forgot Password</a>
|
||||||
|
|
|
||||||
|
<a href="javascript:void(0)" (click)="signup.emit()">Sign Up</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</form>
|
25
@overflow/member/component/member-signin.component.spec.ts
Normal file
25
@overflow/member/component/member-signin.component.spec.ts
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { MemberSigninComponent } from './member-signin.component';
|
||||||
|
|
||||||
|
describe('MemberSigninComponent', () => {
|
||||||
|
let component: MemberSigninComponent;
|
||||||
|
let fixture: ComponentFixture<MemberSigninComponent>;
|
||||||
|
|
||||||
|
beforeEach(async(() => {
|
||||||
|
TestBed.configureTestingModule({
|
||||||
|
declarations: [ MemberSigninComponent ]
|
||||||
|
})
|
||||||
|
.compileComponents();
|
||||||
|
}));
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
fixture = TestBed.createComponent(MemberSigninComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
60
@overflow/member/component/member-signin.component.ts
Normal file
60
@overflow/member/component/member-signin.component.ts
Normal file
|
@ -0,0 +1,60 @@
|
||||||
|
import { Component, OnInit, Output, EventEmitter, Input } from '@angular/core';
|
||||||
|
import { ActivatedRoute, Router } from '@angular/router';
|
||||||
|
import { FormGroup, FormBuilder, Validators } from '@angular/forms';
|
||||||
|
import { Store, select } from '@ngrx/store';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'of-member-signin',
|
||||||
|
templateUrl: './member-signin.component.html',
|
||||||
|
})
|
||||||
|
export class MemberSigninComponent implements OnInit {
|
||||||
|
@Input() signinError: string;
|
||||||
|
@Output() resetPassword = new EventEmitter();
|
||||||
|
@Output() signup = new EventEmitter();
|
||||||
|
@Output() signin = new EventEmitter<{email: string, password: string, returnURL: string}>();
|
||||||
|
|
||||||
|
errorMessage: string | null;
|
||||||
|
returnURL: string;
|
||||||
|
|
||||||
|
signinForm: FormGroup;
|
||||||
|
formErrors = {
|
||||||
|
'email': '',
|
||||||
|
'password': ''
|
||||||
|
};
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private formBuilder: FormBuilder,
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit() {
|
||||||
|
this.initForm();
|
||||||
|
}
|
||||||
|
|
||||||
|
initForm() {
|
||||||
|
this.signinForm = this.formBuilder.group({
|
||||||
|
'email': [
|
||||||
|
'',
|
||||||
|
[
|
||||||
|
Validators.required,
|
||||||
|
Validators.email
|
||||||
|
]
|
||||||
|
],
|
||||||
|
'password': [
|
||||||
|
'',
|
||||||
|
[
|
||||||
|
Validators.pattern('^(?=.*[0-9])(?=.*[a-zA-Z])([a-zA-Z0-9]+)$'),
|
||||||
|
Validators.minLength(6),
|
||||||
|
Validators.maxLength(25)
|
||||||
|
]
|
||||||
|
],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
signinFormSubmit() {
|
||||||
|
const formValue = Object.assign({}, this.signinForm.value);
|
||||||
|
formValue.returnURL = this.returnURL;
|
||||||
|
this.signin.emit(formValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -9,7 +9,7 @@
|
||||||
|
|
||||||
<div class="ui-g">
|
<div class="ui-g">
|
||||||
<div class="ui-g-12 ui-md-9 ui-lg-7">
|
<div class="ui-g-12 ui-md-9 ui-lg-7">
|
||||||
<form [formGroup]="signupForm" (ngSubmit)="signup()">
|
<form [formGroup]="signupForm" (ngSubmit)="signupFormSubmit()">
|
||||||
<table class="login-table">
|
<table class="login-table">
|
||||||
<tr>
|
<tr>
|
||||||
<td>
|
<td>
|
25
@overflow/member/component/member-signup.component.spec.ts
Normal file
25
@overflow/member/component/member-signup.component.spec.ts
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { MemberSignupComponent } from './member-signup.component';
|
||||||
|
|
||||||
|
describe('MemberSignupComponent', () => {
|
||||||
|
let component: MemberSignupComponent;
|
||||||
|
let fixture: ComponentFixture<MemberSignupComponent>;
|
||||||
|
|
||||||
|
beforeEach(async(() => {
|
||||||
|
TestBed.configureTestingModule({
|
||||||
|
declarations: [ MemberSignupComponent ]
|
||||||
|
})
|
||||||
|
.compileComponents();
|
||||||
|
}));
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
fixture = TestBed.createComponent(MemberSignupComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
|
@ -2,18 +2,19 @@ import {
|
||||||
Component,
|
Component,
|
||||||
OnDestroy,
|
OnDestroy,
|
||||||
OnInit,
|
OnInit,
|
||||||
|
Output,
|
||||||
|
EventEmitter,
|
||||||
} from '@angular/core';
|
} from '@angular/core';
|
||||||
import { Router } from '@angular/router';
|
|
||||||
import { FormGroup, FormBuilder, Validators, AbstractControl, FormControl } from '@angular/forms';
|
import { FormGroup, FormBuilder, Validators, AbstractControl, FormControl } from '@angular/forms';
|
||||||
import { Member } from '@overflow/commons-typescript/model/member';
|
import { Member } from '@overflow/commons-typescript/model/member';
|
||||||
import * as AuthStore from '../../store/signup';
|
|
||||||
import {Store} from '@ngrx/store';
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'of-member-signup',
|
selector: 'of-member-signup',
|
||||||
templateUrl: './signup.component.html',
|
templateUrl: './member-signup.component.html',
|
||||||
})
|
})
|
||||||
export class SignupComponent implements OnInit, OnDestroy {
|
export class MemberSignupComponent implements OnInit, OnDestroy {
|
||||||
|
@Output() signup = new EventEmitter<{member: Member, password: string}>();
|
||||||
|
|
||||||
myRecaptcha = new FormControl(false);
|
myRecaptcha = new FormControl(false);
|
||||||
|
|
||||||
signupForm: FormGroup;
|
signupForm: FormGroup;
|
||||||
|
@ -27,9 +28,7 @@ export class SignupComponent implements OnInit, OnDestroy {
|
||||||
policyDisplay = false;
|
policyDisplay = false;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private router: Router,
|
|
||||||
private formBuilder: FormBuilder,
|
private formBuilder: FormBuilder,
|
||||||
private store: Store<AuthStore.State>,
|
|
||||||
) { }
|
) { }
|
||||||
|
|
||||||
|
|
||||||
|
@ -103,7 +102,7 @@ export class SignupComponent implements OnInit, OnDestroy {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
signup() {
|
signupFormSubmit() {
|
||||||
if (!this.myRecaptcha.valid) {
|
if (!this.myRecaptcha.valid) {
|
||||||
console.log('dddddddd');
|
console.log('dddddddd');
|
||||||
return;
|
return;
|
||||||
|
@ -116,8 +115,7 @@ export class SignupComponent implements OnInit, OnDestroy {
|
||||||
phone: signupValue.phone,
|
phone: signupValue.phone,
|
||||||
companyName: signupValue.company,
|
companyName: signupValue.company,
|
||||||
};
|
};
|
||||||
this.store.dispatch(new AuthStore.Signup({member, password}));
|
this.signup.emit({member: member, password: password});
|
||||||
console.log(member);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
termsDisplayOpen() {
|
termsDisplayOpen() {
|
|
@ -1,20 +1,20 @@
|
||||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
import { SignupComponent } from './signup.component';
|
import { MemberTermsComponent } from './member-terms.component';
|
||||||
|
|
||||||
describe('SignupComponent', () => {
|
describe('MemberTermsComponent', () => {
|
||||||
let component: SignupComponent;
|
let component: MemberTermsComponent;
|
||||||
let fixture: ComponentFixture<SignupComponent>;
|
let fixture: ComponentFixture<MemberTermsComponent>;
|
||||||
|
|
||||||
beforeEach(async(() => {
|
beforeEach(async(() => {
|
||||||
TestBed.configureTestingModule({
|
TestBed.configureTestingModule({
|
||||||
declarations: [ SignupComponent ]
|
declarations: [ MemberTermsComponent ]
|
||||||
})
|
})
|
||||||
.compileComponents();
|
.compileComponents();
|
||||||
}));
|
}));
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
fixture = TestBed.createComponent(SignupComponent);
|
fixture = TestBed.createComponent(MemberTermsComponent);
|
||||||
component = fixture.componentInstance;
|
component = fixture.componentInstance;
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
});
|
});
|
24
@overflow/member/component/member-terms.component.ts
Normal file
24
@overflow/member/component/member-terms.component.ts
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
import {Component, OnInit, OnDestroy, Input, EventEmitter, Output} from '@angular/core';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'of-member-terms',
|
||||||
|
templateUrl: './member-terms.component.html',
|
||||||
|
})
|
||||||
|
export class MemberTermsComponent implements OnInit, OnDestroy {
|
||||||
|
|
||||||
|
@Input() termsDisplay;
|
||||||
|
@Output() close = new EventEmitter();
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ngOnInit() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnDestroy() {
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
7
@overflow/member/container/index.ts
Normal file
7
@overflow/member/container/index.ts
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
import { MemberSigninContainerComponent } from './member-signin-container.component';
|
||||||
|
import { MemberSignupContainerComponent } from './member-signup-container.component';
|
||||||
|
|
||||||
|
export const CONTAINERS = [
|
||||||
|
MemberSigninContainerComponent,
|
||||||
|
MemberSignupContainerComponent,
|
||||||
|
];
|
|
@ -0,0 +1 @@
|
||||||
|
<of-member-signin (signin)="onSignin($event)"></of-member-signin>
|
|
@ -0,0 +1,25 @@
|
||||||
|
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { MemberSigninContainerComponent } from './member-signin-container.component';
|
||||||
|
|
||||||
|
describe('MemberSigninContainerComponent', () => {
|
||||||
|
let component: MemberSigninContainerComponent;
|
||||||
|
let fixture: ComponentFixture<MemberSigninContainerComponent>;
|
||||||
|
|
||||||
|
beforeEach(async(() => {
|
||||||
|
TestBed.configureTestingModule({
|
||||||
|
declarations: [ MemberSigninContainerComponent ]
|
||||||
|
})
|
||||||
|
.compileComponents();
|
||||||
|
}));
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
fixture = TestBed.createComponent(MemberSigninContainerComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
|
@ -3,14 +3,14 @@ import { ActivatedRoute, Router } from '@angular/router';
|
||||||
import { FormGroup, FormBuilder, Validators } from '@angular/forms';
|
import { FormGroup, FormBuilder, Validators } from '@angular/forms';
|
||||||
import { Store, select } from '@ngrx/store';
|
import { Store, select } from '@ngrx/store';
|
||||||
|
|
||||||
import * as AuthStore from '../../store/auth';
|
import * as AuthStore from '../store/auth';
|
||||||
import { AuthSelector } from '../../store';
|
import { AuthSelector } from '../store';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'of-member-signin',
|
selector: 'of-member-signin-container',
|
||||||
templateUrl: './signin.component.html',
|
templateUrl: './member-signin-container.component.html',
|
||||||
})
|
})
|
||||||
export class SigninComponent implements OnInit {
|
export class MemberSigninContainerComponent implements OnInit {
|
||||||
pending$ = this.store.pipe(select(AuthSelector.select('pending')));
|
pending$ = this.store.pipe(select(AuthSelector.select('pending')));
|
||||||
error$ = this.store.pipe(select(AuthSelector.select('error')));
|
error$ = this.store.pipe(select(AuthSelector.select('error')));
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
<of-member-signup (signup)="onSignup($event)"></of-member-signup>
|
|
@ -0,0 +1,25 @@
|
||||||
|
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { MemberSignupContainerComponent } from './member-signup-container.component';
|
||||||
|
|
||||||
|
describe('MemberSignupContainerComponent', () => {
|
||||||
|
let component: MemberSignupContainerComponent;
|
||||||
|
let fixture: ComponentFixture<MemberSignupContainerComponent>;
|
||||||
|
|
||||||
|
beforeEach(async(() => {
|
||||||
|
TestBed.configureTestingModule({
|
||||||
|
declarations: [ MemberSignupContainerComponent ]
|
||||||
|
})
|
||||||
|
.compileComponents();
|
||||||
|
}));
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
fixture = TestBed.createComponent(MemberSignupContainerComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
|
@ -0,0 +1,29 @@
|
||||||
|
import {
|
||||||
|
Component,
|
||||||
|
OnDestroy,
|
||||||
|
OnInit,
|
||||||
|
} from '@angular/core';
|
||||||
|
import { Member } from '@overflow/commons-typescript/model/member';
|
||||||
|
import * as AuthStore from '../store/signup';
|
||||||
|
import {Store} from '@ngrx/store';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'of-member-signup-container',
|
||||||
|
templateUrl: './signup-container.component.html',
|
||||||
|
})
|
||||||
|
export class MemberSignupContainerComponent implements OnInit, OnDestroy {
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private store: Store<AuthStore.State>,
|
||||||
|
) { }
|
||||||
|
|
||||||
|
ngOnInit() {
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnDestroy() {
|
||||||
|
}
|
||||||
|
|
||||||
|
onSignup(info: {member: Member, password: string}) {
|
||||||
|
this.store.dispatch(new AuthStore.Signup(info));
|
||||||
|
}
|
||||||
|
}
|
134
@overflow/member/container/policy/policy.component.html
Normal file
134
@overflow/member/container/policy/policy.component.html
Normal file
|
@ -0,0 +1,134 @@
|
||||||
|
<div class="ui-g">
|
||||||
|
|
||||||
|
<div class="ui-g-12">
|
||||||
|
<p-scrollPanel [style]="{width: '800px', height: '100%'}">
|
||||||
|
<div style="padding:1em;line-height:1.5">
|
||||||
|
개인정보 취급방침
|
||||||
|
<pre>
|
||||||
|
“㈜와탭랩스”는(이하 “회사”는) 고객님의 개인정보를 중요시하며, “정보통신망 이용촉진 및 정보보호”에 관한 법률을 준수하고 있습니다.
|
||||||
|
|
||||||
|
회사는 개인정보 취급방침을 통하여 고객님께서 제공하시는 개인정보가 어떠한 용도와 방식으로 이용되고 있으며, 개인정보 보호를 위해 어떠한 조치가 취해지고 있는지 알려드립니다.
|
||||||
|
|
||||||
|
회사는 개인정보취급방침을 개정하는 경우 웹사이트 공지사항(또는 개별공지)을 통하여 공지할 것입니다.
|
||||||
|
|
||||||
|
본 방침은 : 2015년 4월 1일부터 시행됩니다.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
*수집하는 개인정보 항목
|
||||||
|
회사는 회원가입, 상담, 서비스 신청 등등을 위해 아래와 같은 개인정보를 수집하고 있습니다.
|
||||||
|
|
||||||
|
- 수집항목 : 이름, 이메일 ID, 암호화 된 비밀번호, 휴대전화번호, 회사명, 서비스 이용기록, 결제기록
|
||||||
|
|
||||||
|
- 개인정보 수집방법 : 홈페이지(회원가입, 서비스 신청), 세미나 등 행사 응모
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
*개인정보의 수집 및 이용목적
|
||||||
|
회사는 수집한 개인정보를 다음의 목적을 위해 활용합니다.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
- 서비스 제공에 관한 계약 이행 및 서비스 제공에 따른 요금정산 콘텐츠 제공, 구매 및 요금 결제
|
||||||
|
|
||||||
|
- 회원 관리
|
||||||
|
회원제 서비스 이용에 따른 본인 확인, 개인 식별, 불량회원의 부정 이용 방지와 비인가 사용 방지, 불만처리 등 민원처리, 고지사항 전달
|
||||||
|
|
||||||
|
- 마케팅 및 광고에 활용
|
||||||
|
이벤트 등 광고성 정보 전달, 접속 빈도 파악 또는 회원의 서비스 이용에 대한 통계
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
*개인정보의 보유 및 이용기간
|
||||||
|
원칙적으로, 개인정보 수집 및 이용목적이 달성된 후에는 해당 정보를 지체 없이 파기합니다.
|
||||||
|
단, 관계법령의 규정에 의하여 보존할 필요가 있는 경우 회사는 아래와 같이 관계법령에서 정한 일정한 기간 동안 회원정보를 보관합니다.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
- 보존 항목 : 서비스 이용기록
|
||||||
|
|
||||||
|
- 보존 근거 : 전자상거래 등에서의 소비자보호에 관한 법률
|
||||||
|
|
||||||
|
- 보존 기간 : 3년
|
||||||
|
|
||||||
|
- 계약 또는 청약철회 등에 관한 기록 : 5년 (전자상거래 등에서의 소비자보호에 관한 법률)
|
||||||
|
|
||||||
|
- 대금결제 및 재화 등의 공급에 관한 기록 : 5년 (전자상거래 등에서의 소비자보호에 관한 법률)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
*개인정보 자동수집 장치의 설치, 운영 및 그 거부에 관한 사항
|
||||||
|
회사는 귀하의 정보를 수시로 저장하고 찾아내는 “쿠키(cookie)”를 자동 로그인 등의 목적으로 사용합니다.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
*개인정보의 취급위탁
|
||||||
|
회사는 다음과 같이 개인정보 취급업무를 외부 전문업체에 위탁하여 운영하고 있습니다. 아래 각 수탁업자는 계약기간 동안 필요한 범위 내에서 회원의 개인정보를 보유하는 것을 원칙으로 하며, 수탁업자에 대하여 관계법령에서 법정 보유기간을 명시하고 있는 경우는 해당 업체업체는 해당 기간 동안 보유합니다.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
- 수탁업체명 : 주식회사 케이지이니시스
|
||||||
|
|
||||||
|
- 위탁업무 : 신용카드, 계좌이체 결제 대행
|
||||||
|
|
||||||
|
- 위탁기간 : 위탁계약 종료시까지
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
위탁업무계약서 내지 별도의 정보보호서약(특약) 등을 통하여 개인정보보호 관련 법규의 준수, 개인정보에 관한 비밀유지, 제3자 제공에 대한 금지, 사고시의 책임부담, 위탁기간, 처리 종료 후의 개인정보의 반환 또는 파기 의무 등을 규정하고, 이를 준수하도록 관리하고 있습니다.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
*개인정보의 파기절차 및 방법
|
||||||
|
회사는 원칙적으로 개인정보 수집 및 이용목적이 달성된 후에는 해당 정보를 지체 없이 파기합니다. 파기절차 및 방법은 다음과 같습니다.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
- 파기절차
|
||||||
|
회원님이 회원가입 등을 위해 입력하신 정보는 목적이 달성된 후 별도의 DB로 옮겨져(종이의 경우 별도의 서류함) 내부 방침 및 기타 관련 법령에 의한 정보보호 사유에 따라(보유 및 이용기간 참조) 일정 기간 저장된 후 파기됩니다. 별도 DB로 옮겨진 개인정보는 법률에 의한 경우가 아니고서는 보유 이외의 다른 목적으로 이용되지 않습니다.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
- 파기방법
|
||||||
|
전자적 파일형태로 저장된 개인정보는 기록을 재생할 수 없는 기술적 방법을 사용하여 삭제합니다.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
*개인정보에 관한 민원서비스
|
||||||
|
회사는 고객의 개인정보를 보호하고 원활한 운영을 위하여 아래와 책임자를 지정하고 있습니다.
|
||||||
|
|
||||||
|
개인정보관리 책임자 : loafle
|
||||||
|
전화번호 : 031-460-5677
|
||||||
|
이메일 : overflow@loafle.com
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
귀하께서는 회사의 서비스를 이용하시며 발생하는 모든 개인정보보호 관련 민원을 개인정보관리 책임자에게 신고하실 수 있습니다.
|
||||||
|
회사는 이용자들의 신고사항에 대해 신속하게 충분한 답변을 드릴 것입니다.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
기타 개인정보침해에 대한 신고나 상담이 필요하신 경우에는 아래 기관에 문의하시기 바랍니다.
|
||||||
|
<pre>1. KISA 개인정보보호 http://www.1336.or.kr</pre>
|
||||||
|
|
||||||
|
<pre>2. 정보보호마크인증제도 http://www.eprivacy.or.kr</pre>
|
||||||
|
|
||||||
|
<pre>3. 경찰청 사이버테러대응센터 http://www.ctrc.go.kr</pre>
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</p-scrollPanel>
|
||||||
|
</div>
|
||||||
|
</div>
|
7
@overflow/member/container/settings/index.ts
Normal file
7
@overflow/member/container/settings/index.ts
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
import { TotpComponent } from './totp/totp.component';
|
||||||
|
import { ConfigSettingComponent } from './totp/config/config-setting.component';
|
||||||
|
|
||||||
|
export const SETTINGS_COMPONENTS = [
|
||||||
|
TotpComponent,
|
||||||
|
ConfigSettingComponent,
|
||||||
|
];
|
|
@ -0,0 +1,96 @@
|
||||||
|
<div class="ui-g">
|
||||||
|
<div class="ui-g-12">
|
||||||
|
<b>구글 인증기(OTP)</b>는 암호 기능 중 하나입니다. 작동 원리는 SMS 인증 방식과 유사합니다.
|
||||||
|
연동 후 30초 마다 보안 코드가 생성되고, 보안 코드는 로그인, 인출, 보안 설정 변경등의 보안 인증을 하는 곳에 사용됩니다.
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="ui-g">
|
||||||
|
<div class="ui-g-6">
|
||||||
|
<p-card subtitle="IOS 회원">
|
||||||
|
<p>App Store에서 "Authenticator" 검색 후 다운로드 해주세요.<br><br></p>
|
||||||
|
<button type="button" pButton label="App Store" icon="fa-check"></button>
|
||||||
|
</p-card>
|
||||||
|
</div>
|
||||||
|
<div class="ui-g-6">
|
||||||
|
<p-card subtitle="안드로이드 회원">
|
||||||
|
<p>구글 플레이 스토어 또는 핸드폰 브라우저를 통해 "구글 인증기(OTP)" 검색 후 다운로드 해주세요.<br><br></p>
|
||||||
|
<button type="button" pButton label="Google Play" icon="fa-check"></button>
|
||||||
|
</p-card>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="ui-g-12">
|
||||||
|
<h2>Key & Backup Code</h2>
|
||||||
|
<div class="ui-g-3" *ngIf="totp">
|
||||||
|
<qrcode [qrdata]="totp.uri" [size]="150" [level]="'M'"></qrcode>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="ui-g-9">
|
||||||
|
<div style="height: 80px;"></div>
|
||||||
|
<div class="ui-bottom-space-10" *ngIf="totp">{{totp.key}}, {{totp.uri}}</div>
|
||||||
|
<span class="md-inputfield">
|
||||||
|
<input type="text" id="code" autocomplete="off" placeholder="Please enter your code" formControlName="code"
|
||||||
|
required class="ui-inputtext ui-corner-all ui-state-default ui-widget" [formGroup]="totpForm" (ngSubmit)="totpRegistClick()">
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!--QR Code print & Key Print-->
|
||||||
|
</div>
|
||||||
|
<div class="ui-g-12" dir="rtl">
|
||||||
|
<button type="button" class="ui-button-width-fit ui-button-secondary" pButton icon="fa-close" (click)="onCancel()" label="No"></button>
|
||||||
|
<button type="button" class="ui-button-width-fit" pButton icon="fa-check" (click)="totpSettingDisplay=false" label="Yes"></button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!--<p-panel>-->
|
||||||
|
<!--<p-header [style]="{'margin-bottom':'20px'}">-->
|
||||||
|
<!--<div>-->
|
||||||
|
<!--구글 인증기(OTP)는 암호 기능 중 하나입니다. 작동 원리는 SMS 인증 방식과 유사합니다.-->
|
||||||
|
<!--연동 후 30초 마다 보안 코드가 생성되고, 보안 코드는 로그인, 인출, 보안 설정 변경등의 보안 인증을 하는 곳에 사용됩니다.-->
|
||||||
|
<!--</div>-->
|
||||||
|
<!--</p-header>-->
|
||||||
|
<!--구글 인증기(OTP)는 암호 기능 중 하나입니다. 작동 원리는 SMS 인증 방식과 유사합니다.-->
|
||||||
|
<!--연동 후 30초 마다 보안 코드가 생성되고, 보안 코드는 로그인, 인출, 보안 설정 변경등의 보안 인증을 하는 곳에 사용됩니다.-->
|
||||||
|
<!--</p-panel>-->
|
||||||
|
<!--<p-panel>-->
|
||||||
|
|
||||||
|
<!--</p-panel>-->
|
||||||
|
|
||||||
|
<!--<div fxLayout="row" fxLayoutWrap fxLayoutAlign="center">-->
|
||||||
|
<!--<div fxLayout="row" fxLayoutWrap fxLayoutAlign="center">-->
|
||||||
|
|
||||||
|
<!--<mat-card class="example-card">-->
|
||||||
|
<!--<mat-card-header>-->
|
||||||
|
<!--<mat-card-title>QR Code</mat-card-title>-->
|
||||||
|
<!--<!–<mat-card-subtitle>Select Target</mat-card-subtitle>–>-->
|
||||||
|
<!--</mat-card-header>-->
|
||||||
|
<!--<mat-card-content>-->
|
||||||
|
<!--<div fxLayout="row" fxLayoutWrap fxLayoutAlign="left">-->
|
||||||
|
<!--<qrcode [qrdata]="'otpauth://totp/overFlow:geekdev@naver.com?secret=X6AWAK573M5372NM'" [size]="128" [level]="'M'"></qrcode>-->
|
||||||
|
<!--</div>-->
|
||||||
|
<!--</mat-card-content>-->
|
||||||
|
<!--</mat-card>-->
|
||||||
|
|
||||||
|
<!--</div>-->
|
||||||
|
|
||||||
|
<!--<div fxLayout="row" fxLayoutWrap fxLayoutAlign="center">-->
|
||||||
|
|
||||||
|
<!--<mat-card class="example-card">-->
|
||||||
|
<!--<mat-card-header>-->
|
||||||
|
<!--<mat-card-title>Secret Code</mat-card-title>-->
|
||||||
|
<!--<mat-card-subtitle>X6AWAK573M5372NM</mat-card-subtitle>-->
|
||||||
|
<!--</mat-card-header>-->
|
||||||
|
<!--<mat-card-content>-->
|
||||||
|
<!--<form fxLayout="column" fxLayoutAlign="start stretch" [formGroup]="totpForm" (ngSubmit)="registClick()">-->
|
||||||
|
<!--<mat-form-field class="full-width">-->
|
||||||
|
<!--<input type="text" id="code" class="input" placeholder="Please enter your code"-->
|
||||||
|
<!--formControlName="code" required matInput>-->
|
||||||
|
<!--</mat-form-field>-->
|
||||||
|
<!--<!–<div *ngIf="formErrors.email" class="help is-danger">–>-->
|
||||||
|
<!--<!–{{ formErrors.email }}–>-->
|
||||||
|
<!--<!–</div>–>-->
|
||||||
|
<!--</form>-->
|
||||||
|
<!--</mat-card-content>-->
|
||||||
|
<!--</mat-card>-->
|
||||||
|
|
||||||
|
<!--</div>-->
|
||||||
|
|
|
@ -0,0 +1,91 @@
|
||||||
|
import {
|
||||||
|
AfterContentInit,
|
||||||
|
Component,
|
||||||
|
EventEmitter,
|
||||||
|
Input,
|
||||||
|
OnInit,
|
||||||
|
Output
|
||||||
|
} from '@angular/core';
|
||||||
|
import { ActivatedRoute, Router } from '@angular/router';
|
||||||
|
import { Store, select } from '@ngrx/store';
|
||||||
|
import { FormGroup, FormBuilder, Validators } from '@angular/forms';
|
||||||
|
|
||||||
|
import * as TotpStore from '@overflow/member/store/totp';
|
||||||
|
import { AuthSelector } from '@overflow/member/store';
|
||||||
|
import { TotpSelector } from '@overflow/member/store';
|
||||||
|
import { Member } from '@overflow/commons-typescript/model/member';
|
||||||
|
import {RPCClientError} from '@loafer/ng-rpc';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'of-config-setting',
|
||||||
|
templateUrl: './config-setting.component.html',
|
||||||
|
styleUrls: ['./config-setting.component.scss']
|
||||||
|
})
|
||||||
|
export class ConfigSettingComponent implements OnInit, AfterContentInit {
|
||||||
|
member: Member;
|
||||||
|
totpState$ = this.store.pipe(select(TotpSelector.select('totp')));
|
||||||
|
totp: any;
|
||||||
|
totpForm: FormGroup;
|
||||||
|
qrData: string;
|
||||||
|
|
||||||
|
@Input() selectedItem: any;
|
||||||
|
@Output() close = new EventEmitter();
|
||||||
|
@Input() totpSettingDisplay;
|
||||||
|
|
||||||
|
constructor(private activatedRoute: ActivatedRoute,
|
||||||
|
private router: Router,
|
||||||
|
private store: Store<TotpStore.State>,
|
||||||
|
private formBuilder: FormBuilder,
|
||||||
|
) { }
|
||||||
|
|
||||||
|
ngOnInit() {
|
||||||
|
this.totpForm = this.formBuilder.group({
|
||||||
|
'code': [
|
||||||
|
[
|
||||||
|
]
|
||||||
|
]
|
||||||
|
});
|
||||||
|
this.totpState$.subscribe(
|
||||||
|
(obj: any) => {
|
||||||
|
console.log(obj);
|
||||||
|
this.totp = obj;
|
||||||
|
},
|
||||||
|
(error: RPCClientError) => {
|
||||||
|
console.log(error.response.message);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
ngAfterContentInit() {
|
||||||
|
|
||||||
|
this.store.select(AuthSelector.select('member')).subscribe(
|
||||||
|
(member: Member) => {
|
||||||
|
this.member = member;
|
||||||
|
this.store.dispatch(new TotpStore.CreateTotp(this.member));
|
||||||
|
},
|
||||||
|
(error) => {
|
||||||
|
console.log(error);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
totpRegistClick() {
|
||||||
|
const code = this.totpForm.value['code'];
|
||||||
|
const secretCode = 'X6AWAK573M5372NM';
|
||||||
|
|
||||||
|
this.store.select(AuthSelector.select('member')).subscribe(
|
||||||
|
(member: Member) => {
|
||||||
|
this.store.dispatch(new TotpStore.Regist({ member, secretCode, code }));
|
||||||
|
},
|
||||||
|
(error) => {
|
||||||
|
console.log(error);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
onCancel() {
|
||||||
|
this.close.emit();
|
||||||
|
}
|
||||||
|
}
|
25
@overflow/member/container/settings/totp/totp.component.html
Normal file
25
@overflow/member/container/settings/totp/totp.component.html
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
<h1>Settings</h1>
|
||||||
|
<p-dialog header="{{headerItem}}" [modal]="true" [width]="800" [(visible)]="totpSettingDisplay" [showHeader]="true" [closeOnEscape]="false">
|
||||||
|
<of-config-setting [selectedItem]="selectedItem" (close)="onTotpSettingClose()"></of-config-setting>
|
||||||
|
</p-dialog>
|
||||||
|
|
||||||
|
<p-dataView [value]="lists" [paginator]="false" [rows]="5">
|
||||||
|
<p-header>이중보안</p-header>
|
||||||
|
|
||||||
|
<ng-template let-item pTemplate="listItem">
|
||||||
|
<div class="ui-g ui-bottom-border-1" style="padding: 2em;">
|
||||||
|
<!--<div class="ui-g-12 ui-md-3" style="text-align:left">-->
|
||||||
|
<!--</div>-->
|
||||||
|
<div class="ui-g-2 ui-sm-6">{{item.name }} </div>
|
||||||
|
<div class="ui-g-3 ui-sm-6">{{item.value }}</div>
|
||||||
|
<div class="ui-g-5 ui-sm-6">{{item.description }}</div>
|
||||||
|
|
||||||
|
<div class="ui-g-2 ui-sm-6">
|
||||||
|
<button pButton type="button" label="Add" icon="ui-icon-add" (click)="on2factorConfig($event, item)"></button>
|
||||||
|
|
||||||
|
<!--<button pButton type="button" label="Add" icon="ui-icon-add" (click)="selectCar($event, car)"></button>-->
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</ng-template>
|
||||||
|
</p-dataView>
|
||||||
|
|
|
@ -1,20 +1,20 @@
|
||||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
import { ListComponent } from './list.component';
|
import { TotpComponent } from './totp.component';
|
||||||
|
|
||||||
describe('ListComponent', () => {
|
describe('TotpComponent', () => {
|
||||||
let component: ListComponent;
|
let component: TotpComponent;
|
||||||
let fixture: ComponentFixture<ListComponent>;
|
let fixture: ComponentFixture<TotpComponent>;
|
||||||
|
|
||||||
beforeEach(async(() => {
|
beforeEach(async(() => {
|
||||||
TestBed.configureTestingModule({
|
TestBed.configureTestingModule({
|
||||||
declarations: [ ListComponent ]
|
declarations: [ TotpComponent ]
|
||||||
})
|
})
|
||||||
.compileComponents();
|
.compileComponents();
|
||||||
}));
|
}));
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
fixture = TestBed.createComponent(ListComponent);
|
fixture = TestBed.createComponent(TotpComponent);
|
||||||
component = fixture.componentInstance;
|
component = fixture.componentInstance;
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
});
|
});
|
72
@overflow/member/container/settings/totp/totp.component.ts
Normal file
72
@overflow/member/container/settings/totp/totp.component.ts
Normal file
|
@ -0,0 +1,72 @@
|
||||||
|
import {AfterContentInit, Component, OnInit} from '@angular/core';
|
||||||
|
import { ActivatedRoute, Router } from '@angular/router';
|
||||||
|
import { Store, select } from '@ngrx/store';
|
||||||
|
import { FormGroup, FormBuilder, Validators } from '@angular/forms';
|
||||||
|
|
||||||
|
import * as TotpStore from '@overflow/member/store/totp';
|
||||||
|
import { AuthSelector } from '@overflow/member/store';
|
||||||
|
import { Member } from '@overflow/commons-typescript/model/member';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'of-settings-totp',
|
||||||
|
templateUrl: './totp.component.html',
|
||||||
|
})
|
||||||
|
export class TotpComponent implements OnInit, AfterContentInit {
|
||||||
|
member: Member;
|
||||||
|
selectedItem: any;
|
||||||
|
totpSettingDisplay = false;
|
||||||
|
totpForm: FormGroup;
|
||||||
|
headerItem: string;
|
||||||
|
|
||||||
|
formErrors = {
|
||||||
|
'code': '',
|
||||||
|
};
|
||||||
|
|
||||||
|
lists = [];
|
||||||
|
|
||||||
|
constructor(private activatedRoute: ActivatedRoute,
|
||||||
|
private router: Router,
|
||||||
|
private store: Store<TotpStore.State>,
|
||||||
|
private formBuilder: FormBuilder,
|
||||||
|
) { }
|
||||||
|
|
||||||
|
ngOnInit() {
|
||||||
|
this.totpForm = this.formBuilder.group({
|
||||||
|
'code': [
|
||||||
|
[
|
||||||
|
]
|
||||||
|
]
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
ngAfterContentInit() {
|
||||||
|
|
||||||
|
this.store.select(AuthSelector.select('member')).subscribe(
|
||||||
|
(member: Member) => {
|
||||||
|
this.member = member;
|
||||||
|
this.lists = [
|
||||||
|
{id: 1, name: 'Email', value: this.member.email, description: 'blabla', },
|
||||||
|
{id: 2, name: 'Phone', value: this.member.phone, description: 'blabla', },
|
||||||
|
{id: 3, name: 'Google 2factor', value: this.member.totpType, description: 'blabla', },
|
||||||
|
];
|
||||||
|
},
|
||||||
|
(error) => {
|
||||||
|
console.log(error);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
on2factorConfig(event: Event, item: any) {
|
||||||
|
this.selectedItem = item;
|
||||||
|
|
||||||
|
// server totp regist member info modify
|
||||||
|
if (this.selectedItem.id === 3) {
|
||||||
|
this.headerItem = '구글 인증기 설정하기';
|
||||||
|
this.totpSettingDisplay = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onTotpSettingClose() {
|
||||||
|
this.totpSettingDisplay = false;
|
||||||
|
}
|
||||||
|
}
|
104
@overflow/member/container/terms/terms.component.html
Normal file
104
@overflow/member/container/terms/terms.component.html
Normal file
|
@ -0,0 +1,104 @@
|
||||||
|
<div class="ui-g">
|
||||||
|
|
||||||
|
<div class="ui-g-12">
|
||||||
|
<p-scrollPanel [style]="{width: '800px', height: '100%'}">
|
||||||
|
<div style="padding:1em;line-height:1.5">
|
||||||
|
|
||||||
|
이용약관
|
||||||
|
<pre>
|
||||||
|
제 1 장 총칙
|
||||||
|
제1조 (목적)
|
||||||
|
본 약관은 ㈜와탭(이하 "갑"이라 합니다)이 제공하는 각종 서비스에 대한 고객(이하 "을"이라 합니다) 간의 이용조건 및 절차에 관한 제반사항의 규정을 목적으로 합니다.
|
||||||
|
제2조 (약관의 효력 및 개정)
|
||||||
|
본 약관은 전기통신사업법 규정에 의하여 제정한 것이며, 공시 함으로서 효력을 발생합니다. 본 약관의 공시는 "갑"의 홈페이지를 통해 공시됩니다. (홈페이지 : http://www.whatap.io)
|
||||||
|
본 약관은 "갑"의 서비스를 "을"이 이용 신청한 시점부터 서비스가 종료된 후 이용 요금 정산이 완료된 시점까지 효력을 가집니다.
|
||||||
|
"갑"은 합리적인 사유가 발생할 경우 본 약관을 변경할 수 있으며, 약관이 변경된 경우에는 이를 즉시 공시합니다. 단, 요금 등 고객의 권리 또는 의무에 관련된 중요사항의 변경은 공시 후 7일이 경과한 후에 그 효력이 있습니다.
|
||||||
|
제3조 (약관의 적용)
|
||||||
|
본 약관에 명시되지 아니한 사항에 대해서는 관계 법령, 본 약관의 취지 및 동종업계의 관행에 따라 해석 적용됩니다.
|
||||||
|
제 2 장 계약의 체결
|
||||||
|
제4조 (계약의 성립)
|
||||||
|
서비스의 이용 계약은 "갑"의 서비스에 대한 이용약관에 대한 "을"의 동의 및 이용 신청과 "갑"의 이용 승낙에 의하여 성립됩니다.
|
||||||
|
계약기간은 홈페이지에 게시된 상품 중 고객이 선택한 상품의 서비스 개시일로부터 선택한 기간에 따라 서비스를 받을 수 있습니다.
|
||||||
|
서비스 개시일은 "을"이 서비스 이용을 시작한 날짜로 합니다. 단, 유료서비스는 무료에서 유료서비스로 변경한 날짜로 합니다.
|
||||||
|
서비스 신청은 "갑"의 홈페이지에서 온라인으로 신청합니다.
|
||||||
|
제5조 (이용 신청의 승낙)
|
||||||
|
"갑"은 "을"에 대하여 업무상 또는 기술상 특별한 사유가 없는 한 접수 순서에 따라 서비스 이용을 승낙합니다.
|
||||||
|
"갑"은 "을"의 서비스 이용 신청을 승낙한 때에는 다음 각 호의 사항을 "을"에게 mail, 서면 또는 유선 등의 방법으로 통보합니다.
|
||||||
|
① 서비스 시작일
|
||||||
|
② 요금 등에 관한 사항
|
||||||
|
③ 고객의 권익보호 및 의무 등에 관한 사항
|
||||||
|
④ 기타 "갑"이 필요하다고 인정하는 사항
|
||||||
|
"갑" 이 "을" 또는 기존 서비스를 이용 중인 "을"의 신규 계약 및 재 계약에 대해 승낙하지 아니할 경우 계약은 성립되지 아니합니다.
|
||||||
|
"갑"은 다음 각 호에 해당하는 경우에 "을"의 서비스 신청 및 재 계약에 대하여 이를 승낙하지 아니할 수 있습니다. 이 경우에는 그 사유를 "을"에게 즉시 통보합니다.
|
||||||
|
① 타인의 명의를 사용하여 서비스 이용을 신청하였을 때
|
||||||
|
② 신청서의 내용을 허위로 기재하였거나 허위의 서류를 첨부하여 신청하였을 때
|
||||||
|
③ 기타 "을"의 귀책사유로 승낙이 곤란한 경우와 "갑"의 서비스 제공에 지장을 초래하였거나, 초래할 가능성이 있는 "을"의 신규 계약의 경우
|
||||||
|
"을"은 서비스 이용신충 후 "갑"의 승낙이 있는 시점부터 서비스를 이용할 수 있으며 서비스의 이용시간은 특별한 사유가 없는 한 1년 365일, 1일 24시간을 원칙으로 합니다.
|
||||||
|
5 항의 서비스 이용사간에서 "갑"과 "을"이 합의하여 서비스를 제공하지 아니한 날 또는 시간, 정기점검 등의 필요로 "갑"이 정한 날 또는 시간은 예외로 합니다.
|
||||||
|
제 3 장 계약의 변경 및 해지
|
||||||
|
제6조 (계약 내용의 변경)
|
||||||
|
"을"이 서비스 이용에 관한 내용 중 다음 각 호에 해당하는 사항이 변경된 경우에는 "갑"의 홈페이지를 통해 온라인 이용 변경을 하여야 합니다. (http://www.whatap.io)
|
||||||
|
① "을"의 상호, 성명, 주소 또는 연락처의 변경
|
||||||
|
② 서비스 내용의 변경
|
||||||
|
③ 요금납부방식 및 결제계좌번호 변경
|
||||||
|
제1항 제2호에 의하여 서비스 내용이 변경된 경우에는 새로운 서비스 이용 신청에 의한 요금이 적용됩니다.
|
||||||
|
제7조 (계약의 갱신)
|
||||||
|
서비스 이용 기간은 매월 서비스 이용 시작일부터 매월 말일까지로 합니다. 서비스 이용 기간 내에 "갑"과 "을" 상호간에 별도의 의사표시가 없을 경우 이전의 계약 내용과 동일한 조건으로 1개월씩 자동 연장됩니다.
|
||||||
|
제8조 (양도)
|
||||||
|
"갑"과 "을"은 사전 승인 없이는 계약상의 권리와 의무를 제3자에게 양도할 수 없습니다.
|
||||||
|
"을"의 지위 승계 및 양도를 원할 경우 기존의 미납된 서비스 이용 요금 납입이 되어야 승계가 가능합니다. "을"의 지위의 승계는 사명의 변경, 대표자의 변경, 요금납입책임자의 변경(서비스 이용고객과 요금납입책임자가 다른 경우)등 고객의 동일성을 판단할 수 있는 주요 사항이 변경된 경우를 말합니다
|
||||||
|
합병, 분할, 영업양수 등으로 "을"의 지위 승계 사유가 발생한 경우에는 그 사유 발생일로부터 30일 이내에 사업자등록증사본(법인에 한함)과 지위 승계를 입증할 수 있는 관련 서류를 첨부하여 "갑"에게 통보하여야 합니다
|
||||||
|
제9조 (계약의 해지)
|
||||||
|
서비스 이용 계약을 해지한 경우에는 해당 월 서비스 시작일로부터 사용일까지 월 이용요금을 일할 계산하여 청구합니다.
|
||||||
|
"갑"이나 "을" 중 어느 일방이 파산신청, 압류, 가압류, 부도, 경매, 회사정리 등의 사유에 해당하는 경우에는 즉시 계약을 해지 할 수 있습니다.
|
||||||
|
"을"이 서비스 해지를 원할 경우 "갑"은 해지 신청서를 접수한 후 정산절차를 거쳐 "을"의 요청일 까지 해지를 완료합니다. 단, 미납요금 정산이 완료되지 않을 경우 해지를 할 수 없습니다.
|
||||||
|
"갑"은 "을"의 서비스 이용 내용이 본 약관에 따른 서비스 이용의 제한사항에 해당하는 경우, 고객이 일정기간(5일) 내에 그 원인된 사유를 해소하지 않거나, 정당한 사유 없이 회사의 의견 진술 요청에 응하지 않는 경우 직권에 의하여 계약을 해지할 수 있습니다.
|
||||||
|
"갑"은 서비스 제공에 있어 "을"이 영업적 손실을 입혔을 경우와 서비스 제공에 합당하지 아니하다고 판단하였을 경우 그 사유를 서면 통보 후 해지할 수 있습니다.
|
||||||
|
계약 해지가 완료되면 "갑"은 "을"의 서버 모니터링 데이터를 즉시 삭제합니다.
|
||||||
|
"을"이 청구일을 기준으로 30일 내에 사용료를 정산하지 않은 경우 "갑"은 "을"의 서버 모니터링 데이터를 삭제합니다.
|
||||||
|
전자상거래법 17조에 의하여 단순변심 착오구매로 인한 철회는 상품신청 30일이 경과한 경우에는 청약철회가 불가능합니다. 단, 이용 상의 중대한 오류가 있는 경우 전자상거래법 및 소비자분쟁해결기준(공정거래위원회 고시)에 따라 처리됩니다.
|
||||||
|
제10조 (이용자격의 박탈)
|
||||||
|
다음의 경우에 "을"이 해당되는 경우 "갑"은 "을"의 서비스를 정지 할 수 있습니다.
|
||||||
|
미풍양속에 어긋난 정보를 제공한 경우
|
||||||
|
소프트웨어 보호법에 저촉된 행위를 한 경우
|
||||||
|
법률에 반하는 행위를 한 경우
|
||||||
|
"을"이 가입 신청 시 허위로 계약 신청을 하였을 경우
|
||||||
|
"을"이 "갑"의 서비스를 이용하며 "갑"의 다른 서비스 이용자들에게 피해를 입힌 경우
|
||||||
|
"을"이 "갑"의 영업 및 관리 상의 손실을 발생하였거나, 또는 발생할 가능성이 있을 경우
|
||||||
|
타인의 회원정보 및 비밀번호를 도용한 경우
|
||||||
|
부정한 상거래 행위로 서비스 이용을 제한 당한 이용자가 재등록을 신청한 경우
|
||||||
|
제 4 장 서비스 종류 및 요금
|
||||||
|
제11조 (이용요금)
|
||||||
|
서비스 이용요금의 세부 내역은 "갑"의 홈페이지에 명기합니다. (http://www.whatap.io)
|
||||||
|
제12조 (이용요금 변경)
|
||||||
|
① 이용요금 변경이란 요금이 인상 또는 인하되는 것을 말하며, "갑"이 "을"에게 통지한 달의 다음달부터 변경된 이용요금을 적용합니다. 단, 계약기간이 사전에 정해진 경우나 선납의 경우, 요금인하를 제외하고는 해당계약 기간이 종료할 때까지 요금을 변경할 수 없습니다.
|
||||||
|
② "갑"은 ①의 이용요금 변경 사유를 홈페이지에 게시하여야 합니다.
|
||||||
|
제13조 (손해배상)
|
||||||
|
① "갑"은 "갑"의 책임 있는 사유로 장애가 발생하여 월 가용률(아래 정의)구간을 달성하지 못하거나 장애로 인해 "을"이 손해를 입은 경우, "을"이 청구하는 경우에 한하여 본 조 제 2항에 따라 손해를 배상합니다.
|
||||||
|
장애시간 : 서비스를 이용하지 못한 사실을 ”을“이 ”갑“에 통지한 때(”을“의 통지 전에 ”갑“이 그러한 사실을 알게 된 경우는 ”갑“ 이 그러한 사실을 알게 된 때)로부터 ”갑”이 장애 상황을 해소하여 장애 조치가 완료된 때까지의 시간을 측정.(“갑“이 장애 조치를 완료하였으 ”을”의 추가 조치가 지연되어 장애가 연장된 경우, 해당 연장 시간은 장애시간에 포함하지 않음.)
|
||||||
|
가용율 기준
|
||||||
|
손해배상
|
||||||
|
가용률 99.9% 미만 99.5% 이상
|
||||||
|
이용 요금의 10%
|
||||||
|
가용률 99.5% 미만 99.0% 이상
|
||||||
|
이용 요금의 20%
|
||||||
|
가용률 99.0% 미만
|
||||||
|
이용 요금의 30%
|
||||||
|
* 가용률(%)=100 * [1 - 장애시간(분)의 합/최대 사용가능시간(분)]
|
||||||
|
② "을"의 손해배상 청구권은 그 사유가 발생한 날로부터 1개월이 경과한 후에 소멸됩니다.
|
||||||
|
제14조 (면책)
|
||||||
|
① "갑"은 "을"이 "갑"의 서비스를 이용하여 행한 모든 행위의 결과에 따른 손해 및 불법행위에 대한 모든 민, 형사상 책임 및 배상의 책임을 지지 않으며 그 책임은 "을"에게 있습니다.
|
||||||
|
② "갑"이 의무를 다했을 경우에 발생하는 피해에 대해서는 일체의 책임을 지지 않습니다.
|
||||||
|
③ 외부 침입에 의한 "을"의 정보자료의 유출과 훼손에 대해 "갑"은 책임이 없습니다.
|
||||||
|
제15조(약관의 효력)
|
||||||
|
"을"이 서비스 이용 신청을 하고, "갑"이 "을"에게 사용권한을 부여하면 본 약관은 효력이 발생합니다.
|
||||||
|
제16조 (관할법원)
|
||||||
|
① 본 약관에 별도로 규정한 것을 제외하고는 일반 상관례 및 약관법에 따르며, 약관의 해석이나 이행에 관한 분쟁은 "갑"과 "을"의 합의에 의하여 해결합니다.
|
||||||
|
② ①의 합의가 성립되지 못할 때의 관할 법원은 "갑" 주소지 관할 지방 법원으로 합니다.
|
||||||
|
ο 본 약관은 : 2017년 8월 1일부터 시행됩니다.
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</p-scrollPanel>
|
||||||
|
</div>
|
||||||
|
</div>
|
|
@ -6,6 +6,7 @@ import { MemberStoreModule } from './member-store.module';
|
||||||
import { MemberRESTModule } from './member-rest.module';
|
import { MemberRESTModule } from './member-rest.module';
|
||||||
|
|
||||||
import { COMPONENTS } from './component';
|
import { COMPONENTS } from './component';
|
||||||
|
import { CONTAINERS } from './container';
|
||||||
import { SERVICES } from './service';
|
import { SERVICES } from './service';
|
||||||
import { PrimeNGModules } from '../commons/prime-ng/prime-ng.module';
|
import { PrimeNGModules } from '../commons/prime-ng/prime-ng.module';
|
||||||
import { QRCodeModule } from 'angularx-qrcode';
|
import { QRCodeModule } from 'angularx-qrcode';
|
||||||
|
@ -27,9 +28,11 @@ import { RecaptchaModule } from 'angular-google-recaptcha';
|
||||||
],
|
],
|
||||||
declarations: [
|
declarations: [
|
||||||
COMPONENTS,
|
COMPONENTS,
|
||||||
|
CONTAINERS,
|
||||||
],
|
],
|
||||||
exports: [
|
exports: [
|
||||||
COMPONENTS,
|
COMPONENTS,
|
||||||
|
CONTAINERS,
|
||||||
],
|
],
|
||||||
providers: [
|
providers: [
|
||||||
SERVICES,
|
SERVICES,
|
||||||
|
|
5
@overflow/member/store/container/modify/index.ts
Normal file
5
@overflow/member/store/container/modify/index.ts
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
export * from './modify.action';
|
||||||
|
export * from './modify.effect';
|
||||||
|
export * from './modify.reducer';
|
||||||
|
export * from './modify.state';
|
||||||
|
|
35
@overflow/member/store/container/modify/modify.reducer.ts
Normal file
35
@overflow/member/store/container/modify/modify.reducer.ts
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
import {
|
||||||
|
Actions,
|
||||||
|
ActionType,
|
||||||
|
} from '../../entity/member/member.action';
|
||||||
|
|
||||||
|
import {
|
||||||
|
State,
|
||||||
|
initialState,
|
||||||
|
} from './modify.state';
|
||||||
|
|
||||||
|
export function reducer(state = initialState, action: Actions): State {
|
||||||
|
switch (action.type) {
|
||||||
|
case ActionType.Modify: {
|
||||||
|
return {
|
||||||
|
pending: true,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
case ActionType.ModifySuccess: {
|
||||||
|
return {
|
||||||
|
pending: false,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
case ActionType.ModifyFailure: {
|
||||||
|
return {
|
||||||
|
pending: false,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
default: {
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
11
@overflow/member/store/container/modify/modify.state.ts
Normal file
11
@overflow/member/store/container/modify/modify.state.ts
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
import { RESTClientError } from '@loafer/ng-rest';
|
||||||
|
|
||||||
|
import { Member } from '@overflow/commons-typescript/model/member';
|
||||||
|
|
||||||
|
export interface State {
|
||||||
|
pending: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const initialState: State = {
|
||||||
|
pending: false,
|
||||||
|
};
|
5
@overflow/member/store/container/reset-password/index.ts
Normal file
5
@overflow/member/store/container/reset-password/index.ts
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
export * from './reset-password.action';
|
||||||
|
export * from './reset-password.effect';
|
||||||
|
export * from './reset-password.reducer';
|
||||||
|
export * from './reset-password.state';
|
||||||
|
|
|
@ -0,0 +1,54 @@
|
||||||
|
import {
|
||||||
|
Actions,
|
||||||
|
ActionType,
|
||||||
|
} from '../../entity/member/member.action';
|
||||||
|
|
||||||
|
import {
|
||||||
|
State,
|
||||||
|
initialState,
|
||||||
|
} from './reset-password.state';
|
||||||
|
|
||||||
|
export function reducer(state = initialState, action: Actions): State {
|
||||||
|
switch (action.type) {
|
||||||
|
case ActionType.ResetPassword: {
|
||||||
|
return {
|
||||||
|
pending: true,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
case ActionType.ResetPasswordSuccess: {
|
||||||
|
return {
|
||||||
|
pending: false,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
case ActionType.ResetPasswordFailure: {
|
||||||
|
return {
|
||||||
|
pending: false,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
case ActionType.ModifyPassword: {
|
||||||
|
return {
|
||||||
|
pending: true,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
case ActionType.ModifyPasswordSuccess: {
|
||||||
|
return {
|
||||||
|
pending: false,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
case ActionType.ModifyPasswordFailure: {
|
||||||
|
return {
|
||||||
|
pending: false,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
default: {
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,11 @@
|
||||||
|
import { RESTClientError } from '@loafer/ng-rest';
|
||||||
|
|
||||||
|
import { Member } from '@overflow/commons-typescript/model/member';
|
||||||
|
|
||||||
|
export interface State {
|
||||||
|
pending: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const initialState: State = {
|
||||||
|
pending: false,
|
||||||
|
};
|
2
@overflow/member/store/container/signin/index.ts
Normal file
2
@overflow/member/store/container/signin/index.ts
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
export * from './signin.reducer';
|
||||||
|
export * from './signin.state';
|
48
@overflow/member/store/container/signin/signin.reducer.ts
Normal file
48
@overflow/member/store/container/signin/signin.reducer.ts
Normal file
|
@ -0,0 +1,48 @@
|
||||||
|
import {
|
||||||
|
Actions,
|
||||||
|
ActionType,
|
||||||
|
} from '../../entity/member/member.action';
|
||||||
|
|
||||||
|
import {
|
||||||
|
State,
|
||||||
|
initialState,
|
||||||
|
} from './signin.state';
|
||||||
|
|
||||||
|
export function reducer(state = initialState, action: Actions): State {
|
||||||
|
switch (action.type) {
|
||||||
|
case ActionType.Signin: {
|
||||||
|
return {
|
||||||
|
pending: true,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
case ActionType.SigninSuccess: {
|
||||||
|
const domainMember = action.payload.domainMember;
|
||||||
|
return {
|
||||||
|
pending: false,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
case ActionType.SigninFailure: {
|
||||||
|
return {
|
||||||
|
pending: false,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
case ActionType.SigninCookieSuccess: {
|
||||||
|
return {
|
||||||
|
pending: false,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
case ActionType.SigninCookieFailure: {
|
||||||
|
return {
|
||||||
|
pending: false,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
default: {
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
11
@overflow/member/store/container/signin/signin.state.ts
Normal file
11
@overflow/member/store/container/signin/signin.state.ts
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
import { RESTClientError } from '@loafer/ng-rest';
|
||||||
|
import { Domain } from '@overflow/commons-typescript/model/domain';
|
||||||
|
import { Member } from '@overflow/commons-typescript/model/member';
|
||||||
|
|
||||||
|
export interface State {
|
||||||
|
pending: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const initialState: State = {
|
||||||
|
pending: false,
|
||||||
|
};
|
2
@overflow/member/store/container/signout/index.ts
Normal file
2
@overflow/member/store/container/signout/index.ts
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
export * from './signout.reducer';
|
||||||
|
export * from './signout.state';
|
35
@overflow/member/store/container/signout/signout.reducer.ts
Normal file
35
@overflow/member/store/container/signout/signout.reducer.ts
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
import {
|
||||||
|
Actions,
|
||||||
|
ActionType,
|
||||||
|
} from '../../entity/member/member.action';
|
||||||
|
|
||||||
|
import {
|
||||||
|
State,
|
||||||
|
initialState,
|
||||||
|
} from './signout.state';
|
||||||
|
|
||||||
|
export function reducer(state = initialState, action: Actions): State {
|
||||||
|
switch (action.type) {
|
||||||
|
case ActionType.Signout: {
|
||||||
|
return {
|
||||||
|
pending: true,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
case ActionType.SignoutSuccess: {
|
||||||
|
return {
|
||||||
|
pending: false,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
case ActionType.SignoutFailure: {
|
||||||
|
return {
|
||||||
|
pending: false,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
default: {
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
11
@overflow/member/store/container/signout/signout.state.ts
Normal file
11
@overflow/member/store/container/signout/signout.state.ts
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
import { RESTClientError } from '@loafer/ng-rest';
|
||||||
|
import { Domain } from '@overflow/commons-typescript/model/domain';
|
||||||
|
import { Member } from '@overflow/commons-typescript/model/member';
|
||||||
|
|
||||||
|
export interface State {
|
||||||
|
pending: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const initialState: State = {
|
||||||
|
pending: false,
|
||||||
|
};
|
5
@overflow/member/store/container/signup/index.ts
Normal file
5
@overflow/member/store/container/signup/index.ts
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
export * from './signup.action';
|
||||||
|
export * from './signup.effect';
|
||||||
|
export * from './signup.reducer';
|
||||||
|
export * from './signup.state';
|
||||||
|
|
35
@overflow/member/store/container/signup/signup.reducer.ts
Normal file
35
@overflow/member/store/container/signup/signup.reducer.ts
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
import {
|
||||||
|
Actions,
|
||||||
|
ActionType,
|
||||||
|
} from '../../entity/member/member.action';
|
||||||
|
|
||||||
|
import {
|
||||||
|
State,
|
||||||
|
initialState,
|
||||||
|
} from './signup.state';
|
||||||
|
|
||||||
|
export function reducer(state = initialState, action: Actions): State {
|
||||||
|
switch (action.type) {
|
||||||
|
case ActionType.Signup: {
|
||||||
|
return {
|
||||||
|
pending: true,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
case ActionType.SignupSuccess: {
|
||||||
|
return {
|
||||||
|
pending: false,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
case ActionType.SignupFailure: {
|
||||||
|
return {
|
||||||
|
pending: false,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
default: {
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
11
@overflow/member/store/container/signup/signup.state.ts
Normal file
11
@overflow/member/store/container/signup/signup.state.ts
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
import { RESTClientError } from '@loafer/ng-rest';
|
||||||
|
|
||||||
|
import { Member } from '@overflow/commons-typescript/model/member';
|
||||||
|
|
||||||
|
export interface State {
|
||||||
|
pending: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const initialState: State = {
|
||||||
|
pending: false,
|
||||||
|
};
|
5
@overflow/member/store/entity/member/index.ts
Normal file
5
@overflow/member/store/entity/member/index.ts
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
export * from './member.action';
|
||||||
|
export * from './member.effect';
|
||||||
|
export * from './member.reducer';
|
||||||
|
export * from './member.state';
|
||||||
|
|
190
@overflow/member/store/entity/member/member.action.ts
Normal file
190
@overflow/member/store/entity/member/member.action.ts
Normal file
|
@ -0,0 +1,190 @@
|
||||||
|
import { Action } from '@ngrx/store';
|
||||||
|
|
||||||
|
import { RESTClientError } from '@loafer/ng-rest';
|
||||||
|
|
||||||
|
import { Member } from '@overflow/commons-typescript/model/member';
|
||||||
|
import { DomainMember } from '@overflow/commons-typescript/model/domain';
|
||||||
|
|
||||||
|
export enum ActionType {
|
||||||
|
Signin = '[member.member] Signin',
|
||||||
|
SigninSuccess = '[member.member] SigninSuccess',
|
||||||
|
SigninFailure = '[member.member] SigninFailure',
|
||||||
|
SigninRedirect = '[member.member] SigninRedirect',
|
||||||
|
|
||||||
|
SigninCookie = '[member.auth] SigninCookie',
|
||||||
|
SigninCookieSuccess = '[member.auth] SigninCookieSuccess',
|
||||||
|
SigninCookieFailure = '[member.auth] SigninCookieFailure',
|
||||||
|
|
||||||
|
Signout = '[member.auth] Signout',
|
||||||
|
SignoutSuccess = '[member.auth] SignoutSuccess',
|
||||||
|
SignoutFailure = '[member.auth] SignoutFailure',
|
||||||
|
|
||||||
|
Signup = '[member.signup] Signup',
|
||||||
|
SignupSuccess = '[member.signup] SignupSuccess',
|
||||||
|
SignupFailure = '[member.signup] SignupFailure',
|
||||||
|
|
||||||
|
Modify = '[member.modify] Modify',
|
||||||
|
ModifySuccess = '[member.modify] ModifySuccess',
|
||||||
|
ModifyFailure = '[member.modify] ModifyFailure',
|
||||||
|
|
||||||
|
ResetPassword = '[member.resetPassword] ResetPassword',
|
||||||
|
ResetPasswordSuccess = '[member.resetPassword] ResetPasswordSuccess',
|
||||||
|
ResetPasswordFailure = '[member.resetPassword] ResetPasswordFailure',
|
||||||
|
|
||||||
|
ModifyPassword = '[member.modifyPassword] ModifyPassword',
|
||||||
|
ModifyPasswordSuccess = '[member.modifyPassword] ModifyPasswordSuccess',
|
||||||
|
ModifyPasswordFailure = '[member.modifyPassword] ModifyPasswordFailure',
|
||||||
|
}
|
||||||
|
|
||||||
|
export class Signin implements Action {
|
||||||
|
readonly type = ActionType.Signin;
|
||||||
|
|
||||||
|
constructor(public payload: { email: string, password: string, returnURL: string }) { }
|
||||||
|
}
|
||||||
|
|
||||||
|
export class SigninSuccess implements Action {
|
||||||
|
readonly type = ActionType.SigninSuccess;
|
||||||
|
|
||||||
|
constructor(public payload: { authToken: string, domainMember: DomainMember }) { }
|
||||||
|
}
|
||||||
|
|
||||||
|
export class SigninFailure implements Action {
|
||||||
|
readonly type = ActionType.SigninFailure;
|
||||||
|
|
||||||
|
constructor(public payload: RESTClientError) { }
|
||||||
|
}
|
||||||
|
|
||||||
|
export class SigninRedirect implements Action {
|
||||||
|
readonly type = ActionType.SigninRedirect;
|
||||||
|
constructor(public payload: string) { }
|
||||||
|
}
|
||||||
|
|
||||||
|
export class SigninCookie implements Action {
|
||||||
|
readonly type = ActionType.SigninCookie;
|
||||||
|
|
||||||
|
constructor(public payload: { authToken: string, returnURL: string }) { }
|
||||||
|
}
|
||||||
|
|
||||||
|
export class SigninCookieSuccess implements Action {
|
||||||
|
readonly type = ActionType.SigninCookieSuccess;
|
||||||
|
|
||||||
|
constructor(public payload: DomainMember) { }
|
||||||
|
}
|
||||||
|
|
||||||
|
export class SigninCookieFailure implements Action {
|
||||||
|
readonly type = ActionType.SigninCookieFailure;
|
||||||
|
|
||||||
|
constructor(public payload: RESTClientError) { }
|
||||||
|
}
|
||||||
|
|
||||||
|
export class Signout implements Action {
|
||||||
|
readonly type = ActionType.Signout;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class SignoutSuccess implements Action {
|
||||||
|
readonly type = ActionType.SignoutSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class SignoutFailure implements Action {
|
||||||
|
readonly type = ActionType.SignoutFailure;
|
||||||
|
|
||||||
|
constructor(public payload: RESTClientError) { }
|
||||||
|
}
|
||||||
|
|
||||||
|
export class Signup implements Action {
|
||||||
|
readonly type = ActionType.Signup;
|
||||||
|
|
||||||
|
constructor(public payload: { member: Member, password: string }) { }
|
||||||
|
}
|
||||||
|
|
||||||
|
export class SignupSuccess implements Action {
|
||||||
|
readonly type = ActionType.SignupSuccess;
|
||||||
|
|
||||||
|
constructor(public payload: Member) { }
|
||||||
|
}
|
||||||
|
|
||||||
|
export class SignupFailure implements Action {
|
||||||
|
readonly type = ActionType.SignupFailure;
|
||||||
|
|
||||||
|
constructor(public payload: RESTClientError) { }
|
||||||
|
}
|
||||||
|
|
||||||
|
export class Modify implements Action {
|
||||||
|
readonly type = ActionType.Modify;
|
||||||
|
|
||||||
|
constructor(public payload: Member ) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class ModifySuccess implements Action {
|
||||||
|
readonly type = ActionType.ModifySuccess;
|
||||||
|
|
||||||
|
constructor(public payload: Member) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class ModifyFailure implements Action {
|
||||||
|
readonly type = ActionType.ModifyFailure;
|
||||||
|
|
||||||
|
constructor(public payload: RESTClientError) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class ResetPassword implements Action {
|
||||||
|
readonly type = ActionType.ResetPassword;
|
||||||
|
|
||||||
|
constructor(public payload: string ) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class ResetPasswordSuccess implements Action {
|
||||||
|
readonly type = ActionType.ResetPasswordSuccess;
|
||||||
|
|
||||||
|
constructor(public payload: Member) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class ResetPasswordFailure implements Action {
|
||||||
|
readonly type = ActionType.ResetPasswordFailure;
|
||||||
|
|
||||||
|
constructor(public payload: RESTClientError) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class ModifyPassword implements Action {
|
||||||
|
readonly type = ActionType.ModifyPassword;
|
||||||
|
|
||||||
|
constructor(public payload: { token: string, pw: string, confirmPw: string } ) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class ModifyPasswordSuccess implements Action {
|
||||||
|
readonly type = ActionType.ModifyPasswordSuccess;
|
||||||
|
|
||||||
|
constructor(public payload: Member) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class ModifyPasswordFailure implements Action {
|
||||||
|
readonly type = ActionType.ModifyPasswordFailure;
|
||||||
|
|
||||||
|
constructor(public payload: RESTClientError) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export type Actions =
|
||||||
|
| Signin
|
||||||
|
| SigninSuccess
|
||||||
|
| SigninFailure
|
||||||
|
| SigninRedirect
|
||||||
|
| SigninCookie
|
||||||
|
| SigninCookieSuccess
|
||||||
|
| SigninCookieFailure
|
||||||
|
| Signout
|
||||||
|
| SignoutSuccess
|
||||||
|
| SignoutFailure
|
||||||
|
| Signup
|
||||||
|
| SignupSuccess
|
||||||
|
| SignupFailure
|
||||||
|
| Modify
|
||||||
|
| ModifySuccess
|
||||||
|
| ModifyFailure
|
||||||
|
| ResetPassword
|
||||||
|
| ResetPasswordSuccess
|
||||||
|
| ResetPasswordFailure
|
||||||
|
| ModifyPassword
|
||||||
|
| ModifyPasswordSuccess
|
||||||
|
| ModifyPasswordFailure
|
||||||
|
;
|
15
@overflow/member/store/entity/member/member.effect.spec.ts
Normal file
15
@overflow/member/store/entity/member/member.effect.spec.ts
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
import { TestBed, inject } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { Effects } from './signup.effect';
|
||||||
|
|
||||||
|
describe('Signup.Effects', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
TestBed.configureTestingModule({
|
||||||
|
providers: [Effects]
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should be created', inject([Effects], (effects: Effects) => {
|
||||||
|
expect(effects).toBeTruthy();
|
||||||
|
}));
|
||||||
|
});
|
51
@overflow/member/store/entity/member/member.effect.ts
Normal file
51
@overflow/member/store/entity/member/member.effect.ts
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
import { Injectable } from '@angular/core';
|
||||||
|
import { Router } from '@angular/router';
|
||||||
|
|
||||||
|
import { Effect, Actions, ofType } from '@ngrx/effects';
|
||||||
|
import { Action } from '@ngrx/store';
|
||||||
|
|
||||||
|
import { Observable } from 'rxjs/Observable';
|
||||||
|
import { of } from 'rxjs/observable/of';
|
||||||
|
|
||||||
|
import 'rxjs/add/operator/catch';
|
||||||
|
import 'rxjs/add/operator/do';
|
||||||
|
import 'rxjs/add/operator/exhaustMap';
|
||||||
|
import 'rxjs/add/operator/map';
|
||||||
|
import 'rxjs/add/operator/take';
|
||||||
|
|
||||||
|
import { Member } from '@overflow/commons-typescript/model/member';
|
||||||
|
import { MemberService } from '../../service/member.service';
|
||||||
|
|
||||||
|
import {
|
||||||
|
Signup,
|
||||||
|
SignupSuccess,
|
||||||
|
SignupFailure,
|
||||||
|
ActionType,
|
||||||
|
} from './signup.action';
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class Effects {
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private actions$: Actions,
|
||||||
|
private memberService: MemberService,
|
||||||
|
private router: Router
|
||||||
|
) { }
|
||||||
|
|
||||||
|
@Effect()
|
||||||
|
signup$: Observable<Action> = this.actions$
|
||||||
|
.ofType(ActionType.Signup)
|
||||||
|
.map((action: Signup) => action.payload)
|
||||||
|
.exhaustMap(payload =>
|
||||||
|
this.memberService
|
||||||
|
.signup(payload.member, payload.password)
|
||||||
|
.map(_member => new SignupSuccess(_member))
|
||||||
|
.catch(error => of(new SignupFailure(error)))
|
||||||
|
);
|
||||||
|
|
||||||
|
@Effect({ dispatch: false })
|
||||||
|
signupSuccess$ = this.actions$
|
||||||
|
.ofType(ActionType.SignupSuccess)
|
||||||
|
.do(() => this.router.navigate(['/']));
|
||||||
|
|
||||||
|
}
|
45
@overflow/member/store/entity/member/member.reducer.ts
Normal file
45
@overflow/member/store/entity/member/member.reducer.ts
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
import {
|
||||||
|
Actions,
|
||||||
|
ActionType,
|
||||||
|
} from './signup.action';
|
||||||
|
|
||||||
|
import {
|
||||||
|
State,
|
||||||
|
initialState,
|
||||||
|
} from './signup.state';
|
||||||
|
|
||||||
|
import { Member } from '@overflow/commons-typescript/model/member';
|
||||||
|
|
||||||
|
export function reducer(state = initialState, action: Actions): State {
|
||||||
|
switch (action.type) {
|
||||||
|
case ActionType.Signup: {
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
error: null,
|
||||||
|
pending: true,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
case ActionType.SignupSuccess: {
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
error: null,
|
||||||
|
pending: false,
|
||||||
|
member: action.payload,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
case ActionType.SignupFailure: {
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
error: action.payload,
|
||||||
|
pending: false,
|
||||||
|
member: null,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
default: {
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
15
@overflow/member/store/entity/member/member.state.ts
Normal file
15
@overflow/member/store/entity/member/member.state.ts
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
import { RESTClientError } from '@loafer/ng-rest';
|
||||||
|
|
||||||
|
import { Member } from '@overflow/commons-typescript/model/member';
|
||||||
|
|
||||||
|
export interface State {
|
||||||
|
error: RESTClientError | null;
|
||||||
|
pending: boolean;
|
||||||
|
member: Member | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const initialState: State = {
|
||||||
|
error: null,
|
||||||
|
pending: false,
|
||||||
|
member: null,
|
||||||
|
};
|
|
@ -1,4 +1,4 @@
|
||||||
import { NoAuthProbeListComponent } from './list/list.component';
|
import { NoAuthProbeListComponent } from './noauth-probe-list.component';
|
||||||
|
|
||||||
export const COMPONENTS = [
|
export const COMPONENTS = [
|
||||||
NoAuthProbeListComponent,
|
NoAuthProbeListComponent,
|
||||||
|
|
|
@ -0,0 +1,25 @@
|
||||||
|
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { NoAuthProbeListComponent } from './noauth-probe-list.component';
|
||||||
|
|
||||||
|
describe('NoAuthProbeListComponent', () => {
|
||||||
|
let component: NoAuthProbeListComponent;
|
||||||
|
let fixture: ComponentFixture<NoAuthProbeListComponent>;
|
||||||
|
|
||||||
|
beforeEach(async(() => {
|
||||||
|
TestBed.configureTestingModule({
|
||||||
|
declarations: [ NoAuthProbeListComponent ]
|
||||||
|
})
|
||||||
|
.compileComponents();
|
||||||
|
}));
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
fixture = TestBed.createComponent(NoAuthProbeListComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
|
@ -4,8 +4,8 @@ import { ConfirmationService, Message } from 'primeng/primeng';
|
||||||
import { MessageService } from 'primeng/components/common/messageservice';
|
import { MessageService } from 'primeng/components/common/messageservice';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'of-noauth-list',
|
selector: 'of-noauth-probe-list',
|
||||||
templateUrl: './list.component.html',
|
templateUrl: './noauth-probe-list.component.html',
|
||||||
providers: [ConfirmationService, MessageService]
|
providers: [ConfirmationService, MessageService]
|
||||||
})
|
})
|
||||||
export class NoAuthProbeListComponent {
|
export class NoAuthProbeListComponent {
|
|
@ -1,4 +1,4 @@
|
||||||
import { NoAuthProbeListContainerComponent } from './list/list-container.component';
|
import { NoAuthProbeListContainerComponent } from './noauth-probe-list-container.component';
|
||||||
|
|
||||||
export const CONTAINER_COMPONENTS = [
|
export const CONTAINER_COMPONENTS = [
|
||||||
NoAuthProbeListContainerComponent,
|
NoAuthProbeListContainerComponent,
|
||||||
|
|
|
@ -1 +0,0 @@
|
||||||
<of-noauth-list [noauthProbes]="noauthProbes$ | async" (accept)="accept($event)" (deny)="deny($event)"></of-noauth-list>
|
|
|
@ -0,0 +1 @@
|
||||||
|
<of-noauth-probe-list [noauthProbes]="noauthProbes$ | async" (accept)="accept($event)" (deny)="deny($event)"></of-noauth-probe-list>
|
|
@ -0,0 +1,25 @@
|
||||||
|
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { NoAuthProbeListContainerComponent } from './noauth-probe-list-container.component';
|
||||||
|
|
||||||
|
describe('NoAuthProbeListContainerComponent', () => {
|
||||||
|
let component: NoAuthProbeListContainerComponent;
|
||||||
|
let fixture: ComponentFixture<NoAuthProbeListContainerComponent>;
|
||||||
|
|
||||||
|
beforeEach(async(() => {
|
||||||
|
TestBed.configureTestingModule({
|
||||||
|
declarations: [ NoAuthProbeListContainerComponent ]
|
||||||
|
})
|
||||||
|
.compileComponents();
|
||||||
|
}));
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
fixture = TestBed.createComponent(NoAuthProbeListContainerComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
|
@ -5,15 +5,15 @@ import 'rxjs/add/operator/map';
|
||||||
|
|
||||||
import { AuthSelector } from '@overflow/member/store';
|
import { AuthSelector } from '@overflow/member/store';
|
||||||
import { Domain } from '@overflow/commons-typescript/model/domain';
|
import { Domain } from '@overflow/commons-typescript/model/domain';
|
||||||
import * as ListStore from '../../store/entity/noauth-probe';
|
import * as ListStore from '../store/entity/noauth-probe';
|
||||||
import { NoAuthProbeEntitySelector } from '../../store';
|
import { NoAuthProbeEntitySelector } from '../store';
|
||||||
import { NoAuthProbe } from '@overflow/commons-typescript/model/noauth';
|
import { NoAuthProbe } from '@overflow/commons-typescript/model/noauth';
|
||||||
import { ConfirmationService } from 'primeng/primeng';
|
import { ConfirmationService } from 'primeng/primeng';
|
||||||
import { MessageService } from 'primeng/components/common/messageservice';
|
import { MessageService } from 'primeng/components/common/messageservice';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'of-noauth-list-container',
|
selector: 'of-noauth-probe-list-container',
|
||||||
templateUrl: './list-container.component.html',
|
templateUrl: './noauth-probe-list-container.component.html',
|
||||||
providers: [ConfirmationService, MessageService]
|
providers: [ConfirmationService, MessageService]
|
||||||
})
|
})
|
||||||
export class NoAuthProbeListContainerComponent implements OnInit {
|
export class NoAuthProbeListContainerComponent implements OnInit {
|
3
@overflow/shared/auth/auth.constant.ts
Normal file
3
@overflow/shared/auth/auth.constant.ts
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
export const MODULE = {
|
||||||
|
name: 'auth'
|
||||||
|
};
|
9
@overflow/shared/auth/auth.module.ts
Normal file
9
@overflow/shared/auth/auth.module.ts
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
import { NgModule } from '@angular/core';
|
||||||
|
import { CommonModule } from '@angular/common';
|
||||||
|
|
||||||
|
@NgModule({
|
||||||
|
imports: [
|
||||||
|
CommonModule,
|
||||||
|
],
|
||||||
|
})
|
||||||
|
export class AuthModule { }
|
89
@overflow/shared/auth/store/auth/auth.action.ts
Normal file
89
@overflow/shared/auth/store/auth/auth.action.ts
Normal file
|
@ -0,0 +1,89 @@
|
||||||
|
import { Action } from '@ngrx/store';
|
||||||
|
|
||||||
|
import { RESTClientError } from '@loafer/ng-rest';
|
||||||
|
|
||||||
|
import { DomainMember } from '@overflow/commons-typescript/model/domain';
|
||||||
|
import { Member } from '@overflow/commons-typescript/model/member';
|
||||||
|
|
||||||
|
export enum ActionType {
|
||||||
|
Signin = '[member.auth] Signin',
|
||||||
|
SigninSuccess = '[member.auth] SigninSuccess',
|
||||||
|
SigninFailure = '[member.auth] SigninFailure',
|
||||||
|
SigninRedirect = '[member.auth] SigninRedirect',
|
||||||
|
|
||||||
|
SigninCookie = '[member.auth] SigninCookie',
|
||||||
|
SigninCookieSuccess = '[member.auth] SigninCookieSuccess',
|
||||||
|
SigninCookieFailure = '[member.auth] SigninCookieFailure',
|
||||||
|
|
||||||
|
Signout = '[member.auth] Signout',
|
||||||
|
SignoutSuccess = '[member.auth] SignoutSuccess',
|
||||||
|
SignoutFailure = '[member.auth] SignoutFailure',
|
||||||
|
}
|
||||||
|
|
||||||
|
export class Signin implements Action {
|
||||||
|
readonly type = ActionType.Signin;
|
||||||
|
|
||||||
|
constructor(public payload: {email: string, password: string, returnURL: string}) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class SigninSuccess implements Action {
|
||||||
|
readonly type = ActionType.SigninSuccess;
|
||||||
|
|
||||||
|
constructor(public payload: {authToken: string, domainMember: DomainMember}) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class SigninFailure implements Action {
|
||||||
|
readonly type = ActionType.SigninFailure;
|
||||||
|
|
||||||
|
constructor(public payload: RESTClientError) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class SigninRedirect implements Action {
|
||||||
|
readonly type = ActionType.SigninRedirect;
|
||||||
|
constructor(public payload: string) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class SigninCookie implements Action {
|
||||||
|
readonly type = ActionType.SigninCookie;
|
||||||
|
|
||||||
|
constructor(public payload: {authToken: string, returnURL: string}) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class SigninCookieSuccess implements Action {
|
||||||
|
readonly type = ActionType.SigninCookieSuccess;
|
||||||
|
|
||||||
|
constructor(public payload: DomainMember) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class SigninCookieFailure implements Action {
|
||||||
|
readonly type = ActionType.SigninCookieFailure;
|
||||||
|
|
||||||
|
constructor(public payload: RESTClientError) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class Signout implements Action {
|
||||||
|
readonly type = ActionType.Signout;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class SignoutSuccess implements Action {
|
||||||
|
readonly type = ActionType.SignoutSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class SignoutFailure implements Action {
|
||||||
|
readonly type = ActionType.SignoutFailure;
|
||||||
|
|
||||||
|
constructor(public payload: RESTClientError) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
export type Actions =
|
||||||
|
| Signin
|
||||||
|
| SigninSuccess
|
||||||
|
| SigninFailure
|
||||||
|
| SigninRedirect
|
||||||
|
| SigninCookie
|
||||||
|
| SigninCookieSuccess
|
||||||
|
| SigninCookieFailure
|
||||||
|
| Signout
|
||||||
|
| SignoutSuccess
|
||||||
|
| SignoutFailure
|
||||||
|
;
|
15
@overflow/shared/auth/store/auth/auth.effect.spec.ts
Normal file
15
@overflow/shared/auth/store/auth/auth.effect.spec.ts
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
import { TestBed, inject } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { Effects } from './auth.effect';
|
||||||
|
|
||||||
|
describe('Auth.Effects', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
TestBed.configureTestingModule({
|
||||||
|
providers: [Effects]
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should be created', inject([Effects], (effects: Effects) => {
|
||||||
|
expect(effects).toBeTruthy();
|
||||||
|
}));
|
||||||
|
});
|
107
@overflow/shared/auth/store/auth/auth.effect.ts
Normal file
107
@overflow/shared/auth/store/auth/auth.effect.ts
Normal file
|
@ -0,0 +1,107 @@
|
||||||
|
import { Injectable } from '@angular/core';
|
||||||
|
import { Router } from '@angular/router';
|
||||||
|
|
||||||
|
import { Effect, Actions, ofType } from '@ngrx/effects';
|
||||||
|
import { Action } from '@ngrx/store';
|
||||||
|
|
||||||
|
import { Observable } from 'rxjs/Observable';
|
||||||
|
import { of } from 'rxjs/observable/of';
|
||||||
|
|
||||||
|
import 'rxjs/add/operator/catch';
|
||||||
|
import 'rxjs/add/operator/do';
|
||||||
|
import 'rxjs/add/operator/exhaustMap';
|
||||||
|
import 'rxjs/add/operator/switchMap';
|
||||||
|
import 'rxjs/add/operator/map';
|
||||||
|
import 'rxjs/add/operator/take';
|
||||||
|
|
||||||
|
import { RESTClientError } from '@loafer/ng-rest';
|
||||||
|
|
||||||
|
import { DomainMember } from '@overflow/commons-typescript/model/domain';
|
||||||
|
|
||||||
|
import { Member } from '@overflow/commons-typescript/model/member';
|
||||||
|
import { MemberService } from '../../service/member.service';
|
||||||
|
|
||||||
|
import {
|
||||||
|
Signin,
|
||||||
|
SigninSuccess,
|
||||||
|
SigninFailure,
|
||||||
|
SigninRedirect,
|
||||||
|
SigninCookie,
|
||||||
|
SigninCookieSuccess,
|
||||||
|
SigninCookieFailure,
|
||||||
|
|
||||||
|
ActionType,
|
||||||
|
} from './auth.action';
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class Effects {
|
||||||
|
private _returnURL: any;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private actions$: Actions,
|
||||||
|
private memberService: MemberService,
|
||||||
|
private router: Router
|
||||||
|
) { }
|
||||||
|
|
||||||
|
@Effect()
|
||||||
|
signin$: Observable<Action> = this.actions$
|
||||||
|
.ofType(ActionType.Signin)
|
||||||
|
.map((action: Signin) => action.payload)
|
||||||
|
.switchMap(payload => {
|
||||||
|
this._returnURL = payload.returnURL;
|
||||||
|
return this.memberService.signin(payload.email, payload.password);
|
||||||
|
})
|
||||||
|
.map((result: any) => {
|
||||||
|
const authToken = result['authToken'];
|
||||||
|
const domainMember = result['domainMember'];
|
||||||
|
return new SigninSuccess({authToken: authToken, domainMember: domainMember});
|
||||||
|
})
|
||||||
|
.catch((error: RESTClientError) => {
|
||||||
|
return of(new SigninFailure(error));
|
||||||
|
});
|
||||||
|
|
||||||
|
@Effect({ dispatch: false })
|
||||||
|
signinSuccess$ = this.actions$
|
||||||
|
.ofType(ActionType.SigninSuccess)
|
||||||
|
.do(() => {
|
||||||
|
this.router.navigateByUrl(this._returnURL);
|
||||||
|
});
|
||||||
|
|
||||||
|
@Effect({ dispatch: false })
|
||||||
|
signinRedirect$ = this.actions$
|
||||||
|
.ofType(ActionType.SigninRedirect, ActionType.Signout)
|
||||||
|
.map((action: SigninRedirect) => action.payload)
|
||||||
|
.do(returnURL => {
|
||||||
|
this.router.navigate(['/auth/signin'], {queryParams: {returnURL: returnURL}});
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
@Effect()
|
||||||
|
signinCookie$: Observable<Action> = this.actions$
|
||||||
|
.ofType(ActionType.SigninCookie)
|
||||||
|
.map((action: SigninCookie) => action.payload)
|
||||||
|
.switchMap((payload) => {
|
||||||
|
this._returnURL = payload.returnURL;
|
||||||
|
return this.memberService.signin_cookie(payload.authToken);
|
||||||
|
})
|
||||||
|
.map((domainMember: DomainMember) => {
|
||||||
|
return new SigninCookieSuccess(domainMember);
|
||||||
|
})
|
||||||
|
.catch((error: RESTClientError) => {
|
||||||
|
return of(new SigninFailure(error));
|
||||||
|
});
|
||||||
|
|
||||||
|
@Effect({ dispatch: false })
|
||||||
|
signinCookieSuccess$ = this.actions$
|
||||||
|
.ofType(ActionType.SigninCookieSuccess)
|
||||||
|
.do(() => {
|
||||||
|
this.router.navigateByUrl(this._returnURL);
|
||||||
|
});
|
||||||
|
|
||||||
|
@Effect({ dispatch: false })
|
||||||
|
signinCookieFailure$ = this.actions$
|
||||||
|
.ofType(ActionType.SigninCookieFailure)
|
||||||
|
.map(() => {
|
||||||
|
return new SigninRedirect(this._returnURL);
|
||||||
|
});
|
||||||
|
}
|
102
@overflow/shared/auth/store/auth/auth.reducer.ts
Normal file
102
@overflow/shared/auth/store/auth/auth.reducer.ts
Normal file
|
@ -0,0 +1,102 @@
|
||||||
|
import {
|
||||||
|
Actions,
|
||||||
|
ActionType,
|
||||||
|
Signin,
|
||||||
|
} from './auth.action';
|
||||||
|
|
||||||
|
import {
|
||||||
|
State,
|
||||||
|
initialState,
|
||||||
|
} from './auth.state';
|
||||||
|
|
||||||
|
import { Member } from '@overflow/commons-typescript/model/member';
|
||||||
|
import { DomainMember } from '@overflow/commons-typescript/model/domain';
|
||||||
|
|
||||||
|
export function reducer(state = initialState, action: Actions): State {
|
||||||
|
switch (action.type) {
|
||||||
|
case ActionType.Signin: {
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
error: null,
|
||||||
|
pending: true,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
case ActionType.SigninSuccess: {
|
||||||
|
const domainMember = action.payload.domainMember;
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
signined: true,
|
||||||
|
error: null,
|
||||||
|
pending: false,
|
||||||
|
member: domainMember.member,
|
||||||
|
domain: domainMember.domain,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
case ActionType.SigninFailure: {
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
signined: false,
|
||||||
|
error: action.payload,
|
||||||
|
pending: false,
|
||||||
|
member: null,
|
||||||
|
domain: null,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
case ActionType.SigninCookieSuccess: {
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
signined: true,
|
||||||
|
error: null,
|
||||||
|
pending: false,
|
||||||
|
member: action.payload.member,
|
||||||
|
domain: action.payload.domain,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
case ActionType.SigninCookieFailure: {
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
signined: false,
|
||||||
|
error: action.payload,
|
||||||
|
pending: false,
|
||||||
|
member: null,
|
||||||
|
domain: null,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
case ActionType.Signout: {
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
error: null,
|
||||||
|
pending: true,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
case ActionType.SignoutSuccess: {
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
signined: false,
|
||||||
|
error: null,
|
||||||
|
pending: false,
|
||||||
|
member: null,
|
||||||
|
domain: null,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
case ActionType.SignoutFailure: {
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
error: action.payload,
|
||||||
|
pending: false,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
default: {
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
19
@overflow/shared/auth/store/auth/auth.state.ts
Normal file
19
@overflow/shared/auth/store/auth/auth.state.ts
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
import { RESTClientError } from '@loafer/ng-rest';
|
||||||
|
import { Domain } from '@overflow/commons-typescript/model/domain';
|
||||||
|
import { Member } from '@overflow/commons-typescript/model/member';
|
||||||
|
|
||||||
|
export interface State {
|
||||||
|
signined: boolean;
|
||||||
|
error: RESTClientError | null;
|
||||||
|
pending: boolean;
|
||||||
|
member: Member | null;
|
||||||
|
domain: Domain | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const initialState: State = {
|
||||||
|
signined: false,
|
||||||
|
error: null,
|
||||||
|
pending: false,
|
||||||
|
member: null,
|
||||||
|
domain: null,
|
||||||
|
};
|
4
@overflow/shared/auth/store/auth/index.ts
Normal file
4
@overflow/shared/auth/store/auth/index.ts
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
export * from './auth.action';
|
||||||
|
export * from './auth.effect';
|
||||||
|
export * from './auth.reducer';
|
||||||
|
export * from './auth.state';
|
3
@overflow/shared/shared.constant.ts
Normal file
3
@overflow/shared/shared.constant.ts
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
export const MODULE = {
|
||||||
|
name: 'Target'
|
||||||
|
};
|
9
@overflow/shared/shared.module.ts
Normal file
9
@overflow/shared/shared.module.ts
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
import { NgModule } from '@angular/core';
|
||||||
|
import { CommonModule } from '@angular/common';
|
||||||
|
|
||||||
|
@NgModule({
|
||||||
|
imports: [
|
||||||
|
CommonModule,
|
||||||
|
],
|
||||||
|
})
|
||||||
|
export class SharedModule { }
|
|
@ -3,7 +3,8 @@ import {
|
||||||
CanActivate,
|
CanActivate,
|
||||||
CanActivateChild,
|
CanActivateChild,
|
||||||
ActivatedRouteSnapshot,
|
ActivatedRouteSnapshot,
|
||||||
RouterStateSnapshot
|
RouterStateSnapshot,
|
||||||
|
Router,
|
||||||
} from '@angular/router';
|
} from '@angular/router';
|
||||||
import { Store } from '@ngrx/store';
|
import { Store } from '@ngrx/store';
|
||||||
|
|
||||||
|
@ -20,6 +21,7 @@ import { AuthSelector } from '@overflow/member/store';
|
||||||
export class AuthGuard implements CanActivate, CanActivateChild {
|
export class AuthGuard implements CanActivate, CanActivateChild {
|
||||||
constructor(
|
constructor(
|
||||||
private store: Store<AuthStore.State>,
|
private store: Store<AuthStore.State>,
|
||||||
|
private router: Router,
|
||||||
private cookieService: CookieService,
|
private cookieService: CookieService,
|
||||||
) { }
|
) { }
|
||||||
|
|
||||||
|
@ -31,7 +33,8 @@ export class AuthGuard implements CanActivate, CanActivateChild {
|
||||||
if (this.cookieService.check('authToken')) {
|
if (this.cookieService.check('authToken')) {
|
||||||
this.store.dispatch(new AuthStore.SigninCookie({authToken: this.cookieService.get('authToken'), returnURL: state.url}));
|
this.store.dispatch(new AuthStore.SigninCookie({authToken: this.cookieService.get('authToken'), returnURL: state.url}));
|
||||||
} else {
|
} else {
|
||||||
this.store.dispatch(new AuthStore.SigninRedirect(state.url));
|
// this.store.dispatch(new AuthStore.SigninRedirect(state.url));
|
||||||
|
this.router.navigateByUrl(state.url);
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1 +1,8 @@
|
||||||
<of-member-signin></of-member-signin>
|
<div class="ui-g">
|
||||||
|
<div class="ui-g-12 ui-md-9 ui-lg-7">
|
||||||
|
<of-member-signin-container></of-member-signin-container>
|
||||||
|
</div>
|
||||||
|
<div class="ui-g-12 ui-md-3 ui-lg-5 login-descript">
|
||||||
|
<of-site-banner-container></of-site-banner-container>
|
||||||
|
</div>
|
||||||
|
</div>
|
|
@ -1 +1 @@
|
||||||
<of-noauth-list-container></of-noauth-list-container>
|
<of-noauth-probe-list-container></of-noauth-probe-list-container>
|
Loading…
Reference in New Issue
Block a user