Skip to content

Commit

Permalink
add contributor guard to data entry pages
Browse files Browse the repository at this point in the history
  • Loading branch information
lukavdplas committed Oct 2, 2024
1 parent a1e6429 commit 3f228a6
Show file tree
Hide file tree
Showing 9 changed files with 65 additions and 12 deletions.
2 changes: 1 addition & 1 deletion frontend/src/app/core/menu/menu.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
Home
</a>
</li>
<li *ngIf="isAuthenticated$ | async" class="nav-item">
<li *ngIf="isContributor$ | async" class="nav-item">
<a [routerLink]="['/data-entry']" routerLinkActive="active" class="nav-link">
Data entry
</a>
Expand Down
5 changes: 4 additions & 1 deletion frontend/src/app/core/menu/menu.component.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { Component } from '@angular/core';
import { AuthService } from '@services/auth.service';
import { map } from 'rxjs';

@Component({
selector: 'lc-menu',
Expand All @@ -8,7 +9,9 @@ import { AuthService } from '@services/auth.service';
})
export class MenuComponent {
public burgerActive = false;
public isAuthenticated$ = this.authService.isAuthenticated$;
public isContributor$ = this.authService.currentUser$.pipe(
map(user => user?.isContributor || false)
);

constructor(private authService: AuthService) {}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ const fakeUserResponse: UserResponse = {
email: "[email protected]",
first_name: "Frodo",
last_name: "Baggins",
is_staff: false
is_staff: false,
is_contributor: true,
}

const fakeAdminResponse: UserResponse = {
Expand All @@ -21,7 +22,8 @@ const fakeAdminResponse: UserResponse = {
email: "[email protected]",
first_name: "Gandalf",
last_name: "The Grey",
is_staff: true
is_staff: true,
is_contributor: false,
}


Expand Down
5 changes: 3 additions & 2 deletions frontend/src/app/routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { RegisterComponent } from './user/register/register.component';
import { PasswordForgottenComponent } from './user/password-forgotten/password-forgotten.component';
import { ResetPasswordComponent } from './user/reset-password/reset-password.component';
import { UserSettingsComponent } from './user/user-settings/user-settings.component';
import { LoggedOnGuard } from '@shared/logged-on.guard';
import { ContributorGuard, LoggedOnGuard } from '@shared/logged-on.guard';
import { SourcesComponent } from './data-entry/sources/sources.component';
import { LocationFormComponent } from './data-entry/location-form/location-form.component';
import { GiftFormComponent } from './data-entry/gift-form/gift-form.component';
Expand Down Expand Up @@ -55,11 +55,12 @@ const routes: Routes = [
{
path: 'user-settings',
title: pageTitle('Settings'),
canActivate: [LoggedOnGuard],
component: UserSettingsComponent
},
{
path: 'data-entry',
canActivate: [LoggedOnGuard],
canActivate: [ContributorGuard],
children: [
{
path: 'agents/:id',
Expand Down
36 changes: 34 additions & 2 deletions frontend/src/app/shared/logged-on.guard.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,52 @@
import { inject } from "@angular/core";
import { ActivatedRouteSnapshot, CanActivateFn, Router } from "@angular/router";
import { AuthService } from "@services/auth.service";
import { ToastService } from "@services/toast.service";
import { filter, map } from "rxjs";

export const LoggedOnGuard: CanActivateFn = (route: ActivatedRouteSnapshot) => {
const authService = inject(AuthService);
const toastService = inject(ToastService);
const router = inject(Router);

return authService.currentUser$.pipe(
filter((user) => user !== undefined),
map((user) => {
toastService.show({
type: 'danger',
header: 'Not signed in',
body: 'You must be signed in to view this page.'
});
if (user === null) {
router.navigate(["/login"], { queryParams: { next: route.url } });
return false;
return router.createUrlTree(['/login'], {
queryParams: { next: route.url }
});
}
return true;
})
);
};

export const ContributorGuard: CanActivateFn = (route: ActivatedRouteSnapshot) => {
const authService = inject(AuthService);
const toastService = inject(ToastService);
const router = inject(Router);

return authService.currentUser$.pipe(
filter((user) => user !== undefined),
map((user) => {
if (user?.isContributor) {
return true;
} else {
let body = 'You do not have permission to view this page.';
if (!user) { body += ' Do you need to sign in?'; }
toastService.show({
type: 'danger',
header: 'Not authorised',
body,
});
return router.createUrlTree(['/']);
}
}),
);
};
2 changes: 2 additions & 0 deletions frontend/src/app/user/models/user.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ export interface UserResponse {
first_name: string;
last_name: string;
is_staff: boolean;
is_contributor: boolean;
}

export class User {
Expand All @@ -15,6 +16,7 @@ export class User {
public firstName: string,
public lastName: string,
public isStaff: boolean,
public isContributor: boolean,
) { }
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@ const fakeUser: User = {
firstName: 'Frodo',
lastName: 'Baggins',
username: 'frodo',
isStaff: false
isStaff: false,
isContributor: true,
}

@Injectable({ providedIn: 'root' })
Expand Down
16 changes: 14 additions & 2 deletions frontend/src/app/user/utils.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ describe("User utils", () => {
first_name: "Test",
last_name: "User",
is_staff: true,
is_contributor: true,
};
const user = parseUserData(result);
expect(user).toBeInstanceOf(User);
Expand All @@ -48,6 +49,7 @@ describe("User utils", () => {
expect(user?.firstName).toBe("Test");
expect(user?.lastName).toBe("User");
expect(user?.isStaff).toBe(true);
expect(user?.isContributor).toBe(true);
});
});

Expand All @@ -59,7 +61,6 @@ describe("User utils", () => {
email: "[email protected]",
firstName: "Test",
lastName: "User",
isStaff: true,
};
const encoded = encodeUserData(data);
expect(encoded).toEqual({
Expand All @@ -68,9 +69,20 @@ describe("User utils", () => {
email: "[email protected]",
first_name: "Test",
last_name: "User",
is_staff: true,
});
});

it('should omit is_staff and is_contributor', () => {
const data: Partial<User> = {
id: 1,
isStaff: true,
isContributor: true,
};
const encoded = encodeUserData(data);
expect(encoded).toEqual({
id: 1,
});
})
});

describe("setErrors", () => {
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/app/user/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ export const parseUserData = (result: UserResponse | null): User | null => {
result.first_name,
result.last_name,
result.is_staff,
result.is_contributor,
);
};

Expand All @@ -39,7 +40,6 @@ export const encodeUserData = (data: Partial<User>): Partial<UserResponse> => {
email: data.email,
first_name: data.firstName,
last_name: data.lastName,
is_staff: data.isStaff,
};
return _.omit(encoded, _.isUndefined);
};
Expand Down

0 comments on commit 3f228a6

Please sign in to comment.