Commit dcf243b6 authored by François Agneray's avatar François Agneray
Browse files

Instance public private => WIP

parent 7e963a3e
......@@ -19,7 +19,6 @@ import * as authSelector from 'src/app/auth/auth.selector';
import * as databaseActions from 'src/app/metamodel/actions/database.actions';
import * as selectActions from 'src/app/metamodel/actions/select.actions';
import * as optionActions from 'src/app/metamodel/actions/select-option.actions';
import * as instanceGroupActions from 'src/app/metamodel/actions/instance-group.actions';
import { AppConfigService } from 'src/app/app-config.service';
@Component({
......@@ -60,7 +59,6 @@ export class AdminComponent implements OnInit {
Promise.resolve(null).then(() => this.store.dispatch(databaseActions.loadDatabaseList()));
Promise.resolve(null).then(() => this.store.dispatch(selectActions.loadSelectList()));
Promise.resolve(null).then(() => this.store.dispatch(optionActions.loadSelectOptionList()));
Promise.resolve(null).then(() => this.store.dispatch(instanceGroupActions.loadInstanceGroupList()));
}
getBaseHref() {
......
......@@ -11,15 +11,15 @@
Instance groups
</a>
</li>
<li *ngIf="instanceGroupListIsLoaded | async" class="breadcrumb-item active" aria-current="page">Edit instance group {{ (instanceGroup | async).role }}</li>
<li class="breadcrumb-item active" aria-current="page">Edit instance group {{ (instanceGroup | async).role }}</li>
</ol>
</nav>
</div>
<div class="container">
<app-spinner *ngIf="(instanceGroupListIsLoading | async) || (instanceListIsLoading | async)"></app-spinner>
<app-spinner *ngIf="(instanceListIsLoading | async)"></app-spinner>
<div *ngIf="(instanceGroupListIsLoaded | async) && (instanceListIsLoaded | async)" class="row">
<div *ngIf="(instanceListIsLoaded | async)" class="row">
<div class="col-12">
<app-instance-group-form [instanceGroup]="instanceGroup | async" [instanceList]="instanceList | async" (onSubmit)="editInstanceGroup($event)" #formGroup>
<button [disabled]="!formGroup.form.valid || formGroup.form.pristine" type="submit" class="btn btn-primary">
......
......@@ -21,16 +21,12 @@ import * as instanceGroupSelector from 'src/app/metamodel/selectors/instance-gro
templateUrl: 'edit-instance-group.component.html'
})
export class EditInstanceGroupComponent {
public instanceGroupListIsLoading: Observable<boolean>;
public instanceGroupListIsLoaded: Observable<boolean>;
public instanceGroup: Observable<InstanceGroup>;
public instanceListIsLoading: Observable<boolean>;
public instanceListIsLoaded: Observable<boolean>;
public instanceList: Observable<Instance[]>;
constructor(private store: Store<{ }>) {
this.instanceGroupListIsLoading = store.select(instanceGroupSelector.selectInstanceGroupListIsLoading);
this.instanceGroupListIsLoaded = store.select(instanceGroupSelector.selectInstanceGroupListIsLoaded);
this.instanceGroup = store.select(instanceGroupSelector.selectInstanceGroupByRouteId);
this.instanceListIsLoading = store.select(instanceSelector.selectInstanceListIsLoading);
this.instanceListIsLoaded = store.select(instanceSelector.selectInstanceListIsLoaded);
......
......@@ -10,28 +10,24 @@
</ol>
</nav>
<app-spinner *ngIf="instanceGroupListIsLoading | async"></app-spinner>
<ng-container *ngIf="instanceGroupListIsLoaded | async">
<div class="row">
<div class="col-12">
<button title="Add a new instance group" class="btn btn-outline-success float-right" routerLink="new-group">
<span class="fas fa-plus"></span> New instance group
</button>
</div>
<div class="row">
<div class="col-12">
<button title="Add a new instance group" class="btn btn-outline-success float-right" routerLink="new-group">
<span class="fas fa-plus"></span> New instance group
</button>
</div>
</div>
<div class="row mt-1">
<div class="col-12 lead text-center font-weight-bold" *ngIf="(instanceGroupList | async).length < 1">
Oops! No instance groups available...
</div>
<div class="row mt-1">
<div class="col-12 lead text-center font-weight-bold" *ngIf="(instanceGroupList | async).length < 1">
Oops! No instance groups available...
</div>
<div class="col-12" *ngIf="(instanceGroupList | async).length > 0">
<app-instance-group-table
[instanceGroupList]="instanceGroupList | async"
(deleteInstanceGroup)="deleteInstanceGroup($event)">
</app-instance-group-table>
</div>
<div class="col-12" *ngIf="(instanceGroupList | async).length > 0">
<app-instance-group-table
[instanceGroupList]="instanceGroupList | async"
(deleteInstanceGroup)="deleteInstanceGroup($event)">
</app-instance-group-table>
</div>
</ng-container>
</div>
</div>
......@@ -20,13 +20,9 @@ import * as instanceGroupSelector from 'src/app/metamodel/selectors/instance-gro
templateUrl: 'instance-group-list.component.html'
})
export class InstanceGroupListComponent {
public instanceGroupListIsLoading: Observable<boolean>;
public instanceGroupListIsLoaded: Observable<boolean>;
public instanceGroupList: Observable<InstanceGroup[]>;
constructor(private store: Store<{ }>) {
this.instanceGroupListIsLoading = store.select(instanceGroupSelector.selectInstanceGroupListIsLoading);
this.instanceGroupListIsLoaded = store.select(instanceGroupSelector.selectInstanceGroupListIsLoaded);
this.instanceGroupList = store.select(instanceGroupSelector.selectAllInstanceGroups);
}
......
<div *ngIf="(instanceListIsLoading | async)" class="row justify-content-center mt-5">
<div *ngIf="(instanceListIsLoading | async) || (instanceGroupListIsLoading | async)" class="row justify-content-center mt-5">
<span class="fas fa-circle-notch fa-spin fa-3x"></span>
<span class="sr-only">Loading...</span>
</div>
<router-outlet *ngIf="(instanceListIsLoaded | async)"></router-outlet>
<router-outlet *ngIf="(instanceListIsLoaded | async) && (instanceGroupListIsLoaded | async)"></router-outlet>
<footer class="footer mt-auto bg-light">
<div class="container my-3">
<div class="row justify-content-center font-weight-bold mb-1">
......
......@@ -18,6 +18,8 @@ import * as authActions from 'src/app/auth/auth.actions';
import * as authSelector from 'src/app/auth/auth.selector';
import * as instanceActions from 'src/app/metamodel/actions/instance.actions';
import * as instanceSelector from 'src/app/metamodel/selectors/instance.selector';
import * as instanceGroupActions from 'src/app/metamodel/actions/instance-group.actions';
import * as instanceGroupSelector from 'src/app/metamodel/selectors/instance-group.selector';
import { UserProfile } from 'src/app/auth/user-profile.model';
import { AppConfigService } from 'src/app/app-config.service';
......@@ -34,6 +36,8 @@ export class AppComponent implements OnInit {
public year: number = (new Date()).getFullYear();
public instanceListIsLoading: Observable<boolean>;
public instanceListIsLoaded: Observable<boolean>;
public instanceGroupListIsLoading: Observable<boolean>;
public instanceGroupListIsLoaded: Observable<boolean>;
public isAuthenticated: Observable<boolean>;
public userProfile: Observable<UserProfile>;
public userRoles: Observable<string[]>;
......@@ -41,6 +45,8 @@ export class AppComponent implements OnInit {
constructor(private store: Store<{ auth: fromAuth.State }>, private config: AppConfigService) {
this.instanceListIsLoading = store.select(instanceSelector.selectInstanceListIsLoading);
this.instanceListIsLoaded = store.select(instanceSelector.selectInstanceListIsLoaded);
this.instanceGroupListIsLoading = store.select(instanceGroupSelector.selectInstanceGroupListIsLoading);
this.instanceGroupListIsLoaded = store.select(instanceGroupSelector.selectInstanceGroupListIsLoaded);
this.isAuthenticated = store.select(authSelector.selectIsAuthenticated);
this.userProfile = store.select(authSelector.selectUserProfile);
this.userRoles = store.select(authSelector.selectUserRoles);
......@@ -50,6 +56,7 @@ export class AppComponent implements OnInit {
// Create a micro task that is processed after the current synchronous code
// This micro task prevent the expression has changed after view init error
Promise.resolve(null).then(() => this.store.dispatch(instanceActions.loadInstanceList()));
Promise.resolve(null).then(() => this.store.dispatch(instanceGroupActions.loadInstanceGroupList()));
}
/**
......
......@@ -21,6 +21,8 @@ export interface Instance {
wavelength_domain: string;
display: number;
data_path: string;
files_path: string;
public: boolean;
portal_logo: string;
design_color: string;
design_background_color: string;
......
......@@ -56,4 +56,4 @@ export const selectInstanceByRouteName = createSelector(
export const selectInstanceNameByRoute = createSelector(
reducer.selectRouterState,
router => router.state.params.iname as string
);
\ No newline at end of file
);
......@@ -22,8 +22,8 @@
</p>
</div>
<div class="card-footer bg-transparent text-right">
<a routerLink="/instance/{{ instance.name }}" class="btn btn-outline-primary" title="Go to instance">
<button [disabled]="!isInstanceAccessible()" routerLink="/instance/{{ instance.name }}" class="btn btn-outline-primary" title="Go to instance">
Go to instance
</a>
</button>
</div>
</div>
......@@ -9,8 +9,7 @@
import { Component, Input, ChangeDetectionStrategy } from '@angular/core';
import { AppConfigService } from 'src/app/app-config.service';
import { Instance } from 'src/app/metamodel/models';
import { Instance, InstanceGroup } from 'src/app/metamodel/models';
/**
* @class
......@@ -24,6 +23,11 @@ import { Instance } from 'src/app/metamodel/models';
})
export class InstanceCardComponent {
@Input() instance: Instance;
@Input() authenticationEnabled: boolean;
@Input() isAuthenticated: boolean;
@Input() userRoles: string[];
@Input() adminRoles: string[];
@Input() instanceGroupList: InstanceGroup[];
@Input() apiUrl: string;
/**
......@@ -34,4 +38,35 @@ export class InstanceCardComponent {
getLogoSrc(): string {
return `${this.apiUrl}/instance/${this.instance.name}/file-explorer${this.instance.portal_logo}`;
}
isInstanceAccessible() {
let accessible = true;
if (this.authenticationEnabled && !this.instance.public && !this.isAdmin()) {
accessible = false;
if (this.isAuthenticated) {
accessible = this.instanceGroupList
.filter(instanceGroup => instanceGroup.instances.includes(this.instance.name))
.filter(instanceGroup => this.userRoles.includes(instanceGroup.role))
.length > 0;
}
}
return accessible;
}
/**
* Returns true if user is admin
*
* @returns boolean
*/
isAdmin() {
let admin = false;
for (let i = 0; i < this.adminRoles.length; i++) {
admin = this.userRoles.includes(this.adminRoles[i]);
if (admin) break;
}
return admin;
}
}
......@@ -28,6 +28,11 @@
<div class="col-auto mb-3" *ngFor="let instance of (instanceList | async)">
<app-instance-card
[instance]="instance"
[authenticationEnabled]="getAuthenticationEnabled()"
[isAuthenticated]="isAuthenticated | async"
[userRoles]="userRoles | async"
[adminRoles]="getAdminRoles()"
[instanceGroupList]="instanceGroupList | async"
[apiUrl]="getApiUrl()">
</app-instance-card>
</div>
......
......@@ -14,10 +14,11 @@ import { Store } from '@ngrx/store';
import * as fromRouter from '@ngrx/router-store';
import { UserProfile } from 'src/app/auth/user-profile.model';
import { Instance } from 'src/app/metamodel/models';
import { Instance, InstanceGroup } from 'src/app/metamodel/models';
import * as authActions from 'src/app/auth/auth.actions';
import * as authSelector from 'src/app/auth/auth.selector';
import * as instanceSelector from 'src/app/metamodel/selectors/instance.selector';
import * as instanceGroupSelector from 'src/app/metamodel/selectors/instance-group.selector';
import { AppConfigService } from 'src/app/app-config.service';
/**
......@@ -40,6 +41,7 @@ export class PortalHomeComponent implements OnInit {
public userProfile: Observable<UserProfile>;
public userRoles: Observable<string[]>;
public instanceList: Observable<Instance[]>;
public instanceGroupList: Observable<InstanceGroup[]>;
public url: Observable<string>;
public userRolesSubscription: Subscription;
......@@ -48,6 +50,7 @@ export class PortalHomeComponent implements OnInit {
this.userProfile = store.select(authSelector.selectUserProfile);
this.userRoles = store.select(authSelector.selectUserRoles);
this.instanceList = store.select(instanceSelector.selectAllInstances);
this.instanceGroupList = store.select(instanceGroupSelector.selectAllInstanceGroups);
this.url = store.select(fromRouter.getSelectors().selectUrl);
}
......
......@@ -35,7 +35,7 @@ services:
SSO_AUTH_URL: "http://localhost:8180/auth"
SSO_REALM: "anis"
SSO_CLIENT_ID: "anis-client"
TOKEN_ENABLED: 0
TOKEN_ENABLED: 1
TOKEN_JWKS_URL: "http://keycloak:8180/auth/realms/anis/protocol/openid-connect/certs"
TOKEN_ADMIN_ROLES: anis_admin,superuser
RMQ_HOST: rmq
......
......@@ -63,8 +63,8 @@ final class InstanceListAction extends AbstractAction
}
if ($request->getMethod() === GET) {
//$instances = $this->em->getRepository('App\Entity\Instance')->findAll();
$instances = $this->getInstanceList($request->getAttribute('token'));
$instances = $this->em->getRepository('App\Entity\Instance')->findAll();
//$instances = $this->getInstanceList($request->getAttribute('token'));
$payload = json_encode($instances);
}
......@@ -90,34 +90,34 @@ final class InstanceListAction extends AbstractAction
return $response;
}
private function getInstanceList($token)
{
$qb = $this->em->createQueryBuilder();
$qb->select('i')->from('App\Entity\Instance', 'i');
if (boolval($this->settings['enabled'])) {
if (!$token) {
// If user is not connected return public instances
$qb->andWhere($qb->expr()->eq('i.public', 'true'));
} else {
$adminRoles = explode(',', $this->settings['admin_roles']);
$roles = $token->realm_access->roles;
if (!$this->isAdmin($adminRoles, $roles)) {
// If user is not an admin return public datasets
// And returns datasets from user's groups
$qb->andWhere($qb->expr()->eq('i.public', 'true'));
$qb2 = $this->em->createQueryBuilder();
$qb2->select('i2.name')
->from('App\Entity\InstanceGroup', 'ig')
->join('ig.instances', 'i2')
->where($qb2->expr()->in('ig.role', $roles));
$qb->orWhere($qb->expr()->in('i.name', $qb2->getDQL()));
}
}
}
return $qb->getQuery()->getResult();
}
// private function getInstanceList($token)
// {
// $qb = $this->em->createQueryBuilder();
// $qb->select('i')->from('App\Entity\Instance', 'i');
// if (boolval($this->settings['enabled'])) {
// if (!$token) {
// // If user is not connected return public instances
// $qb->andWhere($qb->expr()->eq('i.public', 'true'));
// } else {
// $adminRoles = explode(',', $this->settings['admin_roles']);
// $roles = $token->realm_access->roles;
// if (!$this->isAdmin($adminRoles, $roles)) {
// // If user is not an admin return public datasets
// // And returns datasets from user's groups
// $qb->andWhere($qb->expr()->eq('i.public', 'true'));
// $qb2 = $this->em->createQueryBuilder();
// $qb2->select('i2.name')
// ->from('App\Entity\InstanceGroup', 'ig')
// ->join('ig.instances', 'i2')
// ->where($qb2->expr()->in('ig.role', $roles));
// $qb->orWhere($qb->expr()->in('i.name', $qb2->getDQL()));
// }
// }
// }
// return $qb->getQuery()->getResult();
// }
/**
* Add a new instance into the metamodel
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment