Allow disabling fields, add auth checks with logout, don't allow self-unadmining
This commit is contained in:
parent
079449d980
commit
1f45a3fb84
7 changed files with 54 additions and 16 deletions
|
@ -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<User>,
|
||||
): Promise<Count> {
|
||||
|
@ -136,6 +137,7 @@ export class UserController {
|
|||
},
|
||||
},
|
||||
})
|
||||
@authenticate('jwt')
|
||||
async find(
|
||||
@param.filter(User) filter?: Filter<User>,
|
||||
): Promise<User[]> {
|
||||
|
@ -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<User>
|
||||
|
@ -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<void> {
|
||||
await this.userRepository.deleteById(id);
|
||||
}
|
||||
|
|
|
@ -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<any> {
|
||||
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<T>(url: string, limit: number, page: number): Promise<T[]> {
|
||||
|
@ -32,7 +40,6 @@ export class ApiService {
|
|||
|
||||
async logout(): Promise<void> {
|
||||
await this.request('post', '/users/logout', '');
|
||||
this.loginService.token = null;
|
||||
this.loginService.user = null;
|
||||
this.loginService.deleteToken();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<void> {
|
||||
|
@ -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');
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,7 +3,9 @@
|
|||
<div *ngFor="let field of fields">
|
||||
<mat-label>{{ field.title }}</mat-label>
|
||||
<span [ngSwitch]="getType(item[field.name])">
|
||||
<span *ngSwitchCase="'boolean'"><mat-checkbox [checked]="item[field.name]" [formControlName]="field.name"></mat-checkbox></span>
|
||||
<span *ngSwitchCase="'boolean'">
|
||||
<mat-checkbox [checked]="item[field.name]" [formControlName]="field.name"></mat-checkbox>
|
||||
</span>
|
||||
<mat-form-field *ngSwitchDefault>
|
||||
<input matInput [formControlName]="field.name" type="text" [value]="item[field.name]"/>
|
||||
</mat-form-field>
|
||||
|
|
|
@ -16,7 +16,7 @@ export class EditComponent<T extends Model> 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<T>;
|
||||
formGroup: FormGroup;
|
||||
|
||||
|
@ -30,7 +30,13 @@ export class EditComponent<T extends Model> 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<T extends Model> 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);
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<app-edit [apiPath]="'/users'" [itemType]="itemType" [fields]="[
|
||||
{title: 'E-mail', name: 'email'},
|
||||
{title: 'Név', name: 'name'},
|
||||
{title: 'Admin', name: 'isAdmin'}
|
||||
{title: 'Admin', name: 'isAdmin', readonly: isEditingSelf}
|
||||
]"></app-edit>
|
||||
|
|
|
@ -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 {
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue