diff --git a/backend/src/controllers/user.controller.ts b/backend/src/controllers/user.controller.ts index bc72742..49949cf 100644 --- a/backend/src/controllers/user.controller.ts +++ b/backend/src/controllers/user.controller.ts @@ -118,6 +118,7 @@ export class UserController { description: 'User model count', content: {'application/json': {schema: CountSchema}}, }) + @authenticate('jwt') async count( @param.where(User) where?: Where, ): Promise { @@ -136,6 +137,7 @@ export class UserController { }, }, }) + @authenticate('jwt') async find( @param.filter(User) filter?: Filter, ): Promise { @@ -147,6 +149,7 @@ export class UserController { description: 'User PATCH success count', content: {'application/json': {schema: CountSchema}}, }) + @authenticate('jwt') async updateAll( @requestBody({ content: { @@ -170,6 +173,7 @@ export class UserController { }, }, }) + @authenticate('jwt') async findById( @param.path.number('id') id: number, @param.filter(User, {exclude: 'where'}) filter?: FilterExcludingWhere @@ -181,6 +185,7 @@ export class UserController { @response(204, { description: 'User PATCH success', }) + @authenticate('jwt') async updateById( @param.path.number('id') id: number, @requestBody({ @@ -199,6 +204,7 @@ export class UserController { @response(204, { description: 'User DELETE success', }) + @authenticate('jwt') async deleteById(@param.path.number('id') id: number): Promise { await this.userRepository.deleteById(id); } diff --git a/frontend/src/app/api.service.ts b/frontend/src/app/api.service.ts index c4396fe..fb849fa 100644 --- a/frontend/src/app/api.service.ts +++ b/frontend/src/app/api.service.ts @@ -2,20 +2,28 @@ import { Injectable } from '@angular/core'; import { HttpClient } from '@angular/common/http'; import { environment } from '../environments/environment'; import { LoginService } from './auth/login.service'; +import { Router } from '@angular/router'; @Injectable({ providedIn: 'root' }) export class ApiService { - constructor(private http: HttpClient, private loginService: LoginService) { + constructor(private http: HttpClient, private loginService: LoginService, private router: Router) { } request(method: 'post' | 'get' | 'delete' | 'patch', url: string, body: any): Promise { return this.http.request(method, environment.backendUrl + url, { body, headers: {Authorization: 'Bearer ' + this.loginService.token} - }).toPromise(); + }).toPromise().catch(e => { + if (e.status === 401) { + this.loginService.deleteToken(); + return this.router.navigateByUrl('/auth/login'); + } else { + throw e; + } + }); } requestPage(url: string, limit: number, page: number): Promise { @@ -32,7 +40,6 @@ export class ApiService { async logout(): Promise { await this.request('post', '/users/logout', ''); - this.loginService.token = null; - this.loginService.user = null; + this.loginService.deleteToken(); } } diff --git a/frontend/src/app/auth/login.service.ts b/frontend/src/app/auth/login.service.ts index 7ea81e1..1cfeed8 100644 --- a/frontend/src/app/auth/login.service.ts +++ b/frontend/src/app/auth/login.service.ts @@ -8,12 +8,20 @@ import { User } from '../model/user.model'; }) export class LoginService { - token: string; - user: User; + private tokenP: string; + private userP: User; + + get token(): string { + return this.tokenP; + } + + get user(): User { + return this.userP; + } constructor(private http: HttpClient) { - this.token = window.localStorage.getItem('token'); - this.user = JSON.parse(window.localStorage.getItem('user')); + this.tokenP = window.localStorage.getItem('token'); + this.userP = JSON.parse(window.localStorage.getItem('user')); } async createUser(email: string, password: string, name: string): Promise { @@ -26,8 +34,8 @@ export class LoginService { email, password }).toPromise(); - this.token = resp.token; - this.user = resp.user; + this.tokenP = resp.token; + this.userP = resp.user; window.localStorage.setItem('token', resp.token); window.localStorage.setItem('user', JSON.stringify(resp.user)); return true; @@ -38,4 +46,11 @@ export class LoginService { throw e; } } + + deleteToken(): void { + this.tokenP = null; + this.userP = null; + window.localStorage.removeItem('token'); + window.localStorage.removeItem('user'); + } } diff --git a/frontend/src/app/shared-components/edit/edit.component.html b/frontend/src/app/shared-components/edit/edit.component.html index 848e061..c98418b 100644 --- a/frontend/src/app/shared-components/edit/edit.component.html +++ b/frontend/src/app/shared-components/edit/edit.component.html @@ -3,7 +3,9 @@
{{ field.title }} - + + + diff --git a/frontend/src/app/shared-components/edit/edit.component.ts b/frontend/src/app/shared-components/edit/edit.component.ts index 0cea344..e529399 100644 --- a/frontend/src/app/shared-components/edit/edit.component.ts +++ b/frontend/src/app/shared-components/edit/edit.component.ts @@ -16,7 +16,7 @@ export class EditComponent implements OnInit { isLoading = true; @Input() apiPath: string; - @Input() fields: { title: string, name: keyof T }[]; + @Input() fields: { title: string, name: keyof T, readonly?: (item: T) => boolean }[]; @Input() itemType: Type; formGroup: FormGroup; @@ -30,7 +30,13 @@ export class EditComponent implements OnInit { if (!this.item && url[url.length - 1].path !== 'new') { this.item = await this.api.request('get', this.apiPath + '/' + this.route.snapshot.url[this.route.snapshot.url.length - 1], {}); } - this.formGroup = this.fb.group(this.fields.reduce((pv, cv) => Object.assign(pv, {[cv.name]: new FormControl()}), {})); + this.formGroup = this.fb.group(this.fields.reduce((pv, cv) => { + const control = new FormControl(); + if (cv.readonly && cv.readonly(this.item)) { + control.disable(); + } + return Object.assign(pv, {[cv.name]: control}); + }, {})); if (this.item) { this.formGroup.patchValue(this.item); } else { @@ -48,7 +54,7 @@ export class EditComponent implements OnInit { } else { await this.api.request('post', this.apiPath, this.formGroup.value); } - await this.router.navigateByUrl(this.router.url.substring(0, this.router.url.lastIndexOf('/'))); + await this.router.navigate(this.route.parent.snapshot.url.map(segment => segment.path)); } catch (e) { alert(e.message); } diff --git a/frontend/src/app/users/user-edit/user-edit.component.html b/frontend/src/app/users/user-edit/user-edit.component.html index 0f047e4..e5ac911 100644 --- a/frontend/src/app/users/user-edit/user-edit.component.html +++ b/frontend/src/app/users/user-edit/user-edit.component.html @@ -1,5 +1,5 @@ diff --git a/frontend/src/app/users/user-edit/user-edit.component.ts b/frontend/src/app/users/user-edit/user-edit.component.ts index dc32870..328f839 100644 --- a/frontend/src/app/users/user-edit/user-edit.component.ts +++ b/frontend/src/app/users/user-edit/user-edit.component.ts @@ -1,5 +1,6 @@ import { Component, OnInit } from '@angular/core'; import { User } from '../../model/user.model'; +import { LoginService } from '../../auth/login.service'; @Component({ selector: 'app-user-edit', @@ -8,8 +9,9 @@ import { User } from '../../model/user.model'; }) export class UserEditComponent implements OnInit { itemType = User; + isEditingSelf = user => user.id === this.userService.user.id; - constructor() { } + constructor(private userService: LoginService) { } ngOnInit(): void { }