Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Editor]: Allow logging out #1039

Merged
merged 11 commits into from
Nov 25, 2024
24 changes: 19 additions & 5 deletions apps/metadata-editor-e2e/src/e2e/dashboard.cy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -344,11 +344,25 @@ describe('dashboard (authenticated)', () => {
})
})

describe('when the user is not logged in', () => {
beforeEach(() => {
cy.visit('/catalog/search')
describe('Logging in and out', () => {
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=')
})
})
it('redirects to the login page', () => {
cy.url().should('include', '/catalog.signin?redirect=')
describe('Logging out', () => {
beforeEach(() => {
cy.login('admin', 'admin', false)
cy.visit('/catalog/search')
})
it('logs out the user', () => {
cy.get('gn-ui-avatar').should('be.visible')
cy.get('md-editor-sidebar').find('gn-ui-button').eq(1).click()
cy.url().should('include', '/catalog.signin?redirect=')
cmoinier marked this conversation as resolved.
Show resolved Hide resolved
cy.get('gn-ui-avatar').should('not.exist')
})
})
})
5 changes: 5 additions & 0 deletions apps/metadata-editor/src/app/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import { DashboardPageComponent } from './dashboard/dashboard-page.component'
import { EditorRouterService } from './router.service'
import {
LOGIN_URL,
LOGOUT_URL,
provideGn4,
provideRepositoryUrl,
} from '@geonetwork-ui/api/repository'
Expand Down Expand Up @@ -70,6 +71,10 @@ import { FeatureEditorModule } from '@geonetwork-ui/feature/editor'
provide: LOGIN_URL,
useFactory: () => getGlobalConfig().LOGIN_URL,
},
{
provide: LOGOUT_URL,
useFactory: () => getGlobalConfig().LOGOUT_URL,
},
],
bootstrap: [AppComponent],
})
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,14 @@
<gn-ui-button
type="default"
class="w-10 h-10 flex justify-center items-center hover:cursor-pointer"
(click)="logOut()"
>
<img src="assets/system-shut.svg" alt="Log out" class="w-4 h-4" />
<img
src="assets/system-shut.svg"
[alt]="'editor.sidebar.logout' | translate"
[title]="'editor.sidebar.logout' | translate"
class="w-4 h-4 hover:invert-[.5]"
/>
</gn-ui-button>
</div>
</ng-container>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,19 +1,27 @@
import { ComponentFixture, TestBed } from '@angular/core/testing'
import { AvatarServiceInterface } from '@geonetwork-ui/api/repository'
import {
AuthService,
AvatarServiceInterface,
} from '@geonetwork-ui/api/repository'
import { OrganizationsServiceInterface } from '@geonetwork-ui/common/domain/organizations.service.interface'
import { PlatformServiceInterface } from '@geonetwork-ui/common/domain/platform.service.interface'
import { TranslateModule } from '@ngx-translate/core'
import { MockBuilder, MockProviders } from 'ng-mocks'
import { MockBuilder, MockProvider, MockProviders } from 'ng-mocks'
import { SidebarComponent } from './sidebar.component'

describe('SidebarComponent', () => {
let component: SidebarComponent
let fixture: ComponentFixture<SidebarComponent>
let service: AuthService

beforeEach(() => {
return MockBuilder(SidebarComponent)
})

afterEach(() => {
jest.resetAllMocks()
})

beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [SidebarComponent, TranslateModule.forRoot()],
Expand All @@ -23,9 +31,13 @@ describe('SidebarComponent', () => {
AvatarServiceInterface,
OrganizationsServiceInterface
),
MockProvider(AuthService, {
logoutUrl: 'http://logout.com/bla?',
}),
],
}).compileComponents()

service = TestBed.inject(AuthService)
fixture = TestBed.createComponent(SidebarComponent)
component = fixture.componentInstance
fixture.detectChanges()
Expand All @@ -34,4 +46,21 @@ describe('SidebarComponent', () => {
it('should create', () => {
expect(component).toBeTruthy()
})

describe('logOut', () => {
it('should log out', async () => {
jest.spyOn(window, 'fetch').mockResolvedValue({
ok: true,
} as Response)

const originalUrl = window.location.href

await component.logOut()

expect(window.fetch).toHaveBeenCalledWith(service.logoutUrl, {
method: 'GET',
})
expect(window.location.href).toBe(originalUrl)
})
})
})
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,10 @@ import { ChangeDetectionStrategy, Component, OnInit } from '@angular/core'
import { TranslateModule } from '@ngx-translate/core'
import { DashboardMenuComponent } from '../dashboard-menu/dashboard-menu.component'
import { PlatformServiceInterface } from '@geonetwork-ui/common/domain/platform.service.interface'
import { AvatarServiceInterface } from '@geonetwork-ui/api/repository'
import {
AuthService,
AvatarServiceInterface,
} from '@geonetwork-ui/api/repository'
import { LetDirective } from '@ngrx/component'
import { UiElementsModule } from '@geonetwork-ui/ui/elements'
import { OrganizationsServiceInterface } from '@geonetwork-ui/common/domain/organizations.service.interface'
Expand Down Expand Up @@ -31,7 +34,8 @@ export class SidebarComponent implements OnInit {
constructor(
public platformService: PlatformServiceInterface,
private avatarService: AvatarServiceInterface,
public organisationsService: OrganizationsServiceInterface
public organisationsService: OrganizationsServiceInterface,
private authService: AuthService
) {}

ngOnInit(): void {
Expand All @@ -41,4 +45,21 @@ export class SidebarComponent implements OnInit {
(orgs, me) => orgs.filter((org) => org.name === me?.organisation)
)
}

logOut() {
const current_url = window.location.toString()
cmoinier marked this conversation as resolved.
Show resolved Hide resolved
fetch(this.authService.logoutUrl, {
method: 'GET',
})
.then((response) => {
if (response.ok) {
window.location.href = current_url
} else {
console.error('Logout failed')
}
})
.catch((error) => {
console.error('Error during logout request:', error)
})
}
}
1 change: 1 addition & 0 deletions conf/default.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ proxy_path = ""
# - ${lang2}, ${lang3}: indicates if and where the current language should be part of the login URL in language 2 or 3 letter code
# Example to use the georchestra login page:
# login_url = "/cas/login?service=${current_url}"
# logout_url = "/geonetwork/signout"
# This optional URL should point to the static html page wc-embedder.html which allows to display a web component (like chart and table) via a permalink.
# URLs can be indicated from the root of the same server starting with a "/" or as an external URL. Be conscious of potential CORS issues when using an external URL.
# The default location in the dockerized datahub app for example is "/datahub/wc-embedder.html".
Expand Down
9 changes: 9 additions & 0 deletions libs/api/repository/src/lib/gn4/auth/auth.service.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,4 +82,13 @@ describe('AuthService', () => {
)
})
})

describe('Logout', () => {
beforeEach(() => {
service = TestBed.inject(AuthService)
})
it('should return the logout url', () => {
expect(service.logoutUrl).toEqual('/geonetwork/signout')
})
})
})
14 changes: 11 additions & 3 deletions libs/api/repository/src/lib/gn4/auth/auth.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,15 @@ import { TranslateService } from '@ngx-translate/core'
export const DEFAULT_GN4_LOGIN_URL = `/geonetwork/srv/\${lang3}/catalog.signin?redirect=\${current_url}`
export const LOGIN_URL = new InjectionToken<string>('loginUrl')

export const DEFAULT_GN4_LOGOUT_URL = `/geonetwork/signout`
export const LOGOUT_URL = new InjectionToken<string>('logoutUrl')

@Injectable({
providedIn: 'root',
})
export class AuthService {
baseLoginUrl = this.baseLoginUrlToken || DEFAULT_GN4_LOGIN_URL
baseLogoutUrl = this.baseLogoutUrlToken || DEFAULT_GN4_LOGOUT_URL
get loginUrl() {
let baseUrl = this.baseLoginUrl
const locationHasQueryParams = !!window.location.search
Expand All @@ -25,10 +29,14 @@ export class AuthService {
LANG_2_TO_3_MAPPER[this.translateService.currentLang]
)
}

get logoutUrl() {
return this.baseLogoutUrl
}

constructor(
@Optional()
@Inject(LOGIN_URL)
private baseLoginUrlToken: string,
@Optional() @Inject(LOGIN_URL) private baseLoginUrlToken: string,
@Optional() @Inject(LOGOUT_URL) private baseLogoutUrlToken: string,
private translateService: TranslateService
) {}
}
1 change: 1 addition & 0 deletions libs/util/app-config/src/lib/app-config.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,7 @@ describe('app config utils', () => {
PROXY_PATH: '/proxy/?url=',
METADATA_LANGUAGE: 'fre',
LOGIN_URL: '/cas/login?service=',
LOGOUT_URL: '/geonetwork/signout',
WEB_COMPONENT_EMBEDDER_URL: '/datahub/wc-embedder.html',
})
})
Expand Down
2 changes: 2 additions & 0 deletions libs/util/app-config/src/lib/app-config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ export function loadAppConfig() {
'proxy_path',
'metadata_language',
'login_url',
'logout_url',
'web_component_embedder_url',
'languages',
'contact_email',
Expand All @@ -124,6 +125,7 @@ export function loadAppConfig() {
).toLowerCase()
: undefined,
LOGIN_URL: parsedGlobalSection.login_url,
LOGOUT_URL: parsedGlobalSection.logout_url,
WEB_COMPONENT_EMBEDDER_URL:
parsedGlobalSection.web_component_embedder_url,
LANGUAGES: parsedGlobalSection.languages,
Expand Down
1 change: 1 addition & 0 deletions libs/util/app-config/src/lib/fixtures.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ geonetwork4_api_url = "/geonetwork/srv/api"
proxy_path = "/proxy/?url="
metadata_language = "fre"
login_url = "/cas/login?service="
logout_url = "/geonetwork/signout"
web_component_embedder_url = "/datahub/wc-embedder.html"

[map]
Expand Down
1 change: 1 addition & 0 deletions libs/util/app-config/src/lib/model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ export interface GlobalConfig {
PROXY_PATH?: string
METADATA_LANGUAGE?: string
LOGIN_URL?: string
LOGOUT_URL?: string
WEB_COMPONENT_EMBEDDER_URL?: string
LANGUAGES?: string[]
CONTACT_EMAIL?: string
Expand Down
1 change: 1 addition & 0 deletions translations/de.json
Original file line number Diff line number Diff line change
Expand Up @@ -296,6 +296,7 @@
"editor.record.undo.tooltip.disabled": "",
"editor.record.undo.tooltip.enabled": "",
"editor.record.upToDate": "Dieser Datensatz ist auf dem neuesten Stand",
"editor.sidebar.logout": "",
"editor.sidebar.menu.editor": "",
"editor.temporary.disabled": "",
"externalviewer.dataset.unnamed": "Datensatz aus dem Datahub",
Expand Down
1 change: 1 addition & 0 deletions translations/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -296,6 +296,7 @@
"editor.record.undo.tooltip.disabled": "There are no pending changes on this record",
"editor.record.undo.tooltip.enabled": "Clicking this button will cancel the pending changes on this record.",
"editor.record.upToDate": "This record is up to date",
"editor.sidebar.logout": "Log out",
"editor.sidebar.menu.editor": "Editor",
"editor.temporary.disabled": "Not implemented yet",
"externalviewer.dataset.unnamed": "Datahub layer",
Expand Down
1 change: 1 addition & 0 deletions translations/es.json
Original file line number Diff line number Diff line change
Expand Up @@ -296,6 +296,7 @@
"editor.record.undo.tooltip.disabled": "",
"editor.record.undo.tooltip.enabled": "",
"editor.record.upToDate": "",
"editor.sidebar.logout": "",
"editor.sidebar.menu.editor": "",
"editor.temporary.disabled": "",
"externalviewer.dataset.unnamed": "",
Expand Down
1 change: 1 addition & 0 deletions translations/fr.json
Original file line number Diff line number Diff line change
Expand Up @@ -296,6 +296,7 @@
"editor.record.undo.tooltip.disabled": "Il n'y a pas de modifications en cours sur cette fiche",
"editor.record.undo.tooltip.enabled": "Cliquez sur ce bouton pour annuler les modifications apportées à cette fiche",
"editor.record.upToDate": "",
"editor.sidebar.logout": "Se déconnecter",
"editor.sidebar.menu.editor": "",
"editor.temporary.disabled": "Pas encore implémenté",
"externalviewer.dataset.unnamed": "Couche du datahub",
Expand Down
1 change: 1 addition & 0 deletions translations/it.json
Original file line number Diff line number Diff line change
Expand Up @@ -296,6 +296,7 @@
"editor.record.undo.tooltip.disabled": "",
"editor.record.undo.tooltip.enabled": "",
"editor.record.upToDate": "",
"editor.sidebar.logout": "",
"editor.sidebar.menu.editor": "",
"editor.temporary.disabled": "",
"externalviewer.dataset.unnamed": "Layer del datahub",
Expand Down
1 change: 1 addition & 0 deletions translations/nl.json
Original file line number Diff line number Diff line change
Expand Up @@ -296,6 +296,7 @@
"editor.record.undo.tooltip.disabled": "",
"editor.record.undo.tooltip.enabled": "",
"editor.record.upToDate": "",
"editor.sidebar.logout": "",
"editor.sidebar.menu.editor": "",
"editor.temporary.disabled": "",
"externalviewer.dataset.unnamed": "",
Expand Down
1 change: 1 addition & 0 deletions translations/pt.json
Original file line number Diff line number Diff line change
Expand Up @@ -296,6 +296,7 @@
"editor.record.undo.tooltip.disabled": "",
"editor.record.undo.tooltip.enabled": "",
"editor.record.upToDate": "",
"editor.sidebar.logout": "",
"editor.sidebar.menu.editor": "",
"editor.temporary.disabled": "",
"externalviewer.dataset.unnamed": "",
Expand Down
1 change: 1 addition & 0 deletions translations/sk.json
Original file line number Diff line number Diff line change
Expand Up @@ -296,6 +296,7 @@
"editor.record.undo.tooltip.disabled": "",
"editor.record.undo.tooltip.enabled": "",
"editor.record.upToDate": "",
"editor.sidebar.logout": "",
"editor.sidebar.menu.editor": "",
"editor.temporary.disabled": "",
"externalviewer.dataset.unnamed": "",
Expand Down
Loading