diff --git a/src/components/AnonymousEditWarning.vue b/src/components/AnonymousEditWarning.vue index 8745797a..02300f08 100644 --- a/src/components/AnonymousEditWarning.vue +++ b/src/components/AnonymousEditWarning.vue @@ -3,10 +3,16 @@ import WarningMessage from '@/components/WarningMessage.vue'; import { useConfig } from '@/plugins/ConfigPlugin/Config'; import { useMessages } from '@/plugins/MessagesPlugin/Messages'; import { computed } from 'vue'; +import { useAuthenticationLinker } from '@/plugins/AuthenticationLinkerPlugin/AuthenticationLinker'; +const authenticationLinker = useAuthenticationLinker(); const messages = useMessages(); const warning = computed( - () => messages.get( 'wikibase-anonymouseditwarning' ) ); + () => messages.get( + 'wikibase-anonymouseditwarning', + authenticationLinker.getLoginLink(), + authenticationLinker.getCreateAccountLink(), + ) ); const config = useConfig(); diff --git a/src/init.ts b/src/init.ts index 9c281d8e..aa8a516d 100644 --- a/src/init.ts +++ b/src/init.ts @@ -12,6 +12,7 @@ import { ComponentPublicInstance } from 'vue'; import MediaWikiRouter from './plugins/WikiRouterPlugin/MediaWikiRouter'; import MwApiLangCodeRetriever from './data-access/MwApiLangCodeRetriever'; import LanguageItemSearcher from '@/data-access/LanguageItemSearcher'; +import MediaWikiAuthenticationLinker from '@/plugins/AuthenticationLinkerPlugin/MediaWikiAuthenticationLinker'; interface InitConfig extends CreateAndMountConfig { tags: string[]; @@ -39,6 +40,10 @@ export default function init( config: InitConfig, mw: MediaWiki ): ComponentPubl mw.util.getUrl, ( mw.config.get( 'wgNamespaceIds' ) as Record ).lexeme, ); + const authenticationLinker = new MediaWikiAuthenticationLinker( + mw.util.getUrl, + mw.config.get( 'wgPageName' ) as string, + ); const tracker = new MwTracker( mw.track ); const wikiRouter = new MediaWikiRouter( mw.util.getUrl ); @@ -49,6 +54,7 @@ export default function init( config: InitConfig, mw: MediaWiki ): ComponentPubl messagesRepository, lexemeCreator, searchLinker, + authenticationLinker, tracker, wikiRouter, }; diff --git a/src/main.ts b/src/main.ts index 614461e0..b5884872 100644 --- a/src/main.ts +++ b/src/main.ts @@ -3,6 +3,7 @@ import LexemeCreator from '@/data-access/LexemeCreator'; import { ItemSearchKey } from '@/plugins/ItemSearchPlugin/ItemSearch'; import { Config, ConfigKey } from '@/plugins/ConfigPlugin/Config'; import SearchLinker, { SearchLinkerKey } from '@/plugins/SearchLinkerPlugin/SearchLinker'; +import AuthenticationLinker, { AuthenticationLinkerKey } from '@/plugins/AuthenticationLinkerPlugin/AuthenticationLinker'; import Tracker from '@/data-access/tracking/Tracker'; import { HANDLE_INIT_PARAMS, @@ -35,6 +36,7 @@ export interface Services { langCodeRetriever: LangCodeRetriever; lexemeCreator: LexemeCreator; searchLinker: SearchLinker; + authenticationLinker: AuthenticationLinker; tracker: Tracker; wikiRouter: WikiRouter; } @@ -59,6 +61,7 @@ export default function createAndMount( app.provide( ItemSearchKey, services.itemSearcher ); app.provide( LanguageItemSearchKey, services.languageItemSearcher ); app.provide( SearchLinkerKey, services.searchLinker ); + app.provide( AuthenticationLinkerKey, services.authenticationLinker ); app.provide( WikiRouterKey, services.wikiRouter ); app.provide( LanguageCodesProviderKey, diff --git a/src/plugins/AuthenticationLinkerPlugin/AuthenticationLinker.ts b/src/plugins/AuthenticationLinkerPlugin/AuthenticationLinker.ts new file mode 100644 index 00000000..4bb15759 --- /dev/null +++ b/src/plugins/AuthenticationLinkerPlugin/AuthenticationLinker.ts @@ -0,0 +1,21 @@ +import { inject, InjectionKey } from 'vue'; + +export default interface AuthenticationLinker { + /** + * Return a URL for logging in + */ + getLoginLink(): string; + + /** + * Return a URL for creating a new account + */ + getCreateAccountLink(): string; +} + +export const AuthenticationLinkerKey: InjectionKey = Symbol( 'AuthenticationLinker' ); + +export function useAuthenticationLinker(): AuthenticationLinker { + return inject( AuthenticationLinkerKey, () => { + throw new Error( 'No AuthenticationLinker provided!' ); + }, true ); +} diff --git a/src/plugins/AuthenticationLinkerPlugin/MediaWikiAuthenticationLinker.ts b/src/plugins/AuthenticationLinkerPlugin/MediaWikiAuthenticationLinker.ts new file mode 100644 index 00000000..461b2033 --- /dev/null +++ b/src/plugins/AuthenticationLinkerPlugin/MediaWikiAuthenticationLinker.ts @@ -0,0 +1,19 @@ +import { MwUtilGetUrl } from '@/@types/mediawiki'; +import AuthenticationLinker from '@/plugins/AuthenticationLinkerPlugin/AuthenticationLinker'; + +export default class MediaWikiAuthenticationLinker implements AuthenticationLinker { + + public constructor( + private readonly getUrl: MwUtilGetUrl, + private readonly currentPage: string, + ) {} + + public getCreateAccountLink(): string { + return this.getUrl( 'Special:CreateAccount', { returnto: this.currentPage } ); + } + + public getLoginLink(): string { + return this.getUrl( 'Special:UserLogin', { returnto: this.currentPage } ); + } + +} diff --git a/tests/integration/App.test.ts b/tests/integration/App.test.ts index ca347ffb..8175ed3d 100644 --- a/tests/integration/App.test.ts +++ b/tests/integration/App.test.ts @@ -15,6 +15,7 @@ import DevItemSearcher from '@/data-access/DevItemSearcher'; import DevMessagesRepository from '@/plugins/MessagesPlugin/DevMessagesRepository'; import MediaWikiSearchLinker from '@/plugins/SearchLinkerPlugin/MediaWikiSearchLinker'; import { LanguageItemSearchKey } from '@/plugins/ItemSearchPlugin/LanguageItemSearch'; +import { AuthenticationLinkerKey } from '@/plugins/AuthenticationLinkerPlugin/AuthenticationLinker'; describe( 'App.vue', () => { @@ -64,6 +65,7 @@ describe( 'App.vue', () => { mwUtilGetUrl, lexemeNS, ), + [ AuthenticationLinkerKey as symbol ]: null, [ WikiRouterKey as symbol ]: null, [ MessagesKey as symbol ]: new Messages( new DevMessagesRepository() ), [ ItemSearchKey as symbol ]: new DevItemSearcher(), diff --git a/tests/unit/components/AnonymousEditWarning.test.ts b/tests/unit/components/AnonymousEditWarning.test.ts index 0cd4b219..91d2f729 100644 --- a/tests/unit/components/AnonymousEditWarning.test.ts +++ b/tests/unit/components/AnonymousEditWarning.test.ts @@ -2,37 +2,52 @@ import AnonymousEditWarning from '@/components/AnonymousEditWarning.vue'; import { ConfigKey } from '@/plugins/ConfigPlugin/Config'; import { MessagesKey } from '@/plugins/MessagesPlugin/Messages'; import { mount } from '@vue/test-utils'; +import { AuthenticationLinkerKey } from '@/plugins/AuthenticationLinkerPlugin/AuthenticationLinker'; describe( 'AnonymousEditWarning', () => { it( 'does nothing if not anonymous', () => { const messages = { get: jest.fn() }; + const authenticationLinker = { + getLoginLink: jest.fn(), + getCreateAccountLink: jest.fn(), + }; const warning = mount( AnonymousEditWarning, { global: { provide: { [ ConfigKey as symbol ]: { isAnonymous: false }, [ MessagesKey as symbol ]: messages, + [ AuthenticationLinkerKey as symbol ]: authenticationLinker, }, }, } ); expect( warning.isVisible() ).toBe( false ); expect( messages.get ).not.toHaveBeenCalled(); + expect( authenticationLinker.getLoginLink ).not.toHaveBeenCalled(); + expect( authenticationLinker.getCreateAccountLink ).not.toHaveBeenCalled(); } ); it( 'matches snapshot if anonymous', () => { - const messages = { get: jest.fn().mockImplementation( ( key ) => key ) }; + const messages = { get: jest.fn().mockImplementation( ( ...params ) => + `(${params.join( ', ' )})`, + ) }; + const authenticationLinker = { + getLoginLink: jest.fn().mockReturnValue( 'loginLink' ), + getCreateAccountLink: jest.fn().mockReturnValue( 'createAccountLink' ), + }; const warning = mount( AnonymousEditWarning, { global: { provide: { [ ConfigKey as symbol ]: { isAnonymous: true }, [ MessagesKey as symbol ]: messages, + [ AuthenticationLinkerKey as symbol ]: authenticationLinker, }, }, } ); expect( warning.html() ).toMatchSnapshot(); - expect( messages.get ).toHaveBeenCalledWith( 'wikibase-anonymouseditwarning' ); + expect( messages.get ).toHaveBeenCalledWith( 'wikibase-anonymouseditwarning', 'loginLink', 'createAccountLink' ); } ); } ); diff --git a/tests/unit/components/__snapshots__/AnonymousEditWarning.test.ts.snap b/tests/unit/components/__snapshots__/AnonymousEditWarning.test.ts.snap index 4d488a60..de03082a 100644 --- a/tests/unit/components/__snapshots__/AnonymousEditWarning.test.ts.snap +++ b/tests/unit/components/__snapshots__/AnonymousEditWarning.test.ts.snap @@ -1,3 +1,3 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`AnonymousEditWarning matches snapshot if anonymous 1`] = `"
wikibase-anonymouseditwarning
"`; +exports[`AnonymousEditWarning matches snapshot if anonymous 1`] = `"
(wikibase-anonymouseditwarning, loginLink, createAccountLink)
"`; diff --git a/tests/unit/main.test.ts b/tests/unit/main.test.ts index b29f9528..69556916 100644 --- a/tests/unit/main.test.ts +++ b/tests/unit/main.test.ts @@ -39,6 +39,10 @@ describe( 'createAndMount', () => { searchLinker: { getSearchUrlForLexeme: jest.fn().mockReturnValue( 'https://example.com' ), }, + authenticationLinker: { + getLoginLink: jest.fn(), + getCreateAccountLink: jest.fn(), + }, tracker: unusedTracker, wikiRouter: unusedWikiRouter, langCodeRetriever: unusedLangCodeRetriever, diff --git a/tests/unit/plugins/MediaWikiAuthenticationLinker.test.ts b/tests/unit/plugins/MediaWikiAuthenticationLinker.test.ts new file mode 100644 index 00000000..a037cc7e --- /dev/null +++ b/tests/unit/plugins/MediaWikiAuthenticationLinker.test.ts @@ -0,0 +1,25 @@ +import MediaWikiAuthenticationLinker from '@/plugins/AuthenticationLinkerPlugin/MediaWikiAuthenticationLinker'; + +describe( 'MediaWikiAuthenticationLinker', () => { + it( 'delegates to mw.util.getUrl for getting the login url', () => { + const url = '/w/index.php?title=Special:UserLogin&returnto=Special%3ANewLexeme'; + const getUrlMock = jest.fn().mockReturnValue( url ); + const authenticationLinker = new MediaWikiAuthenticationLinker( getUrlMock, 'Special:NewLexeme' ); + + expect( authenticationLinker.getLoginLink() ).toBe( url ); + expect( getUrlMock ).toHaveBeenCalledWith( 'Special:UserLogin', { + returnto: 'Special:NewLexeme', + } ); + } ); + + it( 'delegates to mw.util.getUrl for getting the create account url', () => { + const url = '/w/index.php?title=Special:CreateAccount&returnto=Special%3ANewLexeme'; + const getUrlMock = jest.fn().mockReturnValue( url ); + const authenticationLinker = new MediaWikiAuthenticationLinker( getUrlMock, 'Special:NewLexeme' ); + + expect( authenticationLinker.getCreateAccountLink() ).toBe( url ); + expect( getUrlMock ).toHaveBeenCalledWith( 'Special:CreateAccount', { + returnto: 'Special:NewLexeme', + } ); + } ); +} );