Skip to content

Commit

Permalink
document: add filter on holdings by items
Browse files Browse the repository at this point in the history
The standard holdings present on the document are filtered
according to a count of the displayable items.
The serial holdings present on the document are automatically displayed.

Permissions: If a library field exists on the resource,
it allows you to check if it matches the connected user.

* Fixes the display of the masking information on the item.
* Improves permission controls.
* Closes rero/rero-ils#1989

Co-Authored-by: Bertrand Zuchuat <bertrand.zuchuat@rero.ch>
  • Loading branch information
Garfield-fr committed Jun 11, 2021
1 parent 174ea48 commit 1a1a19d
Show file tree
Hide file tree
Showing 11 changed files with 98 additions and 56 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,14 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
-->
<div class="container item px-0 mt-1 mb-2" *ngIf="item && permissions">

<div class="row">
<!-- METADATA COLUMN -->
<div class="col-10">
<div class="row">
<!-- Barcode -->
<div class="col-4 pl-5 font-weight-bold label-title" translate>Barcode</div>
<div class="col-8">
<admin-record-masked *ngIf="item.metadata._masked" [record]="item"></admin-record-masked>
<a [routerLink]="['/records', 'items', 'detail', item.metadata.pid]" name="barcode">
{{ item.metadata.barcode }}
</a>
Expand Down Expand Up @@ -111,7 +111,4 @@
</ng-template>
</div>
</div>



</div>
Original file line number Diff line number Diff line change
Expand Up @@ -61,29 +61,33 @@ export class DefaultHoldingItemComponent implements OnInit {
) { }

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


// COMPONENT FUNCTIONS ================================================================
/** Get permissions */
private _getPermissions() {
private _getPermissions(): void {
const permissionObs = this._recordPermissionService.getPermission('items', this.item.metadata.pid);
const canRequestObs = this._itemService.canRequest(this.item.metadata.pid);
forkJoin([permissionObs, canRequestObs]).subscribe(
([permissions, canRequest]) => {
this.permissions = permissions;
this.permissions = this._recordPermissionService
.isMembership(
this._userService.user,
this.item.metadata.library.pid,
permissions
);
this.permissions.canRequest = canRequest;
});
}


/**
* Add request on item and refresh permissions
* @param itemPid - string
*/
addRequest(itemPid: string) {
addRequest(itemPid: string): void {
const modalRef = this._modalService.show(ItemRequestComponent, {
initialState: { itemPid }
});
Expand All @@ -94,7 +98,7 @@ export class DefaultHoldingItemComponent implements OnInit {
* Delete item
* @param itemPid - Item pid
*/
delete(itemPid) {
delete(itemPid): void {
this.deleteItem.emit(itemPid);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,9 @@ import { Component, EventEmitter, Input, OnDestroy, OnInit, Output } from '@angu
import { TranslateService } from '@ngx-translate/core';
import { RecordService, RecordUiService } from '@rero/ng-core';
import { Record } from '@rero/ng-core/lib/record/record';
import { UserService } from '@rero/shared';
import { RecordPermission, RecordPermissionService } from 'projects/admin/src/app/service/record-permission.service';
import { map } from 'rxjs/operators';


@Component({
Expand Down Expand Up @@ -51,17 +53,19 @@ export class HoldingComponent implements OnInit, OnDestroy {

// CONSTRUCTOR & HOOKS ======================================================
/**
* constructor
* Constructor
* @param _recordUiService - RecordUiService
* @param _recordService - RecordService
* @param _recordPermissionService - RecordPermissionService
* @param _translateService - TranslateService
* @param _userService - UserService
*/
constructor(
private _recordUiService: RecordUiService,
private _recordService: RecordService,
private _recordPermissionService: RecordPermissionService,
private _translateService: TranslateService,
protected _userService: UserService
) { }

/** onInit hook */
Expand All @@ -84,6 +88,13 @@ export class HoldingComponent implements OnInit, OnDestroy {
private _getPermissions(): void {
this._recordPermissionService
.getPermission('holdings', this.holding.metadata.pid)
.pipe(map((permissions: RecordPermission) => {
return this._recordPermissionService.isMembership(
this._userService.user,
this.holding.metadata.library.pid,
permissions
);
}))
.subscribe(permissions => this.permissions = permissions);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
<div class="container px-0 mt-1 mb-2" *ngIf="item && permissions && item.metadata.issue.status !== itemIssueStatus.DELETED">
<div class="row"> <!-- First row :: item detail -->
<div class="col-sm-3">
<admin-record-masked *ngIf="item.metadata._masked" [record]="holding"></admin-record-masked>
<admin-record-masked *ngIf="item.metadata._masked" [record]="item"></admin-record-masked>
<a [routerLink]="['/records', 'items', 'detail', item.metadata.pid]" name="barcode">
{{ item.metadata.barcode }}
</a>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,11 @@ export class HoldingsComponent implements OnInit {
ngOnInit() {
this.canAdd = (!('harvested' in this.document.metadata));
const orgPid = this._userService.user.currentOrganisation;
this.query = `document.pid:${this.document.metadata.pid} AND organisation.pid:${orgPid}`;
this.query = `document.pid:${this.document.metadata.pid} AND organisation.pid:${orgPid}
AND (
(holdings_type:standard AND items_count:[1 TO *])
OR (holdings_type:serial AND items_count:[0 TO *])
)`;
const holdingsRecords = this._holdingsQuery(1, this.query);
const holdingsCount = this._holdingsCountQuery(this.query);
const permissionsRef = this._recordPermissionService.getPermission('holdings');
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import { Component, Input, OnInit } from '@angular/core';
import { TranslateService } from '@ngx-translate/core';
import { RecordService, RecordUiService } from '@rero/ng-core';
import { Record } from '@rero/ng-core/lib/record/record';
import { IssueItemStatus } from '@rero/shared';
import { IssueItemStatus, UserService } from '@rero/shared';
import { ToastrService } from 'ngx-toastr';
import { HoldingsService, PredictionIssue } from 'projects/admin/src/app/service/holdings.service';
import { OperationLogsService } from 'projects/admin/src/app/service/operation-logs.service';
Expand Down Expand Up @@ -71,6 +71,7 @@ export class SerialHoldingDetailViewComponent implements OnInit {
* @param _translateService: TranslateService,
* @param _toastrService: ToastrService
* @param _operationLogsService: OperationLogsService
* @param _userService: UserService
*/
constructor(
private _holdingService: HoldingsService,
Expand All @@ -79,7 +80,8 @@ export class SerialHoldingDetailViewComponent implements OnInit {
private _recordPermissionService: RecordPermissionService,
private _translateService: TranslateService,
private _toastrService: ToastrService,
private _operationLogsService: OperationLogsService
private _operationLogsService: OperationLogsService,
private _userService: UserService
) {}

/**
Expand Down Expand Up @@ -126,13 +128,15 @@ export class SerialHoldingDetailViewComponent implements OnInit {
* @return Return the item with linked permissions
*/
private _loadItem(item: any) {
this._recordPermissionService.getPermission('items', item.id).subscribe(
(permissions) => item.permissions = permissions
);
const recordPermission = this._recordPermissionService;
recordPermission.getPermission('items', item.id)
.subscribe((permission) => {
item.permissions = recordPermission
.isMembership(this._userService.user, item.metadata.library.pid, permission);
});
return item;
}


/**
* Action to perform when user click on a showMore link
* @param type - string: the type of item to load more
Expand Down
5 changes: 2 additions & 3 deletions projects/admin/src/app/routes/holdings-route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import { FormlyFieldConfig } from '@ngx-formly/core';
import { DetailComponent, RecordService, RouteInterface } from '@rero/ng-core';
import { Record, JSONSchema7 } from '@rero/ng-core';
import { DetailComponent, JSONSchema7, Record, RecordService, RouteInterface } from '@rero/ng-core';
import { map } from 'rxjs/operators';
import { CanUpdateGuard } from '../guard/can-update.guard';
import { HoldingEditorComponent } from '../record/custom-editor/holding-editor/holding-editor.component';
Expand Down Expand Up @@ -57,7 +56,7 @@ export class HoldingsRoute extends BaseRoute implements RouteInterface {
}
},
detailComponent: HoldingDetailViewComponent,
permissions: (record: any) => this._routeToolService.permissions(record, this.recordType),
permissions: (record: any) => this._routeToolService.permissions(record, this.recordType, true),
preCreateRecord: (data: any) => {
data.document = {
$ref: this._routeToolService.apiService.getRefEndpoint(
Expand Down
26 changes: 2 additions & 24 deletions projects/admin/src/app/routes/items-route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import { FormlyFieldConfig } from '@ngx-formly/core';
import { DetailComponent, EditorComponent, RecordSearchPageComponent, RecordService, RouteInterface } from '@rero/ng-core';
import { Record, JSONSchema7 } from '@rero/ng-core';
import { DetailComponent, EditorComponent, JSONSchema7, Record, RecordSearchPageComponent, RecordService, RouteInterface } from '@rero/ng-core';
import { of } from 'rxjs';
import { map } from 'rxjs/operators';
import { ItemType } from '../classes/items';
Expand Down Expand Up @@ -48,10 +47,6 @@ export class ItemsRoute extends BaseRoute implements RouteInterface {
{ path: 'new', component: EditorComponent }
],
data: {
adminMode: () => of({
can: false,
message: ''
}),
types: [
{
key: this.name,
Expand All @@ -69,7 +64,7 @@ export class ItemsRoute extends BaseRoute implements RouteInterface {
searchFilters: [
this.expertSearchFilter()
],
permissions: (record: any) => this._routeToolService.permissions(record, this.recordType),
permissions: (record: any) => this._routeToolService.permissions(record, this.recordType, true),
preprocessRecordEditor: (record: any) => {
// If we found an `holding` parameter into the query string then we need to pre-populated
// the form with the corresponding holding metadata (see '_populateItemFieldFromHolding' function
Expand Down Expand Up @@ -170,23 +165,6 @@ export class ItemsRoute extends BaseRoute implements RouteInterface {
;
}

/**
* Check if the item is in the same organisation of connected user.
* @param record - Object
* @return Observable
*/
private canReadItem(record: any) {
const organisationPid = this._routeToolService.userService.user
.currentOrganisation;
if ('organisation' in record.metadata) {
return of({
can: organisationPid === record.metadata.organisation.pid,
message: ''
});
}
return of({ can: false, message: '' });
}

/**
* Populate select menu with locations of current user library
* @param field - FormlyFieldConfig
Expand Down
32 changes: 24 additions & 8 deletions projects/admin/src/app/routes/route-tool.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import { TranslateService } from '@ngx-translate/core';
import { ActionStatus, ApiService, RecordService } from '@rero/ng-core';
import { UserService } from '@rero/shared';
import { Observable, of, Subscriber } from 'rxjs';
import { map } from 'rxjs/operators';
import { RecordPermission, RecordPermissionService } from '../service/record-permission.service';

@Injectable({
Expand Down Expand Up @@ -224,26 +225,41 @@ export class RouteToolService {
* Check all permissions of the record
* @param record - Object: the resource object to check
* @param recordType - String: the record type
* @param checkLibrary - boolean: Check library
* @return Observable providing object contains:
* - canRead permission
* - canUpdate permission
* - canDelete permission
*/
permissions(record: any, recordType: string): Observable<any> {
permissions(record: any, recordType: string, checkLibrary = false): Observable<any> {
return new Observable((observer: Subscriber<any>): void => {
this.recordPermissionService
.getPermission(recordType, record.metadata.pid)
.subscribe((permission: RecordPermission) => {
observer.next({
const permissionService = this.recordPermissionService;
permissionService.getPermission(recordType, record.metadata.pid)
.pipe(map((permission: RecordPermission) => {
const user = this.userService.user;
if (checkLibrary) {
// Check if i have the field library in metadata
if ('library' in record.metadata) {
// Extract library pid
const libraryPid = ('$ref' in record.metadata.library)
? record.metadata.library.$ref.split('/').pop()
: record.metadata.library.pid;
permission = permissionService.isMembership(user, libraryPid, permission);
}
}
return {
canRead: { can: permission.read.can, message: '' },
canUpdate: { can: permission.update.can, message: '' },
canDelete: {
can: permission.delete.can,
message: (permission.delete.can)
? ''
: this.recordPermissionService.generateDeleteMessage(permission.delete.reasons)
},
});
: permissionService.generateDeleteMessage(permission.delete.reasons)
}
};
}))
.subscribe((permission: any) => {
observer.next(permission);
});
});
}
Expand Down
26 changes: 25 additions & 1 deletion projects/admin/src/app/service/record-permission.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import { I18nPluralPipe, NgLocaleLocalization } from '@angular/common';
import { HttpClient, HttpHeaders } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { TranslateService } from '@ngx-translate/core';
import { UserService } from '@rero/shared/public-api';
import { Observable } from 'rxjs';

@Injectable({
Expand Down Expand Up @@ -134,6 +135,28 @@ export class RecordPermissionService {
return this.generateTooltipMessage(reasons, 'delete');
}

/**
* Is membership
* @param user - any
* @param libraryPid - string
* @param permission - any
* @returns permissions of current record
*/
isMembership(user: any, libraryPid: string, permission: any): any {
if (user.isSystemLibrarian && user.currentLibrary !== libraryPid) {
permission.update.can = false;
permission.delete = {
can: false,
reasons: {
others: {
record_not_in_current_library: ''
}
}
};
}
return permission;
}

/**
* Plurial links messages
* @return array
Expand Down Expand Up @@ -212,7 +235,8 @@ export class RecordPermissionService {
is_default: this._translateService.instant('The default record cannot be deleted'),
has_settings: this._translateService.instant('The record contains settings'),
harvested: this._translateService.instant('The record has been harvested'),
regular_issue_cannot_be_deleted: this._translateService.instant('A regular issue cannot be deleted')
regular_issue_cannot_be_deleted: this._translateService.instant('A regular issue cannot be deleted'),
record_not_in_current_library: this._translateService.instant('The record does not belong to the current library.')
};
}
}
Expand Down
7 changes: 6 additions & 1 deletion projects/public-search/src/app/api/holdings-api.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,13 @@ export class HoldingsApiService extends BaseApi {
*/
getHoldingsByDocumentPidAndViewcode(
documentPid: string, viewcode: string, page: number, itemsPerPage: number = 5): Observable<QueryResponse> {
const query = `document.pid:${documentPid}
AND (
(holdings_type:standard AND public_items_count:[1 TO *])
OR (holdings_type:serial AND public_items_count:[0 TO *])
)`;
return this._recordService
.getRecords('holdings', `document.pid:${documentPid}`, page, itemsPerPage, undefined, { view: viewcode }, BaseApi.reroJsonheaders)
.getRecords('holdings', query, page, itemsPerPage, undefined, { view: viewcode }, BaseApi.reroJsonheaders)
.pipe(map((response: Record) => response.hits));
}
}

0 comments on commit 1a1a19d

Please sign in to comment.