From e6a014cd23e149523369c26e01fdfa75b76125f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20Gro=C3=9Fe?= Date: Tue, 12 Sep 2023 16:49:02 +0200 Subject: [PATCH] Add anon edit warning link parameters Bug: T330550 --- src/components/AnonymousEditWarning.vue | 8 +++++- src/init.ts | 6 +++++ src/main.ts | 3 +++ .../AccountLinkerPlugin/AccountLinker.ts | 21 ++++++++++++++++ .../MediaWikiAccountLinker.ts | 19 ++++++++++++++ tests/integration/App.test.ts | 2 ++ .../components/AnonymousEditWarning.test.ts | 19 ++++++++++++-- .../AnonymousEditWarning.test.ts.snap | 2 +- tests/unit/main.test.ts | 4 +++ .../plugins/MediaWikiAccountLinker.test.ts | 25 +++++++++++++++++++ 10 files changed, 105 insertions(+), 4 deletions(-) create mode 100644 src/plugins/AccountLinkerPlugin/AccountLinker.ts create mode 100644 src/plugins/AccountLinkerPlugin/MediaWikiAccountLinker.ts create mode 100644 tests/unit/plugins/MediaWikiAccountLinker.test.ts diff --git a/src/components/AnonymousEditWarning.vue b/src/components/AnonymousEditWarning.vue index 8745797a..98532ebf 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 { useAccountLinker } from '@/plugins/AccountLinkerPlugin/AccountLinker'; +const accountLinker = useAccountLinker(); const messages = useMessages(); const warning = computed( - () => messages.get( 'wikibase-anonymouseditwarning' ) ); + () => messages.get( + 'wikibase-anonymouseditwarning', + accountLinker.getLoginLink(), + accountLinker.getCreateAccountLink(), + ) ); const config = useConfig(); diff --git a/src/init.ts b/src/init.ts index 9c281d8e..56cdf678 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 MediaWikiAccountLinker from '@/plugins/AccountLinkerPlugin/MediaWikiAccountLinker'; 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 accountLinker = new MediaWikiAccountLinker( + 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, + accountLinker, tracker, wikiRouter, }; diff --git a/src/main.ts b/src/main.ts index 614461e0..eee8953f 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 AccountLinker, { AccountLinkerKey } from '@/plugins/AccountLinkerPlugin/AccountLinker'; import Tracker from '@/data-access/tracking/Tracker'; import { HANDLE_INIT_PARAMS, @@ -35,6 +36,7 @@ export interface Services { langCodeRetriever: LangCodeRetriever; lexemeCreator: LexemeCreator; searchLinker: SearchLinker; + accountLinker: AccountLinker; 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( AccountLinkerKey, services.accountLinker ); app.provide( WikiRouterKey, services.wikiRouter ); app.provide( LanguageCodesProviderKey, diff --git a/src/plugins/AccountLinkerPlugin/AccountLinker.ts b/src/plugins/AccountLinkerPlugin/AccountLinker.ts new file mode 100644 index 00000000..f11b5ffb --- /dev/null +++ b/src/plugins/AccountLinkerPlugin/AccountLinker.ts @@ -0,0 +1,21 @@ +import { inject, InjectionKey } from 'vue'; + +export default interface AccountLinker { + /** + * FIXME + */ + getLoginLink(): string; + + /** + * FIXME + */ + getCreateAccountLink(): string; +} + +export const AccountLinkerKey: InjectionKey = Symbol( 'AccountLinker' ); + +export function useAccountLinker(): AccountLinker { + return inject( AccountLinkerKey, () => { + throw new Error( 'No AccountLinker provided!' ); + }, true ); +} diff --git a/src/plugins/AccountLinkerPlugin/MediaWikiAccountLinker.ts b/src/plugins/AccountLinkerPlugin/MediaWikiAccountLinker.ts new file mode 100644 index 00000000..4619a4ca --- /dev/null +++ b/src/plugins/AccountLinkerPlugin/MediaWikiAccountLinker.ts @@ -0,0 +1,19 @@ +import { MwUtilGetUrl } from '@/@types/mediawiki'; +import AccountLinker from '@/plugins/AccountLinkerPlugin/AccountLinker'; + +export default class MediaWikiAccountLinker implements AccountLinker { + + 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..2675c72f 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 { AccountLinkerKey } from '@/plugins/AccountLinkerPlugin/AccountLinker'; describe( 'App.vue', () => { @@ -64,6 +65,7 @@ describe( 'App.vue', () => { mwUtilGetUrl, lexemeNS, ), + [ AccountLinkerKey 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..6991cf57 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 { AccountLinkerKey } from '@/plugins/AccountLinkerPlugin/AccountLinker'; describe( 'AnonymousEditWarning', () => { it( 'does nothing if not anonymous', () => { const messages = { get: jest.fn() }; + const accountLinker = { + getLoginLink: jest.fn(), + getCreateAccountLink: jest.fn(), + }; const warning = mount( AnonymousEditWarning, { global: { provide: { [ ConfigKey as symbol ]: { isAnonymous: false }, [ MessagesKey as symbol ]: messages, + [ AccountLinkerKey as symbol ]: accountLinker, }, }, } ); expect( warning.isVisible() ).toBe( false ); expect( messages.get ).not.toHaveBeenCalled(); + expect( accountLinker.getLoginLink ).not.toHaveBeenCalled(); + expect( accountLinker.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 accountLinker = { + 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, + [ AccountLinkerKey as symbol ]: accountLinker, }, }, } ); 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..0893ec2d 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' ), }, + accountLinker: { + getLoginLink: jest.fn(), + getCreateAccountLink: jest.fn(), + }, tracker: unusedTracker, wikiRouter: unusedWikiRouter, langCodeRetriever: unusedLangCodeRetriever, diff --git a/tests/unit/plugins/MediaWikiAccountLinker.test.ts b/tests/unit/plugins/MediaWikiAccountLinker.test.ts new file mode 100644 index 00000000..1c2b6078 --- /dev/null +++ b/tests/unit/plugins/MediaWikiAccountLinker.test.ts @@ -0,0 +1,25 @@ +import MediaWikiAccountLinker from '@/plugins/AccountLinkerPlugin/MediaWikiAccountLinker'; + +describe( 'MediaWikiAccountLinker', () => { + 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 accountLinker = new MediaWikiAccountLinker( getUrlMock, 'Special:NewLexeme' ); + + expect( accountLinker.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 accountLinker = new MediaWikiAccountLinker( getUrlMock, 'Special:NewLexeme' ); + + expect( accountLinker.getCreateAccountLink() ).toBe( url ); + expect( getUrlMock ).toHaveBeenCalledWith( 'Special:CreateAccount', { + returnto: 'Special:NewLexeme', + } ); + } ); +} );