add permission handling on frontend

This commit is contained in:
rubikscraft
2022-03-12 22:37:45 +01:00
parent 52434efdd7
commit 7026c8cb67
12 changed files with 144 additions and 16 deletions

View File

@@ -1,7 +1,10 @@
import { Injectable } from '@angular/core';
import { AutoUnsubscribe } from 'ngx-auto-unsubscribe-decorator';
import { UserMePermissionsResponse } from 'picsur-shared/dist/dto/api/user.dto';
import { Permissions } from 'picsur-shared/dist/dto/permissions';
import {
Permissions,
PermissionsList
} from 'picsur-shared/dist/dto/permissions';
import { AsyncFailable, HasFailed } from 'picsur-shared/dist/types';
import { BehaviorSubject } from 'rxjs';
import { ApiService } from './api.service';
@@ -15,19 +18,22 @@ export class PermissionService {
this.onUser();
}
public get livePermissions() {
public get live() {
return this.permissionsSubject;
}
public get permissions() {
public get snapshot() {
return this.permissionsSubject.getValue();
}
private permissionsSubject = new BehaviorSubject<Permissions>([]);
// Lets be optimistic for better ux
private permissionsSubject = new BehaviorSubject<Permissions>(
PermissionsList as Permissions
);
@AutoUnsubscribe()
private onUser() {
return this.userService.liveUser.subscribe(async (user) => {
return this.userService.live.subscribe(async (user) => {
const permissions = await this.fetchPermissions();
if (HasFailed(permissions)) {
this.logger.warn(permissions.getReason());

View File

@@ -19,11 +19,11 @@ import { KeyService } from './key.service';
export class UserService {
private readonly logger = console;
public get liveUser() {
public get live() {
return this.userSubject;
}
public get user() {
public get snapshot() {
return this.userSubject.getValue();
}

View File

@@ -1,2 +1,12 @@
<footer class="container">
<p>
Made with 🤍 by
<a class="link-unstyled" href="https://rubikscraft.nl" target="_blank"
>RubiksCraft</a
>
-
<a class="link-unstyled" href="https://github.com/rubikscraft/picsur"
>Source Code</a
>
</p>
</footer>

View File

@@ -3,5 +3,5 @@ footer {
flex-direction: column;
align-items: center;
margin-top: 32px;
margin-top: 16px;
}

View File

@@ -8,7 +8,7 @@
<span class="spacer"></span>
<button *ngIf="!isLoggedIn" mat-stroked-button (click)="doLogin()">
<button *ngIf="!isLoggedIn && canLogIn" mat-stroked-button (click)="doLogin()">
Login
</button>

View File

@@ -1,8 +1,10 @@
import { Component, OnInit } from '@angular/core';
import { Router } from '@angular/router';
import { AutoUnsubscribe } from 'ngx-auto-unsubscribe-decorator';
import { Permissions } from 'picsur-shared/dist/dto/permissions';
import { EUser } from 'picsur-shared/dist/entities/user.entity';
import { HasFailed } from 'picsur-shared/dist/types';
import { PermissionService } from 'src/app/api/permission.service';
import { UserService } from 'src/app/api/user.service';
import { SnackBarType } from 'src/app/models/snack-bar-type';
import { UtilService } from 'src/app/util/util.service';
@@ -16,6 +18,7 @@ export class HeaderComponent implements OnInit {
private readonly logger = console;
private currentUser: EUser | null = null;
private permissions: Permissions = [];
public get user() {
return this.currentUser;
@@ -25,24 +28,36 @@ export class HeaderComponent implements OnInit {
return this.currentUser !== null;
}
public get canLogIn() {
return this.permissions.includes('user-login');
}
constructor(
private router: Router,
private userService: UserService,
private permissionService: PermissionService,
private utilService: UtilService
) {}
ngOnInit(): void {
this.subscribeUser();
this.subscribePermissions();
}
@AutoUnsubscribe()
subscribeUser() {
return this.userService.liveUser.subscribe((user) => {
this.logger.log('user', user);
return this.userService.live.subscribe((user) => {
this.currentUser = user;
});
}
@AutoUnsubscribe()
subscribePermissions() {
return this.permissionService.live.subscribe((permissions) => {
this.permissions = permissions;
});
}
doLogin() {
this.router.navigate(['/login']);
}

View File

@@ -37,7 +37,19 @@
</mat-form-field>
</div>
<div class="col-12 py-2">
<button mat-raised-button color="accent" type="submit">Login</button>
<button mat-raised-button color="accent" class="mx-2" type="submit">
Login
</button>
<button
*ngIf="showRegister"
mat-raised-button
color="primary"
class="mx-2"
(click)="onRegister()"
type="button"
>
Register
</button>
</div>
</form>
</div>

View File

@@ -0,0 +1,3 @@
mat-form-field {
width: 100%;
}

View File

@@ -1,6 +1,9 @@
import { Component, OnInit } from '@angular/core';
import { Router } from '@angular/router';
import { AutoUnsubscribe } from 'ngx-auto-unsubscribe-decorator';
import { Permissions } from 'picsur-shared/dist/dto/permissions';
import { HasFailed } from 'picsur-shared/dist/types';
import { PermissionService } from 'src/app/api/permission.service';
import { UserService } from 'src/app/api/user.service';
import { SnackBarType } from 'src/app/models/snack-bar-type';
import { UtilService } from 'src/app/util/util.service';
@@ -14,11 +17,18 @@ import { LoginControl } from './login.model';
export class LoginComponent implements OnInit {
private readonly logger = console;
private permissions: Permissions = [];
public get showRegister() {
return this.permissions.includes('user-register');
}
model = new LoginControl();
loginFail = false;
constructor(
private userService: UserService,
private permissionService: PermissionService,
private router: Router,
private utilService: UtilService
) {}
@@ -26,7 +36,17 @@ export class LoginComponent implements OnInit {
ngOnInit(): void {
if (this.userService.isLoggedIn) {
this.router.navigate(['/'], { replaceUrl: true });
return;
}
this.onPermissions();
}
@AutoUnsubscribe()
onPermissions() {
return this.permissionService.live.subscribe((permissions) => {
this.permissions = permissions;
});
}
async onSubmit() {
@@ -45,4 +65,10 @@ export class LoginComponent implements OnInit {
this.utilService.showSnackBar('Login successful', SnackBarType.Success);
this.router.navigate(['/']);
}
async onRegister() {
//prevent default
console.log('click');
}
}

View File

@@ -1,8 +1,13 @@
<div class="content-border">
<ngx-dropzone (change)="onSelect($event)">
<ngx-dropzone *ngIf="hasUploadPermission" (change)="onSelect($event)">
<div class="centered">
<h1>Upload Image</h1>
<p>Drag and drop an image here, or click to select an image</p>
</div>
</ngx-dropzone>
<div class="centered" *ngIf="!hasUploadPermission">
<h1>Please Log In</h1>
<p>You do not yet have permission to upload</p>
</div>
</div>

View File

@@ -1,6 +1,9 @@
import { Component } from '@angular/core';
import { Component, OnInit } from '@angular/core';
import { Router } from '@angular/router';
import { AutoUnsubscribe } from 'ngx-auto-unsubscribe-decorator';
import { NgxDropzoneChangeEvent } from 'ngx-dropzone';
import { Permissions } from 'picsur-shared/dist/dto/permissions';
import { PermissionService } from 'src/app/api/permission.service';
import { UtilService } from 'src/app/util/util.service';
import { ProcessingViewMetadata } from '../../models/processing-view-metadata';
@@ -8,8 +11,31 @@ import { ProcessingViewMetadata } from '../../models/processing-view-metadata';
templateUrl: './upload.component.html',
styleUrls: ['./upload.component.scss'],
})
export class UploadComponent {
constructor(private utilService: UtilService, private router: Router) {}
export class UploadComponent implements OnInit {
private permissions: Permissions = [];
// Lets be optimistic here, this makes for a better ux
public get hasUploadPermission() {
return this.permissions.includes('image-upload');
}
constructor(
private utilService: UtilService,
private permissionService: PermissionService,
private router: Router
) {}
ngOnInit(): void {
this.onPermission();
}
@AutoUnsubscribe()
onPermission() {
return this.permissionService.live.subscribe((permissions) => {
this.permissions = permissions;
});
}
onSelect(event: NgxDropzoneChangeEvent) {
if (event.addedFiles.length > 1) {
this.utilService.showSnackBar(

View File

@@ -17,3 +17,28 @@
height: 100%;
width: 100%;
}
.link-unstyled {
&,
&:visited,
&:hover,
&:active,
&:focus,
&:active:hover {
font-style: inherit;
color: inherit;
background-color: transparent;
font-size: inherit;
text-decoration: none;
font-variant: inherit;
font-weight: bold;
line-height: inherit;
font-family: inherit;
border-radius: inherit;
border: inherit;
outline: inherit;
box-shadow: inherit;
padding: inherit;
vertical-align: inherit;
}
}