Skip to content

Commit

Permalink
files: add permissions
Browse files Browse the repository at this point in the history
* Fixes broken `ng` command such as `ng c`.
* Adds permissions support to the file component to hide action buttons.

Co-Authored-by: Johnny Mariéthoz <[email protected]>
  • Loading branch information
jma authored and PascalRepond committed Aug 22, 2023
1 parent f43f891 commit c6e3bb3
Show file tree
Hide file tree
Showing 10 changed files with 282 additions and 95 deletions.
12 changes: 1 addition & 11 deletions angular.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"$schema": "./node_modules/@angular/cli/lib/config/schema.json",
"version": 1,
"newProjectRoot": "projects",
"defaultProject": "@rero/ng-core",
"projects": {
"@rero/ng-core": {
"projectType": "library",
Expand Down Expand Up @@ -167,15 +167,5 @@
}
}
}
},
"cli": {
"schematicCollections": [
"@ngx-formly/schematics"
]
},
"schematics": {
"@ngx-formly/schematics:component": {
"styleext": "scss"
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
<i class="fa fa-pencil"></i>
{{ 'Edit' | translate }}
</a>

<ng-container *ngIf="deleteStatus">
<button id="detail-delete-button" class="btn btn-sm btn-outline-danger ml-1" [title]="'Delete'|translate" (click)="deleteRecord(record)"
*ngIf="deleteStatus.can; else deleteMessageLink">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,6 @@ export class DetailComponent implements OnInit, OnDestroy {
this._location.back();
}
});

this._recordUiService.canDeleteRecord$(this.record, this._type).subscribe(result => {
this.deleteStatus = result;
});
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
<!--
RERO angular core
Copyright (C) 2022 RERO
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, version 3 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
-->

<ng-container *ngIf="file">
<div class="row">
<div class="col" [ngClass]="{ 'pl-5 text-muted': !file.is_head }">
<p class="m-0">
{{ file.key }}
<a href="#" class="ml-2" (click)="$event.preventDefault(); file.showInfo = !file.showInfo">
<i class="fa fa-info-circle"></i>
</a>
<a
href="#"
class="ml-2"
(click)="$event.preventDefault(); file.showChildren = !file.showChildren"
*ngIf="hasChildren"
>
<i class="fa fa-history"></i>
</a>
</p>
</div>
<div class="col text-right">
<button *ngIf="canUpdateMetadata.can" class="btn btn-sm btn-outline-primary" (click)="editMetadata()">
<i class="fa fa-pencil mr-1"></i>{{ 'Edit' | translate }}
</button>

<button *ngIf="canUpdate.can" class="btn btn-sm btn-outline-primary ml-1" (click)="manage()">
<i class="fa fa-upload mr-1"></i>{{ 'New version' | translate }}
</button>

<a [href]="file.url" target="_blank" class="btn btn-sm btn-outline-primary ml-1" download>
<i class="fa fa-download mr-1"></i>{{ 'Download' | translate }}
</a>

<button *ngIf="canDelete.can" class="btn btn-sm btn-outline-danger ml-1" (click)="delete()">
<i class="fa fa-trash mr-1"></i>{{ 'Delete' | translate }}
</button>
</div>
</div>
<div class="row mt-2" *ngIf="file.showInfo">
<div class="col" *ngIf="file.is_head">
<dl class="row mt-2 mb-0">
<ng-container *ngFor="let item of file.metadata | keyvalue">
<ng-container *ngIf="!infoExcludedFields.includes(item.key) && item.value">
<dt class="col-lg-4">{{ item.key | translate }}</dt>
<dd class="col-lg-8">{{ item.value | translate }}</dd>
</ng-container>
</ng-container>
</dl>
</div>
<div class="col" [ngClass]="{ 'pl-5 text-muted': !file.is_head }">
<dl class="row mt-2 mb-0">
<dt class="col-lg-4" translate>Size</dt>
<dd class="col-lg-8">{{ file.size | filesize }}</dd>

<dt class="col-lg-4" translate>Mime type</dt>
<dd class="col-lg-8">{{ file.mimetype }}</dd>

<dt class="col-lg-4" translate>Checksum</dt>
<dd class="col-lg-8">{{ file.checksum }}</dd>

<dt class="col-lg-4" translate>Modified at</dt>
<dd class="col-lg-8">{{ file.updated | dateTranslate : 'medium' }}</dd>
</dl>
</div>
</div>
</ng-container>
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';

import { FileComponent } from './file.component';
import { RecordUiService } from '../../record-ui.service';
import { TranslateModule } from '@ngx-translate/core';

const recordUiServiceSpy = jasmine.createSpyObj('RecordUiService', ['getResourceConfig']);
recordUiServiceSpy.getResourceConfig.and.returnValue({ key: 'documents', files: {} });
describe('FileComponent', () => {
let component: FileComponent;
let fixture: ComponentFixture<FileComponent>;

beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [FileComponent],
imports: [TranslateModule.forRoot()],
providers: [{ provide: RecordUiService, useValue: recordUiServiceSpy }],
}).compileComponents();

fixture = TestBed.createComponent(FileComponent);
component = fixture.componentInstance;
component.type = 'documents';
fixture.detectChanges();
});

it('should create', () => {
expect(component).toBeTruthy();
});
});
130 changes: 130 additions & 0 deletions projects/rero/ng-core/src/lib/record/files/file/file.component.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
/*
* RERO angular core
* Copyright (C) 2023 RERO
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, version 3 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

import { Component, EventEmitter, Input, OnDestroy, OnInit, Output } from '@angular/core';
import { RecordUiService } from '../../record-ui.service';
import { Subscription, of } from 'rxjs';
import { ActionStatus } from '../../action-status';

@Component({
selector: 'ng-core-record-file',
templateUrl: './file.component.html',
})
export class FileComponent implements OnInit, OnDestroy {
// record data
@Input() record: any;

// record file data
@Input() file: any;

// record type
@Input() type: any;

// true if the file has old versions
@Input() hasChildren: boolean;

// list of fields to not display
@Input() infoExcludedFields: Array<string> = [];

// event emitter when the delete button is clicked
@Output() deleteFile: EventEmitter<void> = new EventEmitter();

// event emitter when the edit metadata button is clicked
@Output() manageFile: EventEmitter<void> = new EventEmitter();

// event emitter when edit button is clicked
@Output() editMetadataFile: EventEmitter<void> = new EventEmitter();

// permissions
canUpdateMetadata: ActionStatus;
canUpdate: ActionStatus;
canDelete: ActionStatus;

// subscriptions to observables
private _subscriptions: Subscription = new Subscription();

/**
* Constructor.
*
* @param _recordUiService RecordUiService.
*/
constructor(private _recordUiService: RecordUiService) {}

/**
* hook OnInit
*/
ngOnInit(): void {
this.loadPermission();
}

/**
* Loads the permissions.
*/
loadPermission() {
const config = this._recordUiService.getResourceConfig(this.type);
let obs$ = config.files.canUpdate
? config.files.canUpdate(this.record, this.file)
: of({ can: false, message: '' });
this._subscriptions.add(
obs$.subscribe((result: ActionStatus) => {
this.canUpdate = result;
})
);
obs$ = config.files.canDelete ? config.files.canDelete(this.record, this.file) : of({ can: false, message: '' });
this._subscriptions.add(
obs$.subscribe((result: ActionStatus) => {
this.canDelete = result;
})
);
obs$ = config.files.canUpdate
? config.files.canUpdateMetadata(this.record, this.file)
: of({ can: false, message: '' });
this._subscriptions.add(
obs$.subscribe((result: ActionStatus) => {
this.canUpdateMetadata = result;
})
);
}

/**
* Component destruction.
*/
ngOnDestroy(): void {
this._subscriptions.unsubscribe();
}

/**
* Delete the file.
*/
delete() {
this.deleteFile.emit();
}

/**
* Edit the files.
*/
manage() {
this.manageFile.emit();
}

/**
* Edit the metadata.
*/
editMetadata() {
this.editMetadataFile.emit();
}
}
Loading

0 comments on commit c6e3bb3

Please sign in to comment.