Skip to content

Commit

Permalink
feat(me): redirect to login if needed
Browse files Browse the repository at this point in the history
  • Loading branch information
jahow committed Sep 26, 2024
1 parent 4892c30 commit 9817a80
Show file tree
Hide file tree
Showing 9 changed files with 173 additions and 114 deletions.
20 changes: 14 additions & 6 deletions apps/metadata-editor-e2e/src/e2e/dashboard.cy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,15 @@ const fakeUser = {

const gnBaseUrl = 'http://localhost:8080/geonetwork/srv/eng/'

describe('dashboard', () => {
describe('dashboard (authenticated)', () => {
beforeEach(() => {
cy.login('admin', 'admin', false)
})

let pageOne
describe('avatar', () => {
describe('display avatar for user without gravatar hash', () => {
it('should display placeholder url', () => {
cy.login('admin', 'admin', false)
cy.visit(`${gnBaseUrl}admin.console#/organization`)
cy.get('#gn-btn-user-add').click()
cy.get('#username').type(fakeUser.username)
Expand All @@ -35,7 +38,6 @@ describe('dashboard', () => {
.should('eq', 'https://www.gravatar.com/avatar/?d=mp')
})
it('should display monsterid', () => {
cy.login('admin', 'admin', false)
cy.visit(`${gnBaseUrl}admin.console#/settings`)
cy.get('[id="system/users/identicon"]').type(
'{selectAll}gravatar:monsterid'
Expand Down Expand Up @@ -160,7 +162,6 @@ describe('dashboard', () => {
})
describe('columns', () => {
beforeEach(() => {
cy.login('admin', 'admin', false)
cy.visit('/catalog/search')
})
it('should display the right info for unpublished records', () => {
Expand Down Expand Up @@ -216,7 +217,6 @@ describe('dashboard', () => {

describe('navigation', () => {
beforeEach(() => {
cy.login('admin', 'admin', false)
cy.visit('/catalog/search')
})
describe('all records', () => {
Expand Down Expand Up @@ -277,7 +277,6 @@ describe('dashboard', () => {
}
describe('allRecords search input', () => {
beforeEach(() => {
cy.login('admin', 'admin', false)
cy.visit('/catalog/search')
})
it('should filter the dashboard based on the search input', () => {
Expand Down Expand Up @@ -315,3 +314,12 @@ describe('dashboard', () => {
})
})
})

describe('when the user is not logged in', () => {
beforeEach(() => {
cy.visit('/catalog/search')
})
it('redirects to the login page', () => {
cy.url().should('include', '/catalog.signin?redirect=')
})
})
10 changes: 9 additions & 1 deletion apps/metadata-editor/src/app/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,11 @@ import { provideAnimations } from '@angular/platform-browser/animations'
import { extModules } from './build-specifics'
import { DashboardPageComponent } from './dashboard/dashboard-page.component'
import { EditorRouterService } from './router.service'
import { provideGn4, provideRepositoryUrl } from '@geonetwork-ui/api/repository'
import {
LOGIN_URL,
provideGn4,
provideRepositoryUrl,
} from '@geonetwork-ui/api/repository'
import { FeatureEditorModule } from '@geonetwork-ui/feature/editor'

@NgModule({
Expand Down Expand Up @@ -62,6 +66,10 @@ import { FeatureEditorModule } from '@geonetwork-ui/feature/editor'
importProvidersFrom(EffectsModule.forRoot()),
provideGn4(),
provideAnimations(),
{
provide: LOGIN_URL,
useFactory: () => getGlobalConfig().LOGIN_URL,
},
],
bootstrap: [AppComponent],
})
Expand Down
159 changes: 84 additions & 75 deletions apps/metadata-editor/src/app/app.routes.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { Route } from '@angular/router'
import { DashboardPageComponent } from './dashboard/dashboard-page.component'
import { SignInPageComponent } from './sign-in/sign-in-page.component'
import { EditPageComponent } from './edit/edit-page.component'
import { EditRecordResolver } from './edit-record.resolver'
import { MyDraftComponent } from './records/my-draft/my-draft.component'
Expand All @@ -10,100 +9,110 @@ import { NewRecordResolver } from './new-record.resolver'
import { DuplicateRecordResolver } from './duplicate-record.resolver'
import { AllRecordsComponent } from './records/all-records/all-records.component'
import { MyRecordsStateWrapperComponent } from './records/my-records/my-records-state-wrapper.component'
import { AuthGuardService } from './auth-guard.service'

export const appRoutes: Route[] = [
{ path: '', redirectTo: 'catalog/search', pathMatch: 'prefix' },
{
path: 'catalog',
component: DashboardPageComponent,
outlet: 'primary',
path: '',
canActivate: [AuthGuardService],
children: [
{
path: '',
redirectTo: 'search',
redirectTo: 'catalog/search',
pathMatch: 'prefix',
},
{
path: 'discussion',
component: AllRecordsComponent,
pathMatch: 'prefix',
path: 'catalog',
component: DashboardPageComponent,
outlet: 'primary',
children: [
{
path: '',
redirectTo: 'search',
pathMatch: 'prefix',
},
{
path: 'discussion',
component: AllRecordsComponent,
pathMatch: 'prefix',
},
{
path: 'calendar',
component: AllRecordsComponent,
pathMatch: 'prefix',
},
{
path: 'contacts',
component: AllRecordsComponent,
pathMatch: 'prefix',
},
{
path: 'thesaurus',
component: AllRecordsComponent,
pathMatch: 'prefix',
},
{
path: 'search',
title: 'Search Records',
component: AllRecordsComponent,
pathMatch: 'prefix',
},
],
},
{
path: 'calendar',
component: AllRecordsComponent,
pathMatch: 'prefix',
path: 'my-space',
component: DashboardPageComponent,
outlet: 'primary',
title: 'My space',
children: [
{
path: 'my-records',
title: 'My Records',
component: MyRecordsStateWrapperComponent,
pathMatch: 'prefix',
},
{
path: 'my-draft',
title: 'My Draft',
component: MyDraftComponent,
pathMatch: 'prefix',
},
{
path: 'templates',
title: 'Templates',
component: TemplatesComponent,
pathMatch: 'prefix',
},
],
},
{
path: 'contacts',
component: AllRecordsComponent,
pathMatch: 'prefix',
path: 'users',
component: DashboardPageComponent,
outlet: 'primary',
title: 'Users',
children: [
{
path: 'my-org',
component: MyOrgUsersComponent,
pathMatch: 'prefix',
},
],
},
{
path: 'thesaurus',
component: AllRecordsComponent,
pathMatch: 'prefix',
path: 'create',
component: EditPageComponent,
resolve: { record: NewRecordResolver },
},
{
path: 'search',
title: 'Search Records',
component: AllRecordsComponent,
pathMatch: 'prefix',
path: 'duplicate/:uuid',
component: EditPageComponent,
resolve: { record: DuplicateRecordResolver },
},
],
},
{
path: 'my-space',
component: DashboardPageComponent,
outlet: 'primary',
title: 'My space',
children: [
{
path: 'my-records',
title: 'My Records',
component: MyRecordsStateWrapperComponent,
pathMatch: 'prefix',
},
{
path: 'my-draft',
title: 'My Draft',
component: MyDraftComponent,
pathMatch: 'prefix',
},
{
path: 'templates',
title: 'Templates',
component: TemplatesComponent,
pathMatch: 'prefix',
},
],
},
{
path: 'users',
component: DashboardPageComponent,
outlet: 'primary',
title: 'Users',
children: [
{
path: 'my-org',
component: MyOrgUsersComponent,
pathMatch: 'prefix',
path: 'edit/:uuid',
component: EditPageComponent,
resolve: { record: EditRecordResolver },
},
],
},
{ path: 'sign-in', component: SignInPageComponent },
{
path: 'create',
component: EditPageComponent,
resolve: { record: NewRecordResolver },
},
{
path: 'duplicate/:uuid',
component: EditPageComponent,
resolve: { record: DuplicateRecordResolver },
},
{
path: 'edit/:uuid',
component: EditPageComponent,
resolve: { record: EditRecordResolver },
},
]
44 changes: 44 additions & 0 deletions apps/metadata-editor/src/app/auth-guard.service.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import { AuthGuardService } from './auth-guard.service'
import { MockBuilder, MockProvider } from 'ng-mocks'
import { AuthService } from '@geonetwork-ui/api/repository'
import { TestBed } from '@angular/core/testing'
import { of } from 'rxjs'
import { PlatformServiceInterface } from '@geonetwork-ui/common/domain/platform.service.interface'

Object.defineProperty(window, 'location', {
value: new URL('http://localhost'),
})

describe('AuthGuardService', () => {
let service: AuthGuardService
beforeEach(() => {
return MockBuilder(AuthGuardService)
})

beforeEach(() => {
TestBed.configureTestingModule({
providers: [
MockProvider(AuthService, {
loginUrl: 'http://login.com/bla?',
}),
MockProvider(PlatformServiceInterface, {
isAnonymous: () => of(true),
}),
],
})
window.location.href = 'http://original.path'
service = TestBed.inject(AuthGuardService)
})

it('returns true if the user is logged in', async () => {
jest
.spyOn(TestBed.inject(PlatformServiceInterface), 'isAnonymous')
.mockReturnValue(of(false))
expect(await service.canActivate()).toBe(true)
expect(window.location.href).toBe('http://original.path/')
})
it('redirects the user to the login page if the user is not logged in', async () => {
expect(await service.canActivate()).toBe(false)
expect(window.location.href).toBe('http://login.com/bla?')
})
})
22 changes: 22 additions & 0 deletions apps/metadata-editor/src/app/auth-guard.service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { Injectable } from '@angular/core'
import { AuthService } from '@geonetwork-ui/api/repository'
import { PlatformServiceInterface } from '@geonetwork-ui/common/domain/platform.service.interface'
import { firstValueFrom } from 'rxjs'

@Injectable({ providedIn: 'root' })
export class AuthGuardService {
constructor(
private platformService: PlatformServiceInterface,
private authService: AuthService
) {}

// this will redirect the user to the authentication form if required
async canActivate(): Promise<boolean> {
const notLoggedIn = await firstValueFrom(this.platformService.isAnonymous())
if (notLoggedIn) {
window.location.href = this.authService.loginUrl
return false
}
return true
}
}
Empty file.

This file was deleted.

This file was deleted.

This file was deleted.

0 comments on commit 9817a80

Please sign in to comment.