Add formatViewData to response object to fix tests and prepare for async navigation
This commit is contained in:
parent
366e48757e
commit
d6b530d16c
@ -198,9 +198,9 @@ export default abstract class Application implements Extendable<ApplicationCompo
|
||||
error_instructions: httpError.instructions,
|
||||
error_id: errorId,
|
||||
};
|
||||
res.render('errors/' + httpError.errorCode, locals, (err: Error | undefined, html) => {
|
||||
res.formatViewData('errors/' + httpError.errorCode, locals, (err: Error | undefined, html) => {
|
||||
if (err) {
|
||||
res.render('templates/ErrorTemplate', locals);
|
||||
res.formatViewData('templates/ErrorTemplate', locals);
|
||||
} else {
|
||||
res.send(html);
|
||||
}
|
||||
|
@ -148,10 +148,10 @@ export default class TestApp extends Application {
|
||||
this.use(new class extends Controller {
|
||||
public routes(): void {
|
||||
this.get('/', (req, res) => {
|
||||
res.render('home');
|
||||
res.formatViewData('home');
|
||||
}, 'home');
|
||||
this.get('/tests', (req, res) => {
|
||||
res.render('tests');
|
||||
res.formatViewData('tests');
|
||||
}, 'tests');
|
||||
this.get('/design', (req, res) => {
|
||||
req.flash('success', 'Success.');
|
||||
@ -159,7 +159,7 @@ export default class TestApp extends Application {
|
||||
req.flash('warning', 'Warning.');
|
||||
req.flash('error', 'Error.');
|
||||
req.flash('error-alert', 'Error alert.');
|
||||
res.render('design');
|
||||
res.formatViewData('design');
|
||||
}, 'design');
|
||||
}
|
||||
}());
|
||||
|
@ -57,7 +57,7 @@ export default class AccountController extends Controller {
|
||||
const nameChangedAt = nameComponent?.getNameChangedAt()?.getTime() || Date.now();
|
||||
const nameChangeRemainingTime = new Date(nameChangedAt + nameChangeWaitPeriod);
|
||||
|
||||
res.render('auth/account/account', {
|
||||
res.formatViewData('auth/account/account', {
|
||||
user_personal_info_fields: user.getPersonalInfoFields(),
|
||||
main_email: await user.mainEmail.get(),
|
||||
emails: await user.emails.get(),
|
||||
|
@ -35,7 +35,7 @@ export default class AuthController extends Controller {
|
||||
|
||||
const userModelFactory = ModelFactory.get(User);
|
||||
const hasUsername = userModelFactory.hasComponent(UserNameComponent);
|
||||
res.render('auth/auth', {
|
||||
res.formatViewData('auth/auth', {
|
||||
auth_methods: authGuard.getAuthMethodNames(),
|
||||
has_username: hasUsername,
|
||||
register_with_password: hasUsername && userModelFactory.hasComponent(UserPasswordComponent),
|
||||
|
@ -147,7 +147,7 @@ export default class MagicLinkController<A extends Application> extends Controll
|
||||
return;
|
||||
}
|
||||
|
||||
res.render('magic_link_lobby', {
|
||||
res.formatViewData('magic_link_lobby', {
|
||||
email: validLink.getOrFail('email'),
|
||||
type: validLink.getOrFail('action_type'),
|
||||
validUntil: validLink.getExpirationDate().getTime(),
|
||||
@ -179,7 +179,7 @@ export default class MagicLinkController<A extends Application> extends Controll
|
||||
}
|
||||
}
|
||||
|
||||
res.render('magic_link', {
|
||||
res.formatViewData('magic_link', {
|
||||
magicLink: magicLink,
|
||||
err: err,
|
||||
success: success && err === null,
|
||||
|
@ -48,6 +48,26 @@ export default class ExpressAppComponent extends ApplicationComponent {
|
||||
if (!middleware) throw new Error('Middleware ' + type.name + ' not present in this request.');
|
||||
return middleware as M;
|
||||
};
|
||||
res.formatViewData = function (
|
||||
viewName: string,
|
||||
data?: Record<string, unknown>,
|
||||
callback?: (err: Error, html: string) => void,
|
||||
) {
|
||||
this.format({
|
||||
html: () => {
|
||||
this.render(viewName, data, callback);
|
||||
},
|
||||
json: () => {
|
||||
if (typeof data === 'undefined') data = {};
|
||||
const serialized = JSON.stringify({...data, viewName}, (key, value) => {
|
||||
if (key.startsWith('_') || typeof value === 'function') return undefined;
|
||||
else return value;
|
||||
});
|
||||
this.contentType('application/json');
|
||||
this.send(serialized);
|
||||
},
|
||||
});
|
||||
};
|
||||
next();
|
||||
});
|
||||
}
|
||||
|
@ -53,7 +53,7 @@ export default class BackendController extends Controller {
|
||||
}
|
||||
|
||||
protected async getIndex(req: Request, res: Response): Promise<void> {
|
||||
res.render('backend/index', {
|
||||
res.formatViewData('backend/index', {
|
||||
menu: await Promise.all(BackendController.menu.map(async m => ({
|
||||
link: await m.getLink(),
|
||||
display_string: await m.getDisplayString(),
|
||||
@ -66,7 +66,7 @@ export default class BackendController extends Controller {
|
||||
const accounts = await User.paginate(req, 20, User.select()
|
||||
.where('approved', 0)
|
||||
.with('mainEmail'));
|
||||
res.render('backend/accounts_approval', {
|
||||
res.formatViewData('backend/accounts_approval', {
|
||||
accounts: accounts.map(account => Object.assign({
|
||||
mainEmailStr: account.mainEmail.getOrFail()?.email,
|
||||
created_at_iso: account.created_at?.toISOString(),
|
||||
|
@ -7,8 +7,8 @@ export default class MailController extends Controller {
|
||||
this.get("/mail/:template", this.getMail, 'mail');
|
||||
}
|
||||
|
||||
protected async getMail(request: Request, response: Response): Promise<void> {
|
||||
protected async getMail(request: Request, res: Response): Promise<void> {
|
||||
const template = request.params['template'];
|
||||
response.render(`mails/${template}.mnjk`, request.query);
|
||||
res.formatViewData(`mails/${template}.mnjk`, request.query);
|
||||
}
|
||||
}
|
||||
|
6
src/types/Express.d.ts
vendored
6
src/types/Express.d.ts
vendored
@ -36,6 +36,12 @@ declare global {
|
||||
|
||||
export interface Response {
|
||||
setLazyLocal(key: string, valueProvider: () => unknown): void;
|
||||
|
||||
formatViewData(
|
||||
viewName: string,
|
||||
data?: Record<string, unknown>,
|
||||
callback?: (err: Error, html: string) => void,
|
||||
): void;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -142,6 +142,7 @@ describe('Authenticate with email (magic_link)', () => {
|
||||
|
||||
// Authenticate
|
||||
await agent.post('/auth/login?' + querystring.stringify({redirect_uri: '/redirect-uri'}))
|
||||
.accept('json')
|
||||
.set('Cookie', cookies)
|
||||
.send({
|
||||
csrf: csrf,
|
||||
|
@ -35,6 +35,7 @@ describe('Test CSRF protection', () => {
|
||||
test('no csrf token should be in session at first', (done) => {
|
||||
const agent = supertest(app.getExpressApp());
|
||||
agent.post('/')
|
||||
.accept('json')
|
||||
.expect(401)
|
||||
.then(res => {
|
||||
expect(res.text).toContain(`You weren't assigned any CSRF token.`);
|
||||
@ -55,6 +56,7 @@ describe('Test CSRF protection', () => {
|
||||
|
||||
const agent = supertest(app.getExpressApp());
|
||||
agent.post('/')
|
||||
.accept('json')
|
||||
.set('Cookie', cookies)
|
||||
.expect(401)
|
||||
.then((res) => {
|
||||
@ -68,6 +70,7 @@ describe('Test CSRF protection', () => {
|
||||
|
||||
const agent = supertest(app.getExpressApp());
|
||||
agent.post('/')
|
||||
.accept('json')
|
||||
.set('Cookie', cookies)
|
||||
.set('Content-Type', 'application/json')
|
||||
.send({csrf: 'not_a_valid_csrf'})
|
||||
|
@ -23,8 +23,10 @@ export async function followMagicLinkFromMail(
|
||||
expect(query).toBeDefined();
|
||||
|
||||
await agent.get('/magic/link?' + query)
|
||||
.accept('json')
|
||||
.expect(200);
|
||||
await agent.get('/magic/lobby')
|
||||
.accept('json')
|
||||
.set('Cookie', cookies)
|
||||
.expect(302)
|
||||
.expect('Location', expectedRedirectUrl);
|
||||
@ -55,7 +57,7 @@ export function authAppProvider(withUsername: boolean = true, approvalMode: bool
|
||||
this.use(new class extends Controller {
|
||||
public routes(): void {
|
||||
this.get('/', (req, res) => {
|
||||
res.render('home');
|
||||
res.formatViewData('home');
|
||||
}, 'home');
|
||||
this.get('/csrf', (req, res) => {
|
||||
res.send(this.getApp().as(CsrfProtectionComponent).getSessionCsrfToken(req.getSession()));
|
||||
|
Loading…
Reference in New Issue
Block a user