Skip to content

Commit

Permalink
Merge pull request #2759 from 4Science/CST-12109-WITHDRAWN-REINSTATE-…
Browse files Browse the repository at this point in the history
…requests

WITHDRAW / REINSTATE requests for an item
  • Loading branch information
tdonohue authored Feb 27, 2024
2 parents 91a419f + e4b2814 commit 0d63a85
Show file tree
Hide file tree
Showing 67 changed files with 1,528 additions and 199 deletions.
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
import { URLCombiner } from '../../core/url-combiner/url-combiner';
import { getNotificationsModuleRoute } from '../admin-routing-paths';

export const QUALITY_ASSURANCE_EDIT_PATH = 'quality-assurance';
export const PUBLICATION_CLAIMS_PATH = 'publication-claim';

export function getQualityAssuranceRoute(id: string) {
return new URLCombiner(getNotificationsModuleRoute(), QUALITY_ASSURANCE_EDIT_PATH, id).toString();
export function getQualityAssuranceEditRoute() {
return `/${QUALITY_ASSURANCE_EDIT_PATH}`;
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ import { AdminQualityAssuranceTopicsPageResolver } from './admin-quality-assuran
import { AdminQualityAssuranceEventsPageResolver } from './admin-quality-assurance-events-page/admin-quality-assurance-events-page.resolver';
import { AdminQualityAssuranceSourcePageComponent } from './admin-quality-assurance-source-page-component/admin-quality-assurance-source-page.component';
import { AdminQualityAssuranceSourcePageResolver } from './admin-quality-assurance-source-page-component/admin-quality-assurance-source-page-resolver.service';
import {
SiteAdministratorGuard
} from '../../core/data/feature-authorization/feature-authorization-guard/site-administrator.guard';
import { QualityAssuranceBreadcrumbResolver } from '../../core/breadcrumbs/quality-assurance-breadcrumb.resolver';
import { QualityAssuranceBreadcrumbService } from '../../core/breadcrumbs/quality-assurance-breadcrumb.service';
import {
Expand Down Expand Up @@ -55,6 +58,21 @@ import {
},
{
canActivate: [ AuthenticatedGuard ],
path: `${QUALITY_ASSURANCE_EDIT_PATH}/:sourceId/target/:targetId`,
component: AdminQualityAssuranceTopicsPageComponent,
pathMatch: 'full',
resolve: {
breadcrumb: I18nBreadcrumbResolver,
openaireQualityAssuranceTopicsParams: AdminQualityAssuranceTopicsPageResolver
},
data: {
title: 'admin.quality-assurance.page.title',
breadcrumbKey: 'admin.quality-assurance',
showBreadcrumbsFluid: false
}
},
{
canActivate: [ SiteAdministratorGuard ],
path: `${QUALITY_ASSURANCE_EDIT_PATH}`,
component: AdminQualityAssuranceSourcePageComponent,
pathMatch: 'full',
Expand Down
5 changes: 5 additions & 0 deletions src/app/admin/admin-routing-paths.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { URLCombiner } from '../core/url-combiner/url-combiner';
import { getAdminModuleRoute } from '../app-routing-paths';
import { getQualityAssuranceEditRoute } from './admin-notifications/admin-notifications-routing-paths';

export const REGISTRIES_MODULE_PATH = 'registries';
export const NOTIFICATIONS_MODULE_PATH = 'notifications';
Expand All @@ -11,3 +12,7 @@ export function getRegistriesModuleRoute() {
export function getNotificationsModuleRoute() {
return new URLCombiner(getAdminModuleRoute(), NOTIFICATIONS_MODULE_PATH).toString();
}

export function getNotificatioQualityAssuranceRoute() {
return new URLCombiner(`/${NOTIFICATIONS_MODULE_PATH}`, getQualityAssuranceEditRoute()).toString();
}
29 changes: 17 additions & 12 deletions src/app/admin/admin-routing.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,57 +6,62 @@ import { I18nBreadcrumbResolver } from '../core/breadcrumbs/i18n-breadcrumb.reso
import { AdminWorkflowPageComponent } from './admin-workflow-page/admin-workflow-page.component';
import { I18nBreadcrumbsService } from '../core/breadcrumbs/i18n-breadcrumbs.service';
import { AdminCurationTasksComponent } from './admin-curation-tasks/admin-curation-tasks.component';
import { REGISTRIES_MODULE_PATH, NOTIFICATIONS_MODULE_PATH } from './admin-routing-paths';
import { REGISTRIES_MODULE_PATH } from './admin-routing-paths';
import { BatchImportPageComponent } from './admin-import-batch-page/batch-import-page.component';
import {
SiteAdministratorGuard
} from '../core/data/feature-authorization/feature-authorization-guard/site-administrator.guard';

@NgModule({
imports: [
RouterModule.forChild([
{
path: NOTIFICATIONS_MODULE_PATH,
loadChildren: () => import('./admin-notifications/admin-notifications.module')
.then((m) => m.AdminNotificationsModule),
},
{
path: REGISTRIES_MODULE_PATH,
loadChildren: () => import('./admin-registries/admin-registries.module')
.then((m) => m.AdminRegistriesModule),
canActivate: [SiteAdministratorGuard]
},
{
path: 'search',
resolve: { breadcrumb: I18nBreadcrumbResolver },
component: AdminSearchPageComponent,
data: { title: 'admin.search.title', breadcrumbKey: 'admin.search' }
data: { title: 'admin.search.title', breadcrumbKey: 'admin.search' },
canActivate: [SiteAdministratorGuard]
},
{
path: 'workflow',
resolve: { breadcrumb: I18nBreadcrumbResolver },
component: AdminWorkflowPageComponent,
data: { title: 'admin.workflow.title', breadcrumbKey: 'admin.workflow' }
data: { title: 'admin.workflow.title', breadcrumbKey: 'admin.workflow' },
canActivate: [SiteAdministratorGuard]
},
{
path: 'curation-tasks',
resolve: { breadcrumb: I18nBreadcrumbResolver },
component: AdminCurationTasksComponent,
data: { title: 'admin.curation-tasks.title', breadcrumbKey: 'admin.curation-tasks' }
data: { title: 'admin.curation-tasks.title', breadcrumbKey: 'admin.curation-tasks' },
canActivate: [SiteAdministratorGuard]
},
{
path: 'metadata-import',
resolve: { breadcrumb: I18nBreadcrumbResolver },
component: MetadataImportPageComponent,
data: { title: 'admin.metadata-import.title', breadcrumbKey: 'admin.metadata-import' }
data: { title: 'admin.metadata-import.title', breadcrumbKey: 'admin.metadata-import' },
canActivate: [SiteAdministratorGuard]
},
{
path: 'batch-import',
resolve: { breadcrumb: I18nBreadcrumbResolver },
component: BatchImportPageComponent,
data: { title: 'admin.batch-import.title', breadcrumbKey: 'admin.batch-import' }
data: { title: 'admin.batch-import.title', breadcrumbKey: 'admin.batch-import' },
canActivate: [SiteAdministratorGuard]
},
{
path: 'system-wide-alert',
resolve: { breadcrumb: I18nBreadcrumbResolver },
loadChildren: () => import('../system-wide-alert/system-wide-alert.module').then((m) => m.SystemWideAlertModule),
data: {title: 'admin.system-wide-alert.title', breadcrumbKey: 'admin.system-wide-alert'}
data: {title: 'admin.system-wide-alert.title', breadcrumbKey: 'admin.system-wide-alert'},
canActivate: [SiteAdministratorGuard]
},
])
],
Expand Down
7 changes: 7 additions & 0 deletions src/app/app-routing-paths.ts
Original file line number Diff line number Diff line change
Expand Up @@ -132,3 +132,10 @@ export const SUBSCRIPTIONS_MODULE_PATH = 'subscriptions';
export function getSubscriptionsModuleRoute() {
return `/${SUBSCRIPTIONS_MODULE_PATH}`;
}

export const EDIT_ITEM_PATH = 'edit-items';
export function getEditItemPageRoute() {
return `/${EDIT_ITEM_PATH}`;
}
export const CORRECTION_TYPE_PATH = 'corrections';

14 changes: 9 additions & 5 deletions src/app/app-routing.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,6 @@ import { NoPreloading, RouterModule } from '@angular/router';
import { AuthBlockingGuard } from './core/auth/auth-blocking.guard';

import { AuthenticatedGuard } from './core/auth/authenticated.guard';
import {
SiteAdministratorGuard
} from './core/data/feature-authorization/feature-authorization-guard/site-administrator.guard';
import {
ACCESS_CONTROL_MODULE_PATH,
ADMIN_MODULE_PATH,
Expand Down Expand Up @@ -41,6 +38,7 @@ import { ServerCheckGuard } from './core/server-check/server-check.guard';
import { SUGGESTION_MODULE_PATH } from './suggestions-page/suggestions-page-routing-paths';
import { MenuResolver } from './menu.resolver';
import { ThemedPageErrorComponent } from './page-error/themed-page-error.component';
import { NOTIFICATIONS_MODULE_PATH } from './admin/admin-routing-paths';
import { ForgotPasswordCheckGuard } from './core/rest-property/forgot-password-check-guard.guard';

@NgModule({
Expand Down Expand Up @@ -159,7 +157,13 @@ import { ForgotPasswordCheckGuard } from './core/rest-property/forgot-password-c
path: ADMIN_MODULE_PATH,
loadChildren: () => import('./admin/admin.module')
.then((m) => m.AdminModule),
canActivate: [SiteAdministratorGuard, EndUserAgreementCurrentUserGuard]
canActivate: [EndUserAgreementCurrentUserGuard]
},
{
path: NOTIFICATIONS_MODULE_PATH,
loadChildren: () => import('./admin/admin-notifications/admin-notifications.module')
.then((m) => m.AdminNotificationsModule),
canActivate: [AuthenticatedGuard, EndUserAgreementCurrentUserGuard]
},
{
path: 'login',
Expand Down Expand Up @@ -247,7 +251,7 @@ import { ForgotPasswordCheckGuard } from './core/rest-property/forgot-password-c
.then((m) => m.SubscriptionsPageRoutingModule),
canActivate: [AuthenticatedGuard]
},
{ path: '**', pathMatch: 'full', component: ThemedPageNotFoundComponent },
{ path: '**', pathMatch: 'full', component: ThemedPageNotFoundComponent }
]
}
], {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,15 +33,15 @@ export class QualityAssuranceBreadcrumbService implements BreadcrumbsProviderSer
*/
getBreadcrumbs(key: string, url: string): Observable<Breadcrumb[]> {
const sourceId = key.split(':')[0];
const topicId = key.split(':')[1];
const topicId = key.split(':')[2];

if (topicId) {
return this.qualityAssuranceService.getTopic(topicId).pipe(
getFirstCompletedRemoteData(),
map((topic) => {
return [new Breadcrumb(this.translationService.instant(this.QUALITY_ASSURANCE_BREADCRUMB_KEY), url),
new Breadcrumb(sourceId, `${url}${sourceId}`),
new Breadcrumb(topicId, undefined)];
new Breadcrumb(topicId.replace(/[!:]/g, '/'), undefined)];
})
);
} else {
Expand Down
4 changes: 3 additions & 1 deletion src/app/core/core.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,7 @@ import { FlatBrowseDefinition } from './shared/flat-browse-definition.model';
import { ValueListBrowseDefinition } from './shared/value-list-browse-definition.model';
import { NonHierarchicalBrowseDefinition } from './shared/non-hierarchical-browse-definition';
import { BulkAccessConditionOptions } from './config/models/bulk-access-condition-options.model';
import { CorrectionTypeDataService } from './submission/correctiontype-data.service';
import { SuggestionTarget } from './suggestion-notifications/models/suggestion-target.model';
import { SuggestionSource } from './suggestion-notifications/models/suggestion-source.model';

Expand Down Expand Up @@ -309,7 +310,8 @@ const PROVIDERS = [
OrcidAuthService,
OrcidQueueDataService,
OrcidHistoryDataService,
SupervisionOrderDataService
SupervisionOrderDataService,
CorrectionTypeDataService
];

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

import { Observable } from 'rxjs';
import { find, take } from 'rxjs/operators';
import { find, switchMap, take } from 'rxjs/operators';
import { ReplaceOperation } from 'fast-json-patch';

import { HALEndpointService } from '../../../shared/hal-endpoint.service';
Expand All @@ -25,6 +25,11 @@ import { SearchData, SearchDataImpl } from '../../../data/base/search-data';
import { DefaultChangeAnalyzer } from '../../../data/default-change-analyzer.service';
import { hasValue } from '../../../../shared/empty.util';
import { DeleteByIDRequest, PostRequest } from '../../../data/request.models';
import { HttpHeaders, HttpParams } from '@angular/common/http';
import { HttpOptions } from '../../../dspace-rest/dspace-rest.service';
import {
QualityAssuranceEventData
} from '../../../../notifications/qa/project-entry-import-modal/project-entry-import-modal.component';

/**
* The service handling all Quality Assurance topic REST requests.
Expand Down Expand Up @@ -84,6 +89,16 @@ export class QualityAssuranceEventDataService extends IdentifiableDataService<Qu
return this.searchData.searchBy('findByTopic', options, true, true, ...linksToFollow);
}

/**
* Service for retrieving Quality Assurance events by topic and target.
* @param options (Optional) The search options to use when retrieving the events.
* @param linksToFollow (Optional) The links to follow when retrieving the events.
* @returns An observable of the remote data containing the paginated list of Quality Assurance events.
*/
public searchEventsByTopic(options: FindListOptions = {}, ...linksToFollow: FollowLinkConfig<QualityAssuranceEventObject>[]): Observable<RemoteData<PaginatedList<QualityAssuranceEventObject>>> {
return this.searchData.searchBy('findByTopic', options, true, true, ...linksToFollow);
}

/**
* Clear findByTopic requests from cache
*/
Expand Down Expand Up @@ -200,4 +215,38 @@ export class QualityAssuranceEventDataService extends IdentifiableDataService<Qu

return this.rdbService.buildFromRequestUUID<QualityAssuranceEventObject>(requestId);
}

/**
* Perform a post on an endpoint related to correction type
* @param data the data to post
* @returns the RestResponse as an Observable
*/
postData(target: string, correctionType: string, related: string, reason: string): Observable<RemoteData<QualityAssuranceEventObject>> {
const requestId = this.requestService.generateRequestId();
const href$ = this.getBrowseEndpoint();

return href$.pipe(
switchMap((href: string) => {
const options: HttpOptions = Object.create({});
let headers = new HttpHeaders();
headers = headers.append('Content-Type', 'application/json');
options.headers = headers;
let params = new HttpParams();
params = params.append('target', target)
.append('correctionType', correctionType);
options.params = params;
const request = new PostRequest(requestId, href, {'reason': reason} , options);
if (hasValue(this.responseMsToLive)) {
request.responseMsToLive = this.responseMsToLive;
}
this.requestService.send(request);
return this.rdbService.buildFromRequestUUID<QualityAssuranceEventObject>(requestId);
})
);
}

public deleteQAEvent(qaEvent: QualityAssuranceEventData): Observable<RemoteData<NoContent>> {
return this.deleteData.delete(qaEvent.id);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ export interface SourceQualityAssuranceEventMessageObject {
*/
type: string;

reason: string;

/**
* The value suggested by Notifications
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import { PaginatedList } from '../../../data/paginated-list.model';
import { FindListOptions } from '../../../data/find-list-options.model';
import { IdentifiableDataService } from '../../../data/base/identifiable-data.service';
import { FindAllData, FindAllDataImpl } from '../../../data/base/find-all-data';
import { SearchData, SearchDataImpl } from '../../../data/base/search-data';

/**
* The service handling all Quality Assurance source REST requests.
Expand All @@ -25,6 +26,9 @@ import { FindAllData, FindAllDataImpl } from '../../../data/base/find-all-data';
export class QualityAssuranceSourceDataService extends IdentifiableDataService<QualityAssuranceSourceObject> {

private findAllData: FindAllData<QualityAssuranceSourceObject>;
private searchAllData: SearchData<QualityAssuranceSourceObject>;

private searchByTargetMethod = 'byTarget';

/**
* Initialize service variables
Expand All @@ -43,6 +47,7 @@ export class QualityAssuranceSourceDataService extends IdentifiableDataService<Q
) {
super('qualityassurancesources', requestService, rdbService, objectCache, halService);
this.findAllData = new FindAllDataImpl(this.linkPath, requestService, rdbService, objectCache, halService, this.responseMsToLive);
this.searchAllData = new SearchDataImpl(this.linkPath, requestService, rdbService, objectCache, halService, this.responseMsToLive);
}

/**
Expand Down Expand Up @@ -84,4 +89,16 @@ export class QualityAssuranceSourceDataService extends IdentifiableDataService<Q
public getSource(id: string, useCachedVersionIfAvailable = true, reRequestOnStale = true, ...linksToFollow: FollowLinkConfig<QualityAssuranceSourceObject>[]): Observable<RemoteData<QualityAssuranceSourceObject>> {
return this.findById(id, useCachedVersionIfAvailable, reRequestOnStale, ...linksToFollow);
}

/**
* Retrieves a paginated list of QualityAssuranceSourceObject objects that are associated with a given target object.
* @param options The options for the search query.
* @param useCachedVersionIfAvailable Whether to use a cached version of the data if available.
* @param reRequestOnStale Whether to re-request the data if the cached version is stale.
* @param linksToFollow The links to follow to retrieve the data.
* @returns An observable that emits a RemoteData object containing the paginated list of QualityAssuranceSourceObject objects.
*/
public getSourcesByTarget(options: FindListOptions = {}, useCachedVersionIfAvailable = true, reRequestOnStale = true, ...linksToFollow: FollowLinkConfig<QualityAssuranceSourceObject>[]): Observable<RemoteData<PaginatedList<QualityAssuranceSourceObject>>> {
return this.searchAllData.searchBy(this.searchByTargetMethod, options, useCachedVersionIfAvailable, reRequestOnStale, ...linksToFollow);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -83,20 +83,27 @@ describe('QualityAssuranceTopicDataService', () => {

spyOn((service as any).findAllData, 'findAll').and.callThrough();
spyOn((service as any), 'findById').and.callThrough();
spyOn((service as any).searchData, 'searchBy').and.callThrough();
});

describe('getTopics', () => {
it('should call findListByHref', (done) => {
service.getTopics().subscribe(
(res) => {
expect((service as any).findAllData.findAll).toHaveBeenCalledWith({}, true, true);
}
describe('searchTopicsByTarget', () => {
it('should call searchData.searchBy with the correct parameters', () => {
const options = { elementsPerPage: 10 };
const useCachedVersionIfAvailable = true;
const reRequestOnStale = true;

service.searchTopicsByTarget(options, useCachedVersionIfAvailable, reRequestOnStale);

expect((service as any).searchData.searchBy).toHaveBeenCalledWith(
'byTarget',
options,
useCachedVersionIfAvailable,
reRequestOnStale
);
done();
});

it('should return a RemoteData<PaginatedList<QualityAssuranceTopicObject>> for the object with the given URL', () => {
const result = service.getTopics();
const result = service.searchTopicsByTarget();
const expected = cold('(a)', {
a: paginatedListRD
});
Expand Down
Loading

0 comments on commit 0d63a85

Please sign in to comment.