Skip to content

Commit

Permalink
Process CentralAuth redirects on new lexeme as TempUser
Browse files Browse the repository at this point in the history
With T357024, the API will return a URL initialized by CentralAuth
when a TempUser tries to create a new lexeme. We need to redirect
to this URL instead of the new lexeme (the URL will then redirect
to the new lexeme once it’s finished setting up the temporary
account).

Bug: T357152
  • Loading branch information
codders committed Feb 15, 2024
1 parent d8d0d87 commit 2cfa3dd
Show file tree
Hide file tree
Showing 20 changed files with 143 additions and 108 deletions.
6 changes: 3 additions & 3 deletions cypress/e2e/NewLexemeForm.cy.js
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ describe( 'NewLexemeForm', () => {
'Create Lexeme "test lemma"@en-gb as Q123 Q456',
);
expect( spy ).to.have.been.calledWith(
'Navigating to: Special:EntityPage/L1',
`Navigating to: ${ Cypress.config().baseUrl }Special:EntityPage/L1`,
);
} );
} );
Expand Down Expand Up @@ -119,7 +119,7 @@ describe( 'NewLexemeForm', () => {
'Create Lexeme "test lemma"@en-ca as Q123 Q456',
);
expect( spy ).to.have.been.calledWith(
'Navigating to: Special:EntityPage/L1',
`Navigating to: ${ Cypress.config().baseUrl }Special:EntityPage/L1`,
);
} );
} );
Expand Down Expand Up @@ -174,7 +174,7 @@ describe( 'NewLexemeForm', () => {
'Create Lexeme "test lemma"@en-gb as Q123 Q456',
);
expect( spy ).to.have.been.calledWith(
'Navigating to: Special:EntityPage/L1',
`Navigating to: ${ Cypress.config().baseUrl }Special:EntityPage/L1`,
);
} );
} );
Expand Down
2 changes: 1 addition & 1 deletion index.html
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ <h1>New Lexeme</h1>
console.log( `TRACK: increment ${name}` );
},
},
wikiRouter: { async goToTitle( title ) { alert( `Navigating to: ${title}` ); } },
urlLauncher: { async goToURL( url ) { alert( `Navigating to: ${url}` ); } },
};

const params = new URLSearchParams( location.search );
Expand Down
2 changes: 1 addition & 1 deletion jest.overrides.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
( function () {
// eslint-disable-next-line no-console
console.warn = function () {
console.warn = function ( _message ) {
// ignore @vue/compat warnings
};
}() );
8 changes: 4 additions & 4 deletions src/components/NewLexemeForm.vue
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ import {
SET_SPELLING_VARIANT,
SET_SPELLING_VARIANT_SEARCH_INPUT,
} from '@/store/mutations';
import { useWikiRouter } from '@/plugins/WikiRouterPlugin/WikiRouter';
import { useUrlLauncher } from '@/plugins/UrlLauncherPlugin/UrlLauncher';
const config = useConfig();
const $messages = useMessages();
Expand Down Expand Up @@ -129,12 +129,12 @@ const error = computed( () => {
return null;
} );
const wikiRouter = useWikiRouter();
const urlLauncher = useUrlLauncher();
const onSubmit = async () => {
submitting.value = true;
try {
const lexemeId = await store.dispatch( CREATE_LEXEME );
await wikiRouter.goToTitle( `Special:EntityPage/${lexemeId}` );
const targetUrl = await store.dispatch( CREATE_LEXEME );
await urlLauncher.goToURL( targetUrl );
} catch {
// Error is already in store and handled by ErrorMessage component
}
Expand Down
4 changes: 2 additions & 2 deletions src/data-access/DevLexemeCreator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ export default class DevLexemeCreator implements LexemeCreator {
lemmaLanguageCode: string,
lexemeLanguageItemId: string,
lexicalCategoryItemId: string,
): Promise<string> {
): Promise<URL> {

await nextTick(); // let Vue update the DOM before blocking alert()
// eslint-disable-next-line no-alert
Expand All @@ -23,7 +23,7 @@ export default class DevLexemeCreator implements LexemeCreator {
} ];
return Promise.reject( errors );
}
return 'L1';
return new URL( window.origin + '/Special:EntityPage/L1' );
}

}
2 changes: 1 addition & 1 deletion src/data-access/LexemeCreator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,6 @@ export default interface LexemeCreator {
lemmaLanguageCode: string,
lexemeLanguageItemId: string,
lexicalCategoryItemId: string,
): Promise<string>;
): Promise<URL>;

}
15 changes: 11 additions & 4 deletions src/data-access/MwApiLexemeCreator.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import { MwApi } from '@/@types/mediawiki';
import { MwApi, MwUtilGetUrl } from '@/@types/mediawiki';
import LexemeCreator from '@/data-access/LexemeCreator';
import { SubmitError } from '@/store/RootState';

type WbEditEntityResponse = {
entity: {
id: string;
};
tempuserredirect: string;
};

type ApiResult = {
Expand All @@ -18,10 +19,12 @@ type ApiResult = {
export default class MwApiLexemeCreator implements LexemeCreator {

private api: MwApi;
private getUrl: MwUtilGetUrl;
private tags: string[];

public constructor( api: MwApi, tags: string[] = [] ) {
public constructor( api: MwApi, getUrl: MwUtilGetUrl, tags: string[] = [] ) {
this.api = api;
this.getUrl = getUrl;
this.tags = tags;
}

Expand All @@ -30,7 +33,7 @@ export default class MwApiLexemeCreator implements LexemeCreator {
lemmaLanguageCode: string,
lexemeLanguageItemId: string,
lexicalCategoryItemId: string,
): Promise<string> {
): Promise<URL> {
const params = this.api.assertCurrentUser( {
action: 'wbeditentity',
new: 'lexeme',
Expand Down Expand Up @@ -73,7 +76,11 @@ export default class MwApiLexemeCreator implements LexemeCreator {
return Promise.reject( errors );
} );

return ( response as WbEditEntityResponse ).entity.id;
const entityResponse = response as WbEditEntityResponse;
if ( entityResponse.tempuserredirect !== undefined ) {
return new URL( entityResponse.tempuserredirect );
}
return new URL( this.getUrl( `Special:EntityPage/${entityResponse.entity.id}` ) );
}

}
8 changes: 4 additions & 4 deletions src/init.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import MwApiLexemeCreator from './data-access/MwApiLexemeCreator';
import MwMessagesRepository from './plugins/MessagesPlugin/MwMessagesRepository';
import { MediaWiki } from './@types/mediawiki';
import { ComponentPublicInstance } from 'vue';
import MediaWikiRouter from './plugins/WikiRouterPlugin/MediaWikiRouter';
import BrowserRedirectingUrlLauncher from '@/plugins/UrlLauncherPlugin/BrowserRedirectingUrlLauncher';
import MwApiLangCodeRetriever from './data-access/MwApiLangCodeRetriever';
import LanguageItemSearcher from '@/data-access/LanguageItemSearcher';
import MediaWikiAuthenticationLinker from '@/plugins/AuthenticationLinkerPlugin/MediaWikiAuthenticationLinker';
Expand All @@ -35,7 +35,7 @@ export default function init( config: InitConfig, mw: MediaWiki ): ComponentPubl
);
const langCodeRetriever = new MwApiLangCodeRetriever( api, mw.config.get( 'LexemeLanguageCodePropertyId' ) as string );
const messagesRepository = new MwMessagesRepository( mw.message );
const lexemeCreator = new MwApiLexemeCreator( api, config.tags );
const lexemeCreator = new MwApiLexemeCreator( api, mw.util.getUrl, config.tags );
const searchLinker = new MediaWikiSearchLinker(
mw.util.getUrl,
( mw.config.get( 'wgNamespaceIds' ) as Record<string, number> ).lexeme,
Expand All @@ -45,7 +45,7 @@ export default function init( config: InitConfig, mw: MediaWiki ): ComponentPubl
mw.config.get( 'wgPageName' ) as string,
);
const tracker = new MwTracker( mw.track );
const wikiRouter = new MediaWikiRouter( mw.util.getUrl );
const urlLauncher = new BrowserRedirectingUrlLauncher();

const services: Services = {
itemSearcher,
Expand All @@ -56,7 +56,7 @@ export default function init( config: InitConfig, mw: MediaWiki ): ComponentPubl
searchLinker,
authenticationLinker,
tracker,
wikiRouter,
urlLauncher,
};

return createAndMount( config, services );
Expand Down
8 changes: 4 additions & 4 deletions src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ import initStore from './store';
import App from './App.vue';
import Messages, { MessagesKey } from './plugins/MessagesPlugin/Messages';
import MessagesRepository from './plugins/MessagesPlugin/MessagesRepository';
import { WikiRouterKey } from './plugins/WikiRouterPlugin/WikiRouter';
import WikiRouter from './plugins/WikiRouterPlugin/WikiRouter';
import { UrlLauncherKey } from '@/plugins/UrlLauncherPlugin/UrlLauncher';
import UrlLauncher from '@/plugins/UrlLauncherPlugin/UrlLauncher';
import LangCodeRetriever from './data-access/LangCodeRetriever';
import { LanguageCodesProviderKey } from './plugins/LanguageCodesProviderPlugin/LanguageCodesProvider';
import { MapLanguageCodesProvider } from './data-access/LanguageCodesProvider';
Expand All @@ -38,7 +38,7 @@ export interface Services {
searchLinker: SearchLinker;
authenticationLinker: AuthenticationLinker;
tracker: Tracker;
wikiRouter: WikiRouter;
urlLauncher: UrlLauncher;
}

export default function createAndMount(
Expand All @@ -62,7 +62,7 @@ export default function createAndMount(
app.provide( LanguageItemSearchKey, services.languageItemSearcher );
app.provide( SearchLinkerKey, services.searchLinker );
app.provide( AuthenticationLinkerKey, services.authenticationLinker );
app.provide( WikiRouterKey, services.wikiRouter );
app.provide( UrlLauncherKey, services.urlLauncher );
app.provide(
LanguageCodesProviderKey,
languageCodesProvider,
Expand Down
17 changes: 17 additions & 0 deletions src/plugins/UrlLauncherPlugin/BrowserRedirectingUrlLauncher.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import UrlLauncher from './UrlLauncher';

/**
* The plugin performs a redirect away from the current
* page. It returns a promise that never returns, because
* the browser window reloads. In test contexts, this
* can be stubbed to make assertions about the target
* URL.
*/
export default class BrowserRedirectingUrlLauncher implements UrlLauncher {
public goToURL( url: URL ): Promise<never> {
window.location.href = url.toString();
return new Promise( ( _resolve ) => {
// never resolve
} );
}
}
Original file line number Diff line number Diff line change
@@ -1,23 +1,23 @@
import { inject, InjectionKey } from 'vue';

export default interface WikiRouter {
export default interface UrlLauncher {
/**
* Go to the wiki page with the given title.
* Go to the target URL
*
* @param title The title (with namespace, if any).
* @param target The target URL.
* @return A Promise that does not resolve until the navigation is finished.
* A real implementation should never resolve the promise,
* because by the time navigation finishes,
* the page that called this function will no longer be executing JavaScript.
* However, a dev implementation may resolve the promise.
*/
goToTitle( title: string ): Promise<void>;
goToURL( target: URL ): Promise<void>;
}

export const WikiRouterKey: InjectionKey<WikiRouter> = Symbol( 'WikiRouter' );
export const UrlLauncherKey: InjectionKey<UrlLauncher> = Symbol( 'UrlLauncher' );

export function useWikiRouter(): WikiRouter {
return inject( WikiRouterKey, () => {
throw new Error( 'No WikiRouter provided!' );
export function useUrlLauncher(): UrlLauncher {
return inject( UrlLauncherKey, () => {
throw new Error( 'No UrlLauncher provided!' );
}, true );
}
35 changes: 0 additions & 35 deletions src/plugins/WikiRouterPlugin/MediaWikiRouter.ts

This file was deleted.

2 changes: 1 addition & 1 deletion src/store/actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@ export default function createActions(

return formData;
},
async [ CREATE_LEXEME ]( { commit, dispatch }: RootContext ): Promise<string> {
async [ CREATE_LEXEME ]( { commit, dispatch }: RootContext ): Promise<URL> {
const {
validLemma,
validLanguageId,
Expand Down
4 changes: 2 additions & 2 deletions tests/integration/App.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import unusedLanguageCodesProvider from '../mocks/unusedLanguageCodesProvider';
import unusedTracker from '../mocks/unusedTracker';
import { SearchLinkerKey } from '@/plugins/SearchLinkerPlugin/SearchLinker';
import { Config, ConfigKey } from '@/plugins/ConfigPlugin/Config';
import { WikiRouterKey } from '@/plugins/WikiRouterPlugin/WikiRouter';
import { UrlLauncherKey } from '@/plugins/UrlLauncherPlugin/UrlLauncher';
import Messages, { MessagesKey } from '@/plugins/MessagesPlugin/Messages';
import { ItemSearchKey } from '@/plugins/ItemSearchPlugin/ItemSearch';
import DevItemSearcher from '@/data-access/DevItemSearcher';
Expand Down Expand Up @@ -67,7 +67,7 @@ describe( 'App.vue', () => {
lexemeNS,
),
[ AuthenticationLinkerKey as symbol ]: null,
[ WikiRouterKey as symbol ]: null,
[ UrlLauncherKey as symbol ]: null,
[ MessagesKey as symbol ]: new Messages( new DevMessagesRepository() ),
[ ItemSearchKey as symbol ]: new DevItemSearcher(),
[ LanguageItemSearchKey as symbol ]: new DevItemSearcher(),
Expand Down
Loading

0 comments on commit 2cfa3dd

Please sign in to comment.