1- import { Injectable } from '@angular/core' ;
1+ import { Inject , Injectable } from '@angular/core' ;
22import { Observable , of } from 'rxjs' ;
3- import { map , switchMap } from 'rxjs/operators' ;
3+ import { filter , map , switchMap } from 'rxjs/operators' ;
44import { PaginatedList } from '../data/paginated-list.model' ;
55import { RemoteData } from '../data/remote-data' ;
66import { Item } from '../shared/item.model' ;
@@ -22,6 +22,12 @@ import isArray from 'lodash/isArray';
2222import { WORKSPACEITEM } from '../eperson/models/workspaceitem.resource-type' ;
2323import { WORKFLOWITEM } from '../eperson/models/workflowitem.resource-type' ;
2424import { ITEM } from '../shared/item.resource-type' ;
25+ import { APP_CONFIG , AppConfig } from '../../../config/app-config.interface' ;
26+ import { FeatureID } from '../data/feature-authorization/feature-id' ;
27+ import { SearchOptions } from '../../shared/search/models/search-options.model' ;
28+
29+
30+ import { AuthorizationService } from '../data/feature-authorization/authorization.service' ;
2531
2632/**
2733 * The service aims to manage browse requests and subsequent extra fetch requests.
@@ -33,6 +39,8 @@ export class SearchManager {
3339 protected itemService : ItemDataService ,
3440 protected browseService : BrowseService ,
3541 protected searchService : SearchService ,
42+ protected authorizationService : AuthorizationService ,
43+ @Inject ( APP_CONFIG ) protected appConfig : AppConfig
3644 ) {
3745 }
3846
@@ -69,7 +77,7 @@ export class SearchManager {
6977 ...linksToFollow : FollowLinkConfig < T > [ ] ) : Observable < RemoteData < SearchObjects < T > > > {
7078 const optionsWithDefaultProjection = Object . assign ( new PaginatedSearchOptions ( { } ) , searchOptions , { projection : searchOptions . projection ?? 'preventMetadataSecurity' } ) ;
7179 return this . searchService . search ( optionsWithDefaultProjection , responseMsToLive , useCachedVersionIfAvailable , reRequestOnStale , ...linksToFollow )
72- . pipe ( this . completeSearchObjectsWithExtraData ( ) ) ;
80+ . pipe ( this . completeSearchObjectsWithExtraData ( optionsWithDefaultProjection ) ) ;
7381 }
7482
7583
@@ -84,19 +92,107 @@ export class SearchManager {
8492 } ) ;
8593 }
8694
87- protected completeSearchObjectsWithExtraData < T extends DSpaceObject > ( ) {
95+ protected completeSearchObjectsWithExtraData < T extends DSpaceObject > ( searchOptions : SearchOptions ) {
8896 return switchMap ( ( searchObjectsRD : RemoteData < SearchObjects < T > > ) => {
8997 if ( searchObjectsRD . isSuccess ) {
9098 const items : Item [ ] = searchObjectsRD . payload . page
9199 . map ( ( searchResult ) => isNotEmpty ( searchResult ?. _embedded ?. indexableObject ) ? searchResult . _embedded . indexableObject : searchResult . indexableObject ) as any ;
92- return this . fetchExtraData ( items ) . pipe ( map ( ( ) => {
93- return searchObjectsRD ;
94- } ) ) ;
100+ return this . fetchExtraData ( items ) . pipe (
101+ switchMap ( ( ) => this . fetchConfiguredAuthorizations ( searchObjectsRD , searchOptions . configuration ?? 'default' ) ) ,
102+ map ( ( ) => {
103+ return searchObjectsRD ;
104+ } ) ,
105+ ) ;
95106 }
96107 return of ( searchObjectsRD ) ;
97108 } ) ;
98109 }
99110
111+ /**
112+ * Retrieve configured authorizations related to current discovery configuration
113+ *
114+ * @param searchObjects
115+ * @param configuration
116+ * @protected
117+ */
118+ protected fetchConfiguredAuthorizations < T extends DSpaceObject > ( searchObjects : RemoteData < SearchObjects < T > > , configuration : string ) : Observable < any > {
119+ const objects = searchObjects . payload . page . map ( ( searchResult ) => searchResult . indexableObject ) as any ;
120+ const mappedObjects = this . getConfiguredAuthorizationsMap ( objects , configuration ) ;
121+
122+ if ( [ ...mappedObjects . keys ( ) ] . length === 0 ) {
123+ return of ( searchObjects ) ;
124+ }
125+
126+ const uiidListsMappedToAuthorizations = this . groupItemsUuidsByAuthorizations ( objects , mappedObjects ) ;
127+ [ ...uiidListsMappedToAuthorizations . keys ( ) ] . forEach ( ( features ) => {
128+ const uuidList = uiidListsMappedToAuthorizations . get ( features ) ;
129+ const type = objects . find ( object => object . id === uuidList [ 0 ] ) . uniqueType ;
130+
131+ this . authorizationService . initStateForObjects ( uuidList , type , features ) ;
132+ } ) ;
133+
134+ return this . authorizationService . isLoading ( ) . pipe (
135+ filter ( loading => ! loading ) ,
136+ map ( ( ) => {
137+ return searchObjects ;
138+ } ) ,
139+ ) ;
140+ }
141+
142+ /**
143+ * Group items by authorization ID in a map
144+ *
145+ * @param objects
146+ * @param mappedEntities
147+ * @private
148+ */
149+ private groupItemsUuidsByAuthorizations < T extends DSpaceObject > ( objects : T [ ] , mappedEntities : Map < string , FeatureID [ ] > ) : Map < FeatureID [ ] , string [ ] > {
150+ const mappedUuidListsToFeatures = new Map ( ) ;
151+
152+ objects . forEach ( object => {
153+ const objectType = object . uniqueType ;
154+ const features = mappedEntities . get ( objectType ) ;
155+
156+ if ( hasValue ( features ) && hasValue ( mappedUuidListsToFeatures . get ( features ) ) ) {
157+ mappedUuidListsToFeatures . set ( features , [ ...mappedUuidListsToFeatures . get ( features ) , object . id ] ) ;
158+ } else if ( hasValue ( features ) ) {
159+ mappedUuidListsToFeatures . set ( features , [ object . id ] ) ;
160+ }
161+ } ) ;
162+
163+ return mappedUuidListsToFeatures ;
164+ }
165+
166+ /**
167+ * Map entity types oe unique type to required authorizations so that we can group the items by feature
168+ *
169+ * @param objects
170+ * @param configuration
171+ * @private
172+ */
173+ private getConfiguredAuthorizationsMap < T extends DSpaceObject > ( objects : T [ ] , configuration : string ) : Map < string , FeatureID [ ] > {
174+ const configuredAuthorizationsForDiscovery =
175+ this . appConfig . discoveryAuthorizationFeaturesConfig [ configuration ] ?? this . appConfig . discoveryAuthorizationFeaturesConfig . default ;
176+ const configuredAuthorizationsToType = new Map ( ) ;
177+
178+ if ( ! hasValue ( configuredAuthorizationsForDiscovery ) ) {
179+ return configuredAuthorizationsToType ;
180+ }
181+
182+ const objectUniqueTypes = [ ...new Set ( objects . map ( dso => dso ?. uniqueType ) ) ] ;
183+
184+ objectUniqueTypes . forEach ( ( entity ) => {
185+ const config = configuredAuthorizationsForDiscovery [ entity ] ;
186+
187+ if ( hasValue ( config ) ) {
188+ configuredAuthorizationsToType . set ( entity , config ) ;
189+ }
190+ } ) ;
191+
192+ return configuredAuthorizationsToType ;
193+ }
194+
195+
100196 protected fetchExtraData < T extends DSpaceObject > ( objects : T [ ] ) : Observable < any > {
101197
102198 const items : Item [ ] = objects
0 commit comments