-
Notifications
You must be signed in to change notification settings - Fork 0
Feature/#31 cms profile page #43
base: develop
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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]; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
<h3>Profile</h3> | ||
<form [formGroup]="profileForm"> | ||
<mat-form-field> | ||
<input matInput type="text" placeholder="Email" formControlName="email"> | ||
</mat-form-field> | ||
<button mat-raised-button type="button" (click)="onClickUpdate()">Update</button> | ||
</form> |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Let's practice declaring constructor params as There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Alright |
||
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) => { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Break the line in the |
||
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); | ||
}); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 { } |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -105,4 +105,20 @@ describe('UserController', () => { | |
.expect(200); | ||
}); | ||
}); | ||
|
||
describe.only('updateProfileById', async () => { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please remove |
||
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'); | ||
}); | ||
}); | ||
}); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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') | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Doesn't the proper http resource url for I believe this should be something There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Oh I see you are getting it to the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. hmm you are right. Do you have any idea on how to update user profile and at the same time can edit by the admin? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. maybe a different endpoint? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why not have a generic endpoint for updating an account? Like the resource url above mentioned as it just needed an accessToken to allow or disallow certain roles. I think having the currentUser and an admin decorator will satisfy the permissions. |
||
@UseGuards(AccessTokenGuard) | ||
public async updateProfile( | ||
@CurrentUser() currentUser: User, | ||
@Body() user: User | ||
): Promise<User> { | ||
await this.userService.updateProfileById(currentUser.id, user); | ||
return this.userService.getUserById(currentUser.id); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -22,8 +22,14 @@ export class UserRepository extends Repository<User> { | |
|
||
public async getUserByEmail(email: string): Promise<User> { | ||
return this.findOne({ | ||
where: { email } | ||
where: { email }, | ||
relations: ['roles'] | ||
}); | ||
} | ||
|
||
public updateUserById(id: number, data: User): Promise<void> { | ||
delete data.created; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why delete the |
||
return this.updateById(id, data); | ||
} | ||
|
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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)); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hahaha this is good haven't thought about this 👌 but I have a question, don't you think that this will always be unique to each other? Or do you think we should update the passed There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think jwt returns unique token even the data is always the same |
||
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; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Wait, we cannot update without There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Actually I want to separate the endpoint of changing password. I don't want to update the password always for just updating the profile. I can't see any real application that does that. I think it is better to break down all properties that needs to be updated |
||
return this.userRepository.updateUserById(id, data); | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry but
ProfileRoutingModule
is not a good class name hahaha why not name files like this asroutes.ts
?So when I look at the files inside the folder I could see the ff:
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ahh I believe I posted before that we will johnpapa's style guide in client and in server side the nest-js style guide extension in vscode
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does john papa's style do that naming?