diff --git a/src/client/app/cms/cms-routing.module.ts b/src/client/app/cms/cms-routing.module.ts
index 13db19a..95f9794 100644
--- a/src/client/app/cms/cms-routing.module.ts
+++ b/src/client/app/cms/cms-routing.module.ts
@@ -10,7 +10,12 @@ const routes: Routes = [
path: '',
component: CmsComponent,
canActivate: [CurrentUserGuard],
- children: []
+ children: [
+ {
+ path: 'profile',
+ loadChildren: '../profile/profile.module#ProfileModule'
+ }
+ ]
}
];
diff --git a/src/client/app/cms/cms-sidenav/cms-sidenav.component.html b/src/client/app/cms/cms-sidenav/cms-sidenav.component.html
index 4e03837..7225ac9 100644
--- a/src/client/app/cms/cms-sidenav/cms-sidenav.component.html
+++ b/src/client/app/cms/cms-sidenav/cms-sidenav.component.html
@@ -4,5 +4,6 @@
Home
+ Profile
Logout
\ No newline at end of file
diff --git a/src/client/app/core/services/user.service.ts b/src/client/app/core/services/user.service.ts
index c4a02e4..3397e68 100644
--- a/src/client/app/core/services/user.service.ts
+++ b/src/client/app/core/services/user.service.ts
@@ -58,4 +58,12 @@ export class UserService {
this.apiService.setAccessToken(null);
});
}
+
+ public updateProfile(data: User): Observable {
+ return this.apiService.put(`/users/profile`, data)
+ .do((user: User) => {
+ console.log('updated current user', user);
+ this.currentUserSource.next(user);
+ });
+ }
}
diff --git a/src/client/app/profile/profile-routing.module.ts b/src/client/app/profile/profile-routing.module.ts
new file mode 100644
index 0000000..0df748d
--- /dev/null
+++ b/src/client/app/profile/profile-routing.module.ts
@@ -0,0 +1,16 @@
+import { NgModule } from '@angular/core';
+import { RouterModule, Routes } from '@angular/router';
+
+import { ProfileComponent } from './profile.component';
+
+const routes: Routes = [
+ { path: '', component: ProfileComponent }
+];
+
+@NgModule({
+ imports: [RouterModule.forChild(routes)],
+ exports: [RouterModule]
+})
+export class ProfileRoutingModule { }
+
+export const routedComponents = [ProfileComponent];
diff --git a/src/client/app/profile/profile.component.html b/src/client/app/profile/profile.component.html
new file mode 100644
index 0000000..3ffb4ed
--- /dev/null
+++ b/src/client/app/profile/profile.component.html
@@ -0,0 +1,7 @@
+Profile
+
diff --git a/src/client/app/profile/profile.component.scss b/src/client/app/profile/profile.component.scss
new file mode 100644
index 0000000..e69de29
diff --git a/src/client/app/profile/profile.component.ts b/src/client/app/profile/profile.component.ts
new file mode 100644
index 0000000..49c55ce
--- /dev/null
+++ b/src/client/app/profile/profile.component.ts
@@ -0,0 +1,65 @@
+import { Component, OnInit } from '@angular/core';
+import { FormBuilder, FormControl, FormGroup, Validators } from '@angular/forms';
+
+import { Role, User } from '../../../common/entities';
+
+import { UserService } from '../core';
+
+@Component({
+ selector: 'profile',
+ templateUrl: 'profile.component.html',
+ styleUrls: ['profile.component.scss']
+})
+
+export class ProfileComponent implements OnInit {
+
+ public user: User;
+ public profileForm: FormGroup;
+
+ constructor(
+ private formBuilder: FormBuilder,
+ private userService: UserService
+ ) { }
+
+ // interface methods
+ public ngOnInit() {
+ this.loadProfile();
+ this.buildProfileForm();
+ this.patchProfileFormValue(this.user);
+ }
+
+ // event methods
+ public onClickUpdate() {
+ const data = this.profileForm.getRawValue();
+ this.updateProfile(data);
+ }
+
+ private loadProfile() {
+ this.userService.currentUser$.subscribe((user: User) => {
+ this.user = user;
+ });
+ }
+
+ private buildProfileForm() {
+ this.profileForm = this.formBuilder.group({
+ email: ['', Validators.required]
+ });
+ }
+
+ private patchProfileFormValue(user: User) {
+ this.profileForm.patchValue({
+ email: user.email
+ });
+ }
+
+ private updateProfile(data: User) {
+ this.userService
+ .updateProfile(data)
+ .subscribe((user: User) => {
+ this.user = user;
+ this.patchProfileFormValue(this.user);
+ }, (error: Error) => {
+ console.log(error);
+ });
+ }
+}
diff --git a/src/client/app/profile/profile.module.ts b/src/client/app/profile/profile.module.ts
new file mode 100644
index 0000000..149b2f2
--- /dev/null
+++ b/src/client/app/profile/profile.module.ts
@@ -0,0 +1,18 @@
+import { NgModule } from '@angular/core';
+
+import { SharedModule } from '../shared';
+
+import { ProfileRoutingModule, routedComponents } from './profile-routing.module';
+
+@NgModule({
+ imports: [
+ SharedModule,
+ ProfileRoutingModule
+ ],
+ exports: [],
+ declarations: [
+ routedComponents
+ ],
+ providers: []
+})
+export class ProfileModule { }
diff --git a/src/client/app/shared/shared.module.ts b/src/client/app/shared/shared.module.ts
index 1eb7f17..08a9181 100644
--- a/src/client/app/shared/shared.module.ts
+++ b/src/client/app/shared/shared.module.ts
@@ -1,5 +1,6 @@
import { CommonModule } from '@angular/common';
import { NgModule } from '@angular/core';
+import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { MaterialModule } from '../material';
@@ -12,10 +13,14 @@ import { ListComponent } from './list/list.component';
@NgModule({
imports: [
CommonModule,
+ FormsModule,
+ ReactiveFormsModule,
MaterialModule
],
exports: [
CommonModule,
+ FormsModule,
+ ReactiveFormsModule,
MaterialModule,
ListComponent
],
diff --git a/src/server/app/users/user.controller.test.ts b/src/server/app/users/user.controller.test.ts
index 1a027c6..f9c7d94 100644
--- a/src/server/app/users/user.controller.test.ts
+++ b/src/server/app/users/user.controller.test.ts
@@ -105,4 +105,20 @@ describe('UserController', () => {
.expect(200);
});
});
+
+ describe.only('updateProfileById', async () => {
+ it('should update current user, /api/users/profile', async () => {
+ const data = await userService.login({
+ email: `admin@test.com`,
+ password: `test`
+ });
+ const response = await server
+ .put('/api/users/profile')
+ .set('x-access-token', data.token)
+ .send({
+ email: 'updated-admin@test.com'
+ });
+ expect(response.body).to.have.property('email', 'updated-admin@test.com');
+ });
+ });
});
diff --git a/src/server/app/users/user.controller.ts b/src/server/app/users/user.controller.ts
index d587055..0201ab6 100644
--- a/src/server/app/users/user.controller.ts
+++ b/src/server/app/users/user.controller.ts
@@ -1,4 +1,4 @@
-import { Body, Controller, Get, Post, UseGuards } from '@nestjs/common';
+import { Body, Controller, Get, Post, UseGuards, Put } from '@nestjs/common';
import { AccessTokenGuard, CurrentUser } from '../core';
@@ -30,4 +30,14 @@ export class UserController {
public getUsers() {
return this.userService.getUsers();
}
+
+ @Put('profile')
+ @UseGuards(AccessTokenGuard)
+ public async updateProfile(
+ @CurrentUser() currentUser: User,
+ @Body() user: User
+ ): Promise {
+ await this.userService.updateProfileById(currentUser.id, user);
+ return this.userService.getUserById(currentUser.id);
+ }
}
diff --git a/src/server/app/users/user.repository.ts b/src/server/app/users/user.repository.ts
index fd8f9e3..3338725 100644
--- a/src/server/app/users/user.repository.ts
+++ b/src/server/app/users/user.repository.ts
@@ -22,8 +22,14 @@ export class UserRepository extends Repository {
public async getUserByEmail(email: string): Promise {
return this.findOne({
- where: { email }
+ where: { email },
+ relations: ['roles']
});
}
+ public updateUserById(id: number, data: User): Promise {
+ delete data.created;
+ return this.updateById(id, data);
+ }
+
}
diff --git a/src/server/app/users/user.service.ts b/src/server/app/users/user.service.ts
index d738b46..9d5afae 100644
--- a/src/server/app/users/user.service.ts
+++ b/src/server/app/users/user.service.ts
@@ -1,4 +1,5 @@
import { Component, Inject, UnauthorizedException } from '@nestjs/common';
+import { classToPlain } from 'class-transformer';
import { BcryptService, JsonWebTokenService } from '../core';
import { User } from './user.entity';
@@ -22,11 +23,7 @@ export class UserService {
if (!isValidPassword) {
throw new UnauthorizedException();
}
- const token = this.jwtService.sign({
- id: user.id,
- email: user.email,
- roles: user.roles
- });
+ const token = this.jwtService.sign(classToPlain(user));
return { user, token };
}
@@ -39,4 +36,9 @@ export class UserService {
public async getUsers() {
return this.userRepository.getUsers({});
}
+
+ public updateProfileById(id: number, data: User) {
+ delete data.password;
+ return this.userRepository.updateUserById(id, data);
+ }
}