Skip to content

Commit

Permalink
Merged dspace-cris-2023_02_x into task/dspace-cris-2023_02_x/DSC-1988
Browse files Browse the repository at this point in the history
  • Loading branch information
atarix83 committed Nov 28, 2024
2 parents ad9d674 + 29a111a commit 8bcddd2
Show file tree
Hide file tree
Showing 93 changed files with 1,524 additions and 222 deletions.
4 changes: 0 additions & 4 deletions config/config.example.yml
Original file line number Diff line number Diff line change
Expand Up @@ -400,10 +400,6 @@ themes:
attributes:
rel: manifest
href: assets/dspace/images/favicons/manifest.webmanifest
- tagName: link
attributes:
rel: stylesheet
href: "https://fonts.googleapis.com/icon?family=Material+Icons"

# The default bundles that should always be displayed as suggestions when you upload a new bundle
bundle:
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "dspace-angular",
"version": "2023.02.06-SNAPHOT",
"version": "2023.02.07-SNAPSHOT",
"scripts": {
"ng": "ng",
"config:watch": "nodemon",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ <h4 class="mt-4 mb-4">{{ object.name }} (<em>{{object.type}}</em>)</h4>

</ng-container>

<h4 class="mt-4 mb-4" *ngIf="(auditsRD$ | async).statusCode === 404">{{'audit.object.overview.disabled.message' | translate}}</h4>
<h4 class="mt-4 mb-4" *ngIf="(auditsRD$ | async)?.statusCode === 404">{{'audit.object.overview.disabled.message' | translate}}</h4>

</ng-container>

Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Component, OnInit } from '@angular/core';

import { combineLatest, Observable } from 'rxjs';
import { mergeMap } from 'rxjs/operators';
import { combineLatest, Observable, of, switchMap } from 'rxjs';
import { map, mergeMap, take } from 'rxjs/operators';

import { RemoteData } from '../../core/data/remote-data';
import { PaginationComponentOptions } from '../../shared/pagination/pagination-component-options.model';
Expand All @@ -18,6 +18,10 @@ import { AuthService } from '../../core/auth/auth.service';
import { PaginatedList } from '../../core/data/paginated-list.model';
import { PaginationService } from '../../core/pagination/pagination.service';
import { redirectOn4xx } from '../../core/shared/authorized.operators';
import { CollectionDataService } from '../../core/data/collection-data.service';
import { Collection } from '../../core/shared/collection.model';
import { Item } from '../../core/shared/item.model';
import { COLLECTION_PAGE_LINKS_TO_FOLLOW } from '../../collection-page/collection-page.resolver';

/**
* Component displaying a list of all audit about a object in a paginated table
Expand All @@ -31,7 +35,7 @@ export class ObjectAuditOverviewComponent implements OnInit {
/**
* The object extracted from the route.
*/
object;
object: Item;

/**
* List of all audits
Expand Down Expand Up @@ -62,14 +66,17 @@ export class ObjectAuditOverviewComponent implements OnInit {
*/
dateFormat = 'yyyy-MM-dd HH:mm:ss';

owningCollection$: Observable<Collection>;

constructor(protected authService: AuthService,
protected route: ActivatedRoute,
protected router: Router,
protected auditService: AuditDataService,
protected itemService: ItemDataService,
protected authorizationService: AuthorizationDataService,
protected paginationService: PaginationService) {
}
protected paginationService: PaginationService,
protected collectionDataService: CollectionDataService
) {}

ngOnInit(): void {
this.route.paramMap.pipe(
Expand All @@ -78,6 +85,15 @@ export class ObjectAuditOverviewComponent implements OnInit {
redirectOn4xx(this.router, this.authService)
).subscribe((rd) => {
this.object = rd.payload;
this.owningCollection$ = this.collectionDataService.findOwningCollectionFor(
this.object,
true,
false,
...COLLECTION_PAGE_LINKS_TO_FOLLOW
).pipe(
getFirstCompletedRemoteData(),
map(data => data?.payload)
);
this.setAudits();
});
}
Expand All @@ -88,17 +104,35 @@ export class ObjectAuditOverviewComponent implements OnInit {
setAudits() {
const config$ = this.paginationService.getFindListOptions(this.pageConfig.id, this.config, this.pageConfig);
const isAdmin$ = this.isCurrentUserAdmin();
this.auditsRD$ = combineLatest([isAdmin$, config$]).pipe(
mergeMap(([isAdmin, config]) => {
const parentCommunity$ = this.owningCollection$.pipe(
switchMap(collection => collection.parentCommunity),
getFirstCompletedRemoteData(),
map(data => data?.payload)
);


this.auditsRD$ = combineLatest([isAdmin$, config$, this.owningCollection$, parentCommunity$]).pipe(
mergeMap(([isAdmin, config, owningCollection, parentCommunity]) => {
if (isAdmin) {
return this.auditService.findByObject(this.object.id, config);
return this.auditService.findByObject(this.object.id, config, owningCollection.id, parentCommunity.id);
}

return of(null);
})
);
}

isCurrentUserAdmin(): Observable<boolean> {
return this.authorizationService.isAuthorized(FeatureID.AdministratorOf, undefined, undefined);
return combineLatest([
this.authorizationService.isAuthorized(FeatureID.IsCollectionAdmin),
this.authorizationService.isAuthorized(FeatureID.IsCommunityAdmin),
this.authorizationService.isAuthorized(FeatureID.AdministratorOf),
]).pipe(
map(([isCollectionAdmin, isCommunityAdmin, isSiteAdmin]) => {
return isCollectionAdmin || isCommunityAdmin || isSiteAdmin;
}),
take(1),
);
}

/**
Expand Down
2 changes: 1 addition & 1 deletion src/app/breadcrumbs/breadcrumbs.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
</ng-template>

<ng-template #activeBreadcrumb let-text="text">
<li class="breadcrumb-item active" aria-current="page"><div class="breadcrumb-item-limiter"><div class="text-truncate">{{text | translate}}</div></div></li>
<li class="breadcrumb-item active" aria-current="page"><div class="breadcrumb-item-limiter"><span class="text-truncate" [innerHTML]="text | translate"></span></div></li>
</ng-template>
</ng-container>

8 changes: 4 additions & 4 deletions src/app/collection-page/collection-page.component.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,14 @@ import { RouterStub } from '../shared/testing/router.stub';
import { environment } from 'src/environments/environment.test';
import { createSuccessfulRemoteDataObject$ } from '../shared/remote-data.utils';
import { Collection } from '../core/shared/collection.model';
import { SearchService } from '../core/shared/search/search.service';
import { By } from '@angular/platform-browser';
import { FormsModule } from '@angular/forms';
import { RouterTestingModule } from '@angular/router/testing';
import { TranslateModule } from '@ngx-translate/core';
import { VarDirective } from '../shared/utils/var.directive';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { Bitstream } from '../core/shared/bitstream.model';
import { SearchManager } from '../core/browse/search-manager';

describe('CollectionPageComponent', () => {
let component: CollectionPageComponent;
Expand All @@ -33,7 +33,7 @@ describe('CollectionPageComponent', () => {
let paginationServiceSpy: jasmine.SpyObj<PaginationService>;
let authorizationDataServiceSpy: jasmine.SpyObj<AuthorizationDataService>;
let dsoNameServiceSpy: jasmine.SpyObj<DSONameService>;
let searchServiceSpy: jasmine.SpyObj<SearchService>;
let searchServiceSpy: jasmine.SpyObj<SearchManager>;
let aroute = new ActivatedRouteStub();
let router = new RouterStub();

Expand All @@ -44,7 +44,7 @@ describe('CollectionPageComponent', () => {
paginationServiceSpy = jasmine.createSpyObj('PaginationService', ['getCurrentPagination', 'getCurrentSort', 'clearPagination']);
authorizationDataServiceSpy = jasmine.createSpyObj('AuthorizationDataService', ['isAuthorized']);
collectionDataServiceSpy = jasmine.createSpyObj('CollectionDataService', ['findById', 'getAuthorizedCollection']);
searchServiceSpy = jasmine.createSpyObj('SearchService', ['search']);
searchServiceSpy = jasmine.createSpyObj('SearchManager', ['search']);
dsoNameServiceSpy = jasmine.createSpyObj('DSONameService', ['getName']);

await TestBed.configureTestingModule({
Expand All @@ -58,7 +58,7 @@ describe('CollectionPageComponent', () => {
{ provide: PaginationService, useValue: paginationServiceSpy },
{ provide: AuthorizationDataService, useValue: authorizationDataServiceSpy },
{ provide: DSONameService, useValue: dsoNameServiceSpy },
{ provide: SearchService, useValue: searchServiceSpy },
{ provide: SearchManager, useValue: searchServiceSpy },
{ provide: APP_CONFIG, useValue: environment },
{ provide: PLATFORM_ID, useValue: 'browser' },
]
Expand Down
10 changes: 4 additions & 6 deletions src/app/collection-page/collection-page.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,7 @@ import { ActivatedRoute, Router } from '@angular/router';
import { BehaviorSubject, combineLatest as observableCombineLatest, Observable, Subject } from 'rxjs';
import { filter, map, mergeMap, startWith, switchMap, take } from 'rxjs/operators';
import { PaginatedSearchOptions } from '../shared/search/models/paginated-search-options.model';
import { SearchService } from '../core/shared/search/search.service';
import { SortDirection, SortOptions } from '../core/cache/models/sort-options.model';
import { CollectionDataService } from '../core/data/collection-data.service';
import { PaginatedList } from '../core/data/paginated-list.model';
import { RemoteData } from '../core/data/remote-data';
import { Bitstream } from '../core/shared/bitstream.model';
Expand All @@ -30,6 +28,7 @@ import { redirectOn4xx } from '../core/shared/authorized.operators';
import { BROWSE_LINKS_TO_FOLLOW } from '../core/browse/browse.service';
import { DSONameService } from '../core/breadcrumbs/dso-name.service';
import { APP_CONFIG, AppConfig } from '../../../src/config/app-config.interface';
import { SearchManager } from '../core/browse/search-manager';

@Component({
selector: 'ds-collection-page',
Expand Down Expand Up @@ -64,8 +63,7 @@ export class CollectionPageComponent implements OnInit {

constructor(
@Inject(PLATFORM_ID) private platformId: Object,
private collectionDataService: CollectionDataService,
private searchService: SearchService,
private searchManager: SearchManager,
private route: ActivatedRoute,
private router: Router,
private authService: AuthService,
Expand Down Expand Up @@ -113,13 +111,13 @@ export class CollectionPageComponent implements OnInit {
getFirstSucceededRemoteData(),
map((rd) => rd.payload.id),
switchMap((id: string) => {
return this.searchService.search<Item>(
return this.searchManager.search<Item>(
new PaginatedSearchOptions({
scope: id,
pagination: currentPagination,
sort: currentSort,
dsoTypes: [DSpaceObjectType.ITEM],
forcedEmbeddedKeys: ['metrics']
forcedEmbeddedKeys: ['metrics'],
}), null, true, true, ...BROWSE_LINKS_TO_FOLLOW)
.pipe(toDSpaceObjectListRD()) as Observable<RemoteData<PaginatedList<Item>>>;
}),
Expand Down
16 changes: 14 additions & 2 deletions src/app/core/audit/audit-data.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import { SearchDataImpl } from '../data/base/search-data';
import { DeleteDataImpl } from '../data/base/delete-data';
import { FindAllData, FindAllDataImpl } from '../data/base/find-all-data';
import { DSONameService } from '../breadcrumbs/dso-name.service';
import { hasValue } from '../../shared/empty.util';

export const AUDIT_PERSON_NOT_AVAILABLE = 'n/a';

Expand Down Expand Up @@ -60,12 +61,23 @@ export class AuditDataService extends IdentifiableDataService<Audit>{
*
* @param objectId The objectId id
* @param options The [[FindListOptions]] object
* @param collUuid The Uuid of the collection
* @param commUuid The Uuid of the community
* @return Observable<RemoteData<PaginatedList<Audit>>>
*/
findByObject(objectId: string, options: FindListOptions = {}): Observable<RemoteData<PaginatedList<Audit>>> {
findByObject(objectId: string, options: FindListOptions = {}, collUuid?: string, commUuid?: string): Observable<RemoteData<PaginatedList<Audit>>> {
const searchMethod = AUDIT_FIND_BY_OBJECT_SEARCH_METHOD;
const searchParams = [new RequestParam('object', objectId)];

if (hasValue(commUuid)) {
searchParams.push(new RequestParam('commUuid', commUuid));
}

if (hasValue(collUuid)) {
searchParams.push(new RequestParam('collUuid', collUuid));
}
const optionsWithObject = Object.assign(new FindListOptions(), options, {
searchParams: [new RequestParam('object', objectId)]
searchParams
});
return this.searchData.searchBy(searchMethod, optionsWithObject, true, true, followLink('eperson'));
}
Expand Down
4 changes: 3 additions & 1 deletion src/app/core/browse/browse-entry-search-options.model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ export class BrowseEntrySearchOptions {
public sort?: SortOptions,
public startsWith?: string,
public scope?: string,
public fetchThumbnail?: boolean) {
public fetchThumbnail?: boolean,
public projection?: string,
) {
}
}
3 changes: 3 additions & 0 deletions src/app/core/browse/browse.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,9 @@ export class BrowseService {
if (isNotEmpty(filterAuthority)) {
args.push(`filterAuthority=${encodeURIComponent(filterAuthority)}`);
}
if (isNotEmpty(options.projection)) {
args.push(`projection=${options.projection}`);
}
if (isNotEmpty(args)) {
href = new URLCombiner(href, `?${args.join('&')}`).toString();
}
Expand Down
6 changes: 4 additions & 2 deletions src/app/core/browse/search-manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,8 @@ export class SearchManager {
* @returns {Observable<RemoteData<PaginatedList<Item>>>}
*/
getBrowseItemsFor(filterValue: string, filterAuthority: string, options: BrowseEntrySearchOptions, ...linksToFollow: FollowLinkConfig<any>[]): Observable<RemoteData<PaginatedList<Item>>> {
return this.browseService.getBrowseItemsFor(filterValue, filterAuthority, options, ...linksToFollow)
const browseOptions = Object.assign({}, options, { projection: options.projection ?? 'preventMetadataSecurity' });
return this.browseService.getBrowseItemsFor(filterValue, filterAuthority, browseOptions, ...linksToFollow)
.pipe(this.completeWithExtraData());
}

Expand All @@ -66,7 +67,8 @@ export class SearchManager {
useCachedVersionIfAvailable = true,
reRequestOnStale = true,
...linksToFollow: FollowLinkConfig<T>[]): Observable<RemoteData<SearchObjects<T>>> {
return this.searchService.search(searchOptions, responseMsToLive, useCachedVersionIfAvailable, reRequestOnStale, ...linksToFollow)
const optionsWithDefaultProjection = Object.assign(new PaginatedSearchOptions({}), searchOptions, { projection: searchOptions.projection ?? 'preventMetadataSecurity' });
return this.searchService.search(optionsWithDefaultProjection, responseMsToLive, useCachedVersionIfAvailable, reRequestOnStale, ...linksToFollow)
.pipe(this.completeSearchObjectsWithExtraData());
}

Expand Down
12 changes: 6 additions & 6 deletions src/app/core/browse/search.manager.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -130,13 +130,13 @@ describe('SearchManager', () => {

const filterValue = 'filterValue';
const filterAuthority = null;
const options: BrowseEntrySearchOptions = { options: null} as any;
const browseOptions: BrowseEntrySearchOptions = Object.assign({}, { projection: 'preventMetadataSecurity' }) as BrowseEntrySearchOptions;
const followLink: FollowLinkConfig<any> = {} as any;

scheduler.schedule(() => service.getBrowseItemsFor(filterValue, filterAuthority, options, followLink).subscribe());
scheduler.schedule(() => service.getBrowseItemsFor(filterValue, filterAuthority, browseOptions, followLink).subscribe());
scheduler.flush();

expect(mockBrowseService.getBrowseItemsFor).toHaveBeenCalledWith(filterValue, null, options, followLink);
expect(mockBrowseService.getBrowseItemsFor).toHaveBeenCalledWith(filterValue, null, browseOptions, followLink);
expect(mockItemService.findAllById).toHaveBeenCalledWith([validAuthority, validAuthority2]);

});
Expand All @@ -145,13 +145,13 @@ describe('SearchManager', () => {

const filterValue = 'filterValue';
const filterAuthority = 'filterAuthority';
const options: BrowseEntrySearchOptions = { options: null} as any;
const browseOptions: BrowseEntrySearchOptions = Object.assign({}, { projection: 'preventMetadataSecurity' }) as BrowseEntrySearchOptions;
const followLink: FollowLinkConfig<any> = {} as any;

scheduler.schedule(() => service.getBrowseItemsFor(filterValue, filterAuthority, options, followLink).subscribe());
scheduler.schedule(() => service.getBrowseItemsFor(filterValue, filterAuthority, browseOptions, followLink).subscribe());
scheduler.flush();

expect(mockBrowseService.getBrowseItemsFor).toHaveBeenCalledWith(filterValue, filterAuthority, options, followLink);
expect(mockBrowseService.getBrowseItemsFor).toHaveBeenCalledWith(filterValue, filterAuthority, browseOptions, followLink);
expect(mockItemService.findAllById).toHaveBeenCalledWith([validAuthority, validAuthority2]);

});
Expand Down
7 changes: 5 additions & 2 deletions src/app/core/data/collection-data.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -321,9 +321,12 @@ export class CollectionDataService extends ComColDataService<Collection> {
/**
* Returns {@link RemoteData} of {@link Collection} that is the owning collection of the given item
* @param item Item we want the owning collection of
* @param useCachedVersionIfAvailable
* @param reRequestOnStale
* @param linksToFollow
*/
findOwningCollectionFor(item: Item): Observable<RemoteData<Collection>> {
return this.findByHref(item._links.owningCollection.href);
findOwningCollectionFor(item: Item, useCachedVersionIfAvailable = true, reRequestOnStale = true, ...linksToFollow: FollowLinkConfig<Collection>[]): Observable<RemoteData<Collection>> {
return this.findByHref(item._links.owningCollection.href, useCachedVersionIfAvailable, reRequestOnStale, ...linksToFollow);
}

/**
Expand Down
18 changes: 14 additions & 4 deletions src/app/core/data/site-data.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,17 +46,27 @@ export class SiteDataService extends IdentifiableDataService<Site> implements Fi

/**
* Retrieve the Site Object
*
* @param options Find list options object
* @param useCachedVersionIfAvailable If this is true, the request will only be sent if there's
* no valid cached version. Defaults to true
* @param reRequestOnStale Whether or not the request should automatically be re-
* requested after the response becomes stale
* @param linksToFollow List of {@link FollowLinkConfig} that indicate which
* {@link HALLink}s should be automatically resolved
* @return {Observable<RemoteData<PaginatedList<T>>>}
* Return an observable that emits object list
*/
find(): Observable<Site> {
find(options?: FindListOptions, useCachedVersionIfAvailable?: boolean, reRequestOnStale?: boolean, ...linksToFollow: FollowLinkConfig<Site>[]): Observable<Site> {
const searchParams: RequestParam[] = [new RequestParam('projection', 'allLanguages')];
const options = Object.assign(new FindListOptions(), { searchParams });
return this.findAll(options).pipe(
const findOptions = Object.assign(new FindListOptions(), options, { searchParams });
return this.findAll(findOptions, useCachedVersionIfAvailable, reRequestOnStale, ...linksToFollow).pipe(
getFirstCompletedRemoteData(),
switchMap((remoteData: RemoteData<PaginatedList<Site>>) => {
if (remoteData.hasSucceeded) {
return of(remoteData.payload.page[0]);
} else {
return this.findAll().pipe(
return this.findAll(options, useCachedVersionIfAvailable, reRequestOnStale, ...linksToFollow).pipe(
getFirstCompletedRemoteData(),
map((rd: RemoteData<PaginatedList<Site>>) => rd.hasSucceeded ? rd.payload.page[0] : null)
);
Expand Down
Loading

0 comments on commit 8bcddd2

Please sign in to comment.