mirror of
https://github.com/DSpace/dspace-angular.git
synced 2025-10-10 03:23:07 +00:00
Use the item's HALLink to get the access status
This commit is contained in:
@@ -164,6 +164,7 @@ import { CoreState } from './core-state.model';
|
|||||||
import { GroupDataService } from './eperson/group-data.service';
|
import { GroupDataService } from './eperson/group-data.service';
|
||||||
import { SubmissionAccessesModel } from './config/models/config-submission-accesses.model';
|
import { SubmissionAccessesModel } from './config/models/config-submission-accesses.model';
|
||||||
import { AccessStatusObject } from '../shared/object-list/access-status-badge/access-status.model';
|
import { AccessStatusObject } from '../shared/object-list/access-status-badge/access-status.model';
|
||||||
|
import { AccessStatusDataService } from './data/access-status-data.service';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* When not in production, endpoint responses can be mocked for testing purposes
|
* When not in production, endpoint responses can be mocked for testing purposes
|
||||||
@@ -221,6 +222,7 @@ const PROVIDERS = [
|
|||||||
MyDSpaceResponseParsingService,
|
MyDSpaceResponseParsingService,
|
||||||
ServerResponseService,
|
ServerResponseService,
|
||||||
BrowseService,
|
BrowseService,
|
||||||
|
AccessStatusDataService,
|
||||||
SubmissionCcLicenseDataService,
|
SubmissionCcLicenseDataService,
|
||||||
SubmissionCcLicenseUrlDataService,
|
SubmissionCcLicenseUrlDataService,
|
||||||
SubmissionFormsConfigService,
|
SubmissionFormsConfigService,
|
||||||
|
45
src/app/core/data/access-status-data.service.ts
Normal file
45
src/app/core/data/access-status-data.service.ts
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
import { HttpClient } from '@angular/common/http';
|
||||||
|
import { Injectable } from '@angular/core';
|
||||||
|
import { Store } from '@ngrx/store';
|
||||||
|
import { NotificationsService } from '../../shared/notifications/notifications.service';
|
||||||
|
import { dataService } from '../cache/builders/build-decorators';
|
||||||
|
import { RemoteDataBuildService } from '../cache/builders/remote-data-build.service';
|
||||||
|
import { ObjectCacheService } from '../cache/object-cache.service';
|
||||||
|
import { HALEndpointService } from '../shared/hal-endpoint.service';
|
||||||
|
import { DataService } from './data.service';
|
||||||
|
import { RequestService } from './request.service';
|
||||||
|
import { DefaultChangeAnalyzer } from './default-change-analyzer.service';
|
||||||
|
import { CoreState } from '../core-state.model';
|
||||||
|
import { AccessStatusObject } from 'src/app/shared/object-list/access-status-badge/access-status.model';
|
||||||
|
import { ACCESS_STATUS } from 'src/app/shared/object-list/access-status-badge/access-status.resource-type';
|
||||||
|
import { Observable } from 'rxjs';
|
||||||
|
import { RemoteData } from './remote-data';
|
||||||
|
import { Item } from '../shared/item.model';
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
@dataService(ACCESS_STATUS)
|
||||||
|
export class AccessStatusDataService extends DataService<AccessStatusObject> {
|
||||||
|
|
||||||
|
protected linkPath = 'accessStatus';
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
protected comparator: DefaultChangeAnalyzer<AccessStatusObject>,
|
||||||
|
protected halService: HALEndpointService,
|
||||||
|
protected http: HttpClient,
|
||||||
|
protected notificationsService: NotificationsService,
|
||||||
|
protected objectCache: ObjectCacheService,
|
||||||
|
protected rdbService: RemoteDataBuildService,
|
||||||
|
protected requestService: RequestService,
|
||||||
|
protected store: Store<CoreState>,
|
||||||
|
) {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns {@link RemoteData} of {@link AccessStatusObject} that is the access status of the given item
|
||||||
|
* @param item Item we want the access status of
|
||||||
|
*/
|
||||||
|
findAccessStatusFor(item: Item): Observable<RemoteData<AccessStatusObject>> {
|
||||||
|
return this.findByHref(item._links.accessStatus.href);
|
||||||
|
}
|
||||||
|
}
|
@@ -36,7 +36,6 @@ import { sendRequest } from '../shared/request.operators';
|
|||||||
import { RestRequest } from './rest-request.model';
|
import { RestRequest } from './rest-request.model';
|
||||||
import { CoreState } from '../core-state.model';
|
import { CoreState } from '../core-state.model';
|
||||||
import { FindListOptions } from './find-list-options.model';
|
import { FindListOptions } from './find-list-options.model';
|
||||||
import { AccessStatusObject } from 'src/app/shared/object-list/access-status-badge/access-status.model';
|
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
@dataService(ITEM)
|
@dataService(ITEM)
|
||||||
@@ -292,33 +291,6 @@ export class ItemDataService extends DataService<Item> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the endpoint for an item's access status
|
|
||||||
* @param itemId
|
|
||||||
*/
|
|
||||||
public getAccessStatusEndpoint(itemId: string): Observable<string> {
|
|
||||||
return this.halService.getEndpoint(this.linkPath).pipe(
|
|
||||||
switchMap((url: string) => this.halService.getEndpoint('accessStatus', `${url}/${itemId}`))
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the the access status
|
|
||||||
* @param itemId
|
|
||||||
*/
|
|
||||||
public getAccessStatus(itemId: string): Observable<RemoteData<AccessStatusObject>> {
|
|
||||||
const hrefObs = this.getAccessStatusEndpoint(itemId);
|
|
||||||
|
|
||||||
hrefObs.pipe(
|
|
||||||
take(1)
|
|
||||||
).subscribe((href) => {
|
|
||||||
const request = new GetRequest(this.requestService.generateRequestId(), href);
|
|
||||||
this.requestService.send(request);
|
|
||||||
});
|
|
||||||
|
|
||||||
return this.rdbService.buildSingle<AccessStatusObject>(hrefObs);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Invalidate the cache of the item
|
* Invalidate the cache of the item
|
||||||
* @param itemUUID
|
* @param itemUUID
|
||||||
|
@@ -21,6 +21,8 @@ import { Version } from './version.model';
|
|||||||
import { VERSION } from './version.resource-type';
|
import { VERSION } from './version.resource-type';
|
||||||
import { BITSTREAM } from './bitstream.resource-type';
|
import { BITSTREAM } from './bitstream.resource-type';
|
||||||
import { Bitstream } from './bitstream.model';
|
import { Bitstream } from './bitstream.model';
|
||||||
|
import { ACCESS_STATUS } from 'src/app/shared/object-list/access-status-badge/access-status.resource-type';
|
||||||
|
import { AccessStatusObject } from 'src/app/shared/object-list/access-status-badge/access-status.model';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class representing a DSpace Item
|
* Class representing a DSpace Item
|
||||||
@@ -72,6 +74,7 @@ export class Item extends DSpaceObject implements ChildHALResource {
|
|||||||
templateItemOf: HALLink;
|
templateItemOf: HALLink;
|
||||||
version: HALLink;
|
version: HALLink;
|
||||||
thumbnail: HALLink;
|
thumbnail: HALLink;
|
||||||
|
accessStatus: HALLink;
|
||||||
self: HALLink;
|
self: HALLink;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -110,6 +113,13 @@ export class Item extends DSpaceObject implements ChildHALResource {
|
|||||||
@link(BITSTREAM, false, 'thumbnail')
|
@link(BITSTREAM, false, 'thumbnail')
|
||||||
thumbnail?: Observable<RemoteData<Bitstream>>;
|
thumbnail?: Observable<RemoteData<Bitstream>>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The access status for this Item
|
||||||
|
* Will be undefined unless the access status {@link HALLink} has been resolved.
|
||||||
|
*/
|
||||||
|
@link(ACCESS_STATUS)
|
||||||
|
accessStatus?: Observable<RemoteData<AccessStatusObject>>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Method that returns as which type of object this object should be rendered
|
* Method that returns as which type of object this object should be rendered
|
||||||
*/
|
*/
|
||||||
|
@@ -18,7 +18,7 @@
|
|||||||
</span>
|
</span>
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<ds-type-badge *ngIf="showLabel" [object]="dso"></ds-type-badge>
|
<ds-type-badge *ngIf="showLabel" [object]="dso"></ds-type-badge>
|
||||||
<ds-access-status-badge [uuid]="dso.uuid"></ds-access-status-badge>
|
<ds-access-status-badge [item]="dso"></ds-access-status-badge>
|
||||||
<ds-truncatable-part [id]="dso.id" [minLines]="3" type="h4">
|
<ds-truncatable-part [id]="dso.id" [minLines]="3" type="h4">
|
||||||
<h4 class="card-title" [innerHTML]="firstMetadataValue('dc.title')"></h4>
|
<h4 class="card-title" [innerHTML]="firstMetadataValue('dc.title')"></h4>
|
||||||
</ds-truncatable-part>
|
</ds-truncatable-part>
|
||||||
|
@@ -1,11 +1,11 @@
|
|||||||
import { Component, Input } from '@angular/core';
|
import { Component, Input } from '@angular/core';
|
||||||
import { catchError, map } from 'rxjs/operators';
|
import { catchError, map } from 'rxjs/operators';
|
||||||
import { Observable, of as observableOf } from 'rxjs';
|
import { Observable, of as observableOf } from 'rxjs';
|
||||||
import { getFirstCompletedRemoteData } from 'src/app/core/shared/operators';
|
|
||||||
import { ItemDataService } from 'src/app/core/data/item-data.service';
|
|
||||||
import { AccessStatusObject } from './access-status.model';
|
import { AccessStatusObject } from './access-status.model';
|
||||||
import { hasValue } from '../../empty.util';
|
import { hasValue } from '../../empty.util';
|
||||||
import { environment } from 'src/environments/environment';
|
import { environment } from 'src/environments/environment';
|
||||||
|
import { Item } from 'src/app/core/shared/item.model';
|
||||||
|
import { AccessStatusDataService } from 'src/app/core/data/access-status-data.service';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'ds-access-status-badge',
|
selector: 'ds-access-status-badge',
|
||||||
@@ -16,7 +16,7 @@ import { environment } from 'src/environments/environment';
|
|||||||
*/
|
*/
|
||||||
export class AccessStatusBadgeComponent {
|
export class AccessStatusBadgeComponent {
|
||||||
|
|
||||||
@Input() uuid: string;
|
@Input() item: Item;
|
||||||
accessStatus$: Observable<string>;
|
accessStatus$: Observable<string>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -27,16 +27,21 @@ export class AccessStatusBadgeComponent {
|
|||||||
/**
|
/**
|
||||||
* Initialize instance variables
|
* Initialize instance variables
|
||||||
*
|
*
|
||||||
* @param {ItemDataService} itemDataService
|
* @param {AccessStatusDataService} accessStatusDataService
|
||||||
*/
|
*/
|
||||||
constructor(private itemDataService: ItemDataService) { }
|
constructor(private accessStatusDataService: AccessStatusDataService) { }
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
this.showAccessStatus = environment.item.showAccessStatuses;
|
this.showAccessStatus = environment.item.showAccessStatuses;
|
||||||
this.accessStatus$ = this.itemDataService
|
if (!this.showAccessStatus || this.item == null) {
|
||||||
.getAccessStatus(this.uuid)
|
// Do not show the badge if the feature is inactive or if the item is null.
|
||||||
.pipe(
|
return;
|
||||||
getFirstCompletedRemoteData(),
|
}
|
||||||
|
if (this.item.accessStatus == null) {
|
||||||
|
// In case the access status has not been loaded, do it individually.
|
||||||
|
this.item.accessStatus = this.accessStatusDataService.findAccessStatusFor(this.item);
|
||||||
|
}
|
||||||
|
this.accessStatus$ = this.item.accessStatus.pipe(
|
||||||
map((accessStatusRD) => {
|
map((accessStatusRD) => {
|
||||||
if (accessStatusRD.statusCode !== 401 && hasValue(accessStatusRD.payload)) {
|
if (accessStatusRD.statusCode !== 401 && hasValue(accessStatusRD.payload)) {
|
||||||
return accessStatusRD.payload;
|
return accessStatusRD.payload;
|
||||||
|
@@ -4,7 +4,7 @@
|
|||||||
</ng-container>
|
</ng-container>
|
||||||
<div class="d-flex">
|
<div class="d-flex">
|
||||||
<ds-type-badge [object]="item"></ds-type-badge>
|
<ds-type-badge [object]="item"></ds-type-badge>
|
||||||
<ds-access-status-badge [uuid]="item.uuid" class="pl-1"></ds-access-status-badge>
|
<ds-access-status-badge [item]="item" class="pl-1"></ds-access-status-badge>
|
||||||
</div>
|
</div>
|
||||||
<ds-truncatable [id]="item.id">
|
<ds-truncatable [id]="item.id">
|
||||||
<h3 [innerHTML]="item.firstMetadataValue('dc.title') || ('mydspace.results.no-title' | translate)" [ngClass]="{'lead': true,'text-muted': !item.firstMetadataValue('dc.title')}"></h3>
|
<h3 [innerHTML]="item.firstMetadataValue('dc.title') || ('mydspace.results.no-title' | translate)" [ngClass]="{'lead': true,'text-muted': !item.firstMetadataValue('dc.title')}"></h3>
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
<div class="d-flex">
|
<div class="d-flex">
|
||||||
<ds-type-badge *ngIf="showLabel" [object]="dso"></ds-type-badge>
|
<ds-type-badge *ngIf="showLabel" [object]="dso"></ds-type-badge>
|
||||||
<ds-access-status-badge [uuid]="dso.uuid" class="pl-1"></ds-access-status-badge>
|
<ds-access-status-badge [item]="dso" class="pl-1"></ds-access-status-badge>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<ds-truncatable [id]="dso.id" *ngIf="object !== undefined && object !== null">
|
<ds-truncatable [id]="dso.id" *ngIf="object !== undefined && object !== null">
|
||||||
|
@@ -31,6 +31,7 @@ import { ViewMode } from '../../core/shared/view-mode.model';
|
|||||||
import { SelectionConfig } from './search-results/search-results.component';
|
import { SelectionConfig } from './search-results/search-results.component';
|
||||||
import { ListableObject } from '../object-collection/shared/listable-object.model';
|
import { ListableObject } from '../object-collection/shared/listable-object.model';
|
||||||
import { CollectionElementLinkType } from '../object-collection/collection-element-link.type';
|
import { CollectionElementLinkType } from '../object-collection/collection-element-link.type';
|
||||||
|
import { environment } from 'src/environments/environment';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'ds-search',
|
selector: 'ds-search',
|
||||||
@@ -355,7 +356,8 @@ export class SearchComponent implements OnInit {
|
|||||||
undefined,
|
undefined,
|
||||||
this.useCachedVersionIfAvailable,
|
this.useCachedVersionIfAvailable,
|
||||||
true,
|
true,
|
||||||
followLink<Item>('thumbnail', { isOptional: true })
|
followLink<Item>('thumbnail', { isOptional: true }),
|
||||||
|
followLink<Item>('accessStatus', { isOptional: true, shouldEmbed: environment.item.showAccessStatuses })
|
||||||
).pipe(getFirstCompletedRemoteData())
|
).pipe(getFirstCompletedRemoteData())
|
||||||
.subscribe((results: RemoteData<SearchObjects<DSpaceObject>>) => {
|
.subscribe((results: RemoteData<SearchObjects<DSpaceObject>>) => {
|
||||||
if (results.hasSucceeded && results.payload?.page?.length > 0) {
|
if (results.hasSucceeded && results.payload?.page?.length > 0) {
|
||||||
|
Reference in New Issue
Block a user