Skip to content

Commit 6eb0690

Browse files
fix(moderation): add registration moderation guard (#526)
1 parent 85fb51d commit 6eb0690

File tree

10 files changed

+65
-20
lines changed

10 files changed

+65
-20
lines changed

src/app/app.routes.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,12 @@ export const routes: Routes = [
157157
import('./core/components/request-access/request-access.component').then((mod) => mod.RequestAccessComponent),
158158
data: { skipBreadcrumbs: true },
159159
},
160+
{
161+
path: 'not-found',
162+
loadComponent: () =>
163+
import('./core/components/page-not-found/page-not-found.component').then((mod) => mod.PageNotFoundComponent),
164+
data: { skipBreadcrumbs: true },
165+
},
160166
{
161167
path: ':id/files/:provider/:fileId',
162168
loadComponent: () =>

src/app/core/components/nav-menu/nav-menu.component.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,8 @@ export class NavMenuComponent {
5959
preprintReviewsPageVisible: this.canUserViewReviews(),
6060
registrationModerationPageVisible:
6161
this.provider()?.type === CurrentResourceType.Registrations &&
62-
this.provider()?.permissions?.includes(ReviewPermissions.ViewSubmissions),
62+
this.provider()?.permissions?.includes(ReviewPermissions.ViewSubmissions) &&
63+
!!this.provider()?.reviewsWorkflow,
6364
collectionModerationPageVisible:
6465
this.provider()?.type === CurrentResourceType.Collections &&
6566
this.provider()?.permissions?.includes(ReviewPermissions.ViewSubmissions),
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import { Store } from '@ngxs/store';
2+
3+
import { map, switchMap, take } from 'rxjs';
4+
5+
import { inject } from '@angular/core';
6+
import { CanActivateFn, Router } from '@angular/router';
7+
8+
import { GetRegistryProvider, RegistrationProviderSelectors } from '@osf/shared/stores/registration-provider';
9+
10+
export const registrationModerationGuard: CanActivateFn = (route) => {
11+
const store = inject(Store);
12+
const router = inject(Router);
13+
14+
const provider = store.selectSnapshot(RegistrationProviderSelectors.getBrandedProvider);
15+
16+
if (provider?.reviewsWorkflow) {
17+
return true;
18+
}
19+
const id = route.params['providerId'];
20+
return store.dispatch(new GetRegistryProvider(id)).pipe(
21+
switchMap(() => {
22+
return store.select(RegistrationProviderSelectors.getBrandedProvider).pipe(
23+
take(1),
24+
map((provider) => {
25+
if (!provider?.reviewsWorkflow) {
26+
router.navigate(['/not-found']);
27+
return false;
28+
}
29+
30+
return true;
31+
})
32+
);
33+
})
34+
);
35+
};

src/app/features/registries/registries.routes.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { provideStates } from '@ngxs/store';
22

33
import { Routes } from '@angular/router';
44

5+
import { registrationModerationGuard } from '@core/guards/registration-moderation.guard';
56
import { authGuard } from '@osf/core/guards';
67
import { RegistriesComponent } from '@osf/features/registries/registries.component';
78
import { RegistriesState } from '@osf/features/registries/store';
@@ -43,7 +44,7 @@ export const registriesRoutes: Routes = [
4344
},
4445
{
4546
path: ':providerId/moderation',
46-
canActivate: [authGuard],
47+
canActivate: [authGuard, registrationModerationGuard],
4748
loadChildren: () =>
4849
import('@osf/features/moderation/registry-moderation.routes').then((c) => c.registryModerationRoutes),
4950
},

src/app/shared/mappers/registration-provider.mapper.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ export class RegistrationProviderMapper {
3434
}
3535
: null,
3636
iri: response.links.iri,
37+
reviewsWorkflow: response.attributes.reviews_workflow,
3738
};
3839
}
3940
}

src/app/shared/mappers/registration/registration-node.mapper.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@ export class RegistrationNodeMapper {
8585
name: provider.attributes.name,
8686
permissions: provider.attributes.permissions,
8787
type: CurrentResourceType.Registrations,
88+
reviewsWorkflow: provider.attributes.reviews_workflow,
8889
};
8990
}
9091
}

src/app/shared/models/provider/provider.model.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ export interface ProviderShortInfoModel {
55
name: string;
66
type: CurrentResourceType;
77
permissions?: ReviewPermissions[];
8+
reviewsWorkflow?: string;
89
}
910

1011
export interface BaseProviderModel {

src/app/shared/models/provider/registry-provider.model.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,5 @@ export interface RegistryProviderDetails {
88
permissions: ReviewPermissions[];
99
brand: Brand | null;
1010
iri: string;
11+
reviewsWorkflow: string;
1112
}

src/app/shared/stores/registration-provider/registration-provider.actions.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ const stateName = '[Registry Provider Search]';
33
export class GetRegistryProvider {
44
static readonly type = `${stateName} Get Registry Provider`;
55

6-
constructor(public providerName: string) {}
6+
constructor(public providerId: string) {}
77
}
88

99
export class ClearRegistryProvider {

src/app/shared/stores/registration-provider/registration-provider.state.ts

Lines changed: 15 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import { Action, State, StateContext } from '@ngxs/store';
2-
import { patch } from '@ngxs/store/operators';
32

43
import { catchError, of, tap } from 'rxjs';
54

@@ -30,14 +29,14 @@ export class RegistrationProviderState {
3029
const state = ctx.getState();
3130

3231
const currentProvider = state.currentBrandedProvider.data;
33-
34-
if (currentProvider?.name === action.providerName) {
32+
if (currentProvider && currentProvider?.id === action.providerId) {
3533
ctx.dispatch(
3634
new SetCurrentProvider({
37-
id: currentProvider.id,
38-
name: currentProvider.name,
35+
id: currentProvider?.id,
36+
name: currentProvider?.name,
3937
type: CurrentResourceType.Registrations,
40-
permissions: currentProvider.permissions,
38+
permissions: currentProvider?.permissions,
39+
reviewsWorkflow: currentProvider?.reviewsWorkflow,
4140
})
4241
);
4342

@@ -51,24 +50,23 @@ export class RegistrationProviderState {
5150
},
5251
});
5352

54-
return this.registrationProvidersService.getProviderBrand(action.providerName).pipe(
53+
return this.registrationProvidersService.getProviderBrand(action.providerId).pipe(
5554
tap((provider) => {
56-
ctx.setState(
57-
patch({
58-
currentBrandedProvider: patch({
59-
data: provider,
60-
isLoading: false,
61-
error: null,
62-
}),
63-
})
64-
);
55+
ctx.patchState({
56+
currentBrandedProvider: {
57+
data: provider,
58+
isLoading: false,
59+
error: null,
60+
},
61+
});
6562

6663
ctx.dispatch(
6764
new SetCurrentProvider({
6865
id: provider.id,
6966
name: provider.name,
7067
type: CurrentResourceType.Registrations,
7168
permissions: provider.permissions,
69+
reviewsWorkflow: provider.reviewsWorkflow,
7270
})
7371
);
7472
}),
@@ -78,6 +76,6 @@ export class RegistrationProviderState {
7876

7977
@Action(ClearRegistryProvider)
8078
clearRegistryProvider(ctx: StateContext<RegistrationProviderStateModel>) {
81-
ctx.setState(patch({ ...REGISTRIES_PROVIDER_SEARCH_STATE_DEFAULTS }));
79+
ctx.patchState({ ...REGISTRIES_PROVIDER_SEARCH_STATE_DEFAULTS });
8280
}
8381
}

0 commit comments

Comments
 (0)