mirror of
https://github.com/CaramelFur/Picsur.git
synced 2025-11-13 15:25:39 +01:00
add permission handling on frontend
This commit is contained in:
@@ -1,7 +1,10 @@
|
|||||||
import { Injectable } from '@angular/core';
|
import { Injectable } from '@angular/core';
|
||||||
import { AutoUnsubscribe } from 'ngx-auto-unsubscribe-decorator';
|
import { AutoUnsubscribe } from 'ngx-auto-unsubscribe-decorator';
|
||||||
import { UserMePermissionsResponse } from 'picsur-shared/dist/dto/api/user.dto';
|
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 { AsyncFailable, HasFailed } from 'picsur-shared/dist/types';
|
||||||
import { BehaviorSubject } from 'rxjs';
|
import { BehaviorSubject } from 'rxjs';
|
||||||
import { ApiService } from './api.service';
|
import { ApiService } from './api.service';
|
||||||
@@ -15,19 +18,22 @@ export class PermissionService {
|
|||||||
this.onUser();
|
this.onUser();
|
||||||
}
|
}
|
||||||
|
|
||||||
public get livePermissions() {
|
public get live() {
|
||||||
return this.permissionsSubject;
|
return this.permissionsSubject;
|
||||||
}
|
}
|
||||||
|
|
||||||
public get permissions() {
|
public get snapshot() {
|
||||||
return this.permissionsSubject.getValue();
|
return this.permissionsSubject.getValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
private permissionsSubject = new BehaviorSubject<Permissions>([]);
|
// Lets be optimistic for better ux
|
||||||
|
private permissionsSubject = new BehaviorSubject<Permissions>(
|
||||||
|
PermissionsList as Permissions
|
||||||
|
);
|
||||||
|
|
||||||
@AutoUnsubscribe()
|
@AutoUnsubscribe()
|
||||||
private onUser() {
|
private onUser() {
|
||||||
return this.userService.liveUser.subscribe(async (user) => {
|
return this.userService.live.subscribe(async (user) => {
|
||||||
const permissions = await this.fetchPermissions();
|
const permissions = await this.fetchPermissions();
|
||||||
if (HasFailed(permissions)) {
|
if (HasFailed(permissions)) {
|
||||||
this.logger.warn(permissions.getReason());
|
this.logger.warn(permissions.getReason());
|
||||||
|
|||||||
@@ -19,11 +19,11 @@ import { KeyService } from './key.service';
|
|||||||
export class UserService {
|
export class UserService {
|
||||||
private readonly logger = console;
|
private readonly logger = console;
|
||||||
|
|
||||||
public get liveUser() {
|
public get live() {
|
||||||
return this.userSubject;
|
return this.userSubject;
|
||||||
}
|
}
|
||||||
|
|
||||||
public get user() {
|
public get snapshot() {
|
||||||
return this.userSubject.getValue();
|
return this.userSubject.getValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,2 +1,12 @@
|
|||||||
<footer class="container">
|
<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>
|
</footer>
|
||||||
|
|||||||
@@ -3,5 +3,5 @@ footer {
|
|||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
|
||||||
margin-top: 32px;
|
margin-top: 16px;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
|
|
||||||
<span class="spacer"></span>
|
<span class="spacer"></span>
|
||||||
|
|
||||||
<button *ngIf="!isLoggedIn" mat-stroked-button (click)="doLogin()">
|
<button *ngIf="!isLoggedIn && canLogIn" mat-stroked-button (click)="doLogin()">
|
||||||
Login
|
Login
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,10 @@
|
|||||||
import { Component, OnInit } from '@angular/core';
|
import { Component, OnInit } from '@angular/core';
|
||||||
import { Router } from '@angular/router';
|
import { Router } from '@angular/router';
|
||||||
import { AutoUnsubscribe } from 'ngx-auto-unsubscribe-decorator';
|
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 { EUser } from 'picsur-shared/dist/entities/user.entity';
|
||||||
import { HasFailed } from 'picsur-shared/dist/types';
|
import { HasFailed } from 'picsur-shared/dist/types';
|
||||||
|
import { PermissionService } from 'src/app/api/permission.service';
|
||||||
import { UserService } from 'src/app/api/user.service';
|
import { UserService } from 'src/app/api/user.service';
|
||||||
import { SnackBarType } from 'src/app/models/snack-bar-type';
|
import { SnackBarType } from 'src/app/models/snack-bar-type';
|
||||||
import { UtilService } from 'src/app/util/util.service';
|
import { UtilService } from 'src/app/util/util.service';
|
||||||
@@ -16,6 +18,7 @@ export class HeaderComponent implements OnInit {
|
|||||||
private readonly logger = console;
|
private readonly logger = console;
|
||||||
|
|
||||||
private currentUser: EUser | null = null;
|
private currentUser: EUser | null = null;
|
||||||
|
private permissions: Permissions = [];
|
||||||
|
|
||||||
public get user() {
|
public get user() {
|
||||||
return this.currentUser;
|
return this.currentUser;
|
||||||
@@ -25,24 +28,36 @@ export class HeaderComponent implements OnInit {
|
|||||||
return this.currentUser !== null;
|
return this.currentUser !== null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public get canLogIn() {
|
||||||
|
return this.permissions.includes('user-login');
|
||||||
|
}
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private router: Router,
|
private router: Router,
|
||||||
private userService: UserService,
|
private userService: UserService,
|
||||||
|
private permissionService: PermissionService,
|
||||||
private utilService: UtilService
|
private utilService: UtilService
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
this.subscribeUser();
|
this.subscribeUser();
|
||||||
|
this.subscribePermissions();
|
||||||
}
|
}
|
||||||
|
|
||||||
@AutoUnsubscribe()
|
@AutoUnsubscribe()
|
||||||
subscribeUser() {
|
subscribeUser() {
|
||||||
return this.userService.liveUser.subscribe((user) => {
|
return this.userService.live.subscribe((user) => {
|
||||||
this.logger.log('user', user);
|
|
||||||
this.currentUser = user;
|
this.currentUser = user;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@AutoUnsubscribe()
|
||||||
|
subscribePermissions() {
|
||||||
|
return this.permissionService.live.subscribe((permissions) => {
|
||||||
|
this.permissions = permissions;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
doLogin() {
|
doLogin() {
|
||||||
this.router.navigate(['/login']);
|
this.router.navigate(['/login']);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -37,7 +37,19 @@
|
|||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-12 py-2">
|
<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>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -0,0 +1,3 @@
|
|||||||
|
mat-form-field {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,6 +1,9 @@
|
|||||||
import { Component, OnInit } from '@angular/core';
|
import { Component, OnInit } from '@angular/core';
|
||||||
import { Router } from '@angular/router';
|
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 { HasFailed } from 'picsur-shared/dist/types';
|
||||||
|
import { PermissionService } from 'src/app/api/permission.service';
|
||||||
import { UserService } from 'src/app/api/user.service';
|
import { UserService } from 'src/app/api/user.service';
|
||||||
import { SnackBarType } from 'src/app/models/snack-bar-type';
|
import { SnackBarType } from 'src/app/models/snack-bar-type';
|
||||||
import { UtilService } from 'src/app/util/util.service';
|
import { UtilService } from 'src/app/util/util.service';
|
||||||
@@ -14,11 +17,18 @@ import { LoginControl } from './login.model';
|
|||||||
export class LoginComponent implements OnInit {
|
export class LoginComponent implements OnInit {
|
||||||
private readonly logger = console;
|
private readonly logger = console;
|
||||||
|
|
||||||
|
private permissions: Permissions = [];
|
||||||
|
|
||||||
|
public get showRegister() {
|
||||||
|
return this.permissions.includes('user-register');
|
||||||
|
}
|
||||||
|
|
||||||
model = new LoginControl();
|
model = new LoginControl();
|
||||||
loginFail = false;
|
loginFail = false;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private userService: UserService,
|
private userService: UserService,
|
||||||
|
private permissionService: PermissionService,
|
||||||
private router: Router,
|
private router: Router,
|
||||||
private utilService: UtilService
|
private utilService: UtilService
|
||||||
) {}
|
) {}
|
||||||
@@ -26,7 +36,17 @@ export class LoginComponent implements OnInit {
|
|||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
if (this.userService.isLoggedIn) {
|
if (this.userService.isLoggedIn) {
|
||||||
this.router.navigate(['/'], { replaceUrl: true });
|
this.router.navigate(['/'], { replaceUrl: true });
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.onPermissions();
|
||||||
|
}
|
||||||
|
|
||||||
|
@AutoUnsubscribe()
|
||||||
|
onPermissions() {
|
||||||
|
return this.permissionService.live.subscribe((permissions) => {
|
||||||
|
this.permissions = permissions;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async onSubmit() {
|
async onSubmit() {
|
||||||
@@ -45,4 +65,10 @@ export class LoginComponent implements OnInit {
|
|||||||
this.utilService.showSnackBar('Login successful', SnackBarType.Success);
|
this.utilService.showSnackBar('Login successful', SnackBarType.Success);
|
||||||
this.router.navigate(['/']);
|
this.router.navigate(['/']);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async onRegister() {
|
||||||
|
//prevent default
|
||||||
|
|
||||||
|
console.log('click');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,13 @@
|
|||||||
<div class="content-border">
|
<div class="content-border">
|
||||||
<ngx-dropzone (change)="onSelect($event)">
|
<ngx-dropzone *ngIf="hasUploadPermission" (change)="onSelect($event)">
|
||||||
<div class="centered">
|
<div class="centered">
|
||||||
<h1>Upload Image</h1>
|
<h1>Upload Image</h1>
|
||||||
<p>Drag and drop an image here, or click to select an image</p>
|
<p>Drag and drop an image here, or click to select an image</p>
|
||||||
</div>
|
</div>
|
||||||
</ngx-dropzone>
|
</ngx-dropzone>
|
||||||
|
|
||||||
|
<div class="centered" *ngIf="!hasUploadPermission">
|
||||||
|
<h1>Please Log In</h1>
|
||||||
|
<p>You do not yet have permission to upload</p>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,6 +1,9 @@
|
|||||||
import { Component } from '@angular/core';
|
import { Component, OnInit } from '@angular/core';
|
||||||
import { Router } from '@angular/router';
|
import { Router } from '@angular/router';
|
||||||
|
import { AutoUnsubscribe } from 'ngx-auto-unsubscribe-decorator';
|
||||||
import { NgxDropzoneChangeEvent } from 'ngx-dropzone';
|
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 { UtilService } from 'src/app/util/util.service';
|
||||||
import { ProcessingViewMetadata } from '../../models/processing-view-metadata';
|
import { ProcessingViewMetadata } from '../../models/processing-view-metadata';
|
||||||
|
|
||||||
@@ -8,8 +11,31 @@ import { ProcessingViewMetadata } from '../../models/processing-view-metadata';
|
|||||||
templateUrl: './upload.component.html',
|
templateUrl: './upload.component.html',
|
||||||
styleUrls: ['./upload.component.scss'],
|
styleUrls: ['./upload.component.scss'],
|
||||||
})
|
})
|
||||||
export class UploadComponent {
|
export class UploadComponent implements OnInit {
|
||||||
constructor(private utilService: UtilService, private router: Router) {}
|
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) {
|
onSelect(event: NgxDropzoneChangeEvent) {
|
||||||
if (event.addedFiles.length > 1) {
|
if (event.addedFiles.length > 1) {
|
||||||
this.utilService.showSnackBar(
|
this.utilService.showSnackBar(
|
||||||
|
|||||||
@@ -17,3 +17,28 @@
|
|||||||
height: 100%;
|
height: 100%;
|
||||||
width: 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user