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_instructions: httpError.instructions,
|
||||||
error_id: errorId,
|
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) {
|
if (err) {
|
||||||
res.render('templates/ErrorTemplate', locals);
|
res.formatViewData('templates/ErrorTemplate', locals);
|
||||||
} else {
|
} else {
|
||||||
res.send(html);
|
res.send(html);
|
||||||
}
|
}
|
||||||
|
@ -148,10 +148,10 @@ export default class TestApp extends Application {
|
|||||||
this.use(new class extends Controller {
|
this.use(new class extends Controller {
|
||||||
public routes(): void {
|
public routes(): void {
|
||||||
this.get('/', (req, res) => {
|
this.get('/', (req, res) => {
|
||||||
res.render('home');
|
res.formatViewData('home');
|
||||||
}, 'home');
|
}, 'home');
|
||||||
this.get('/tests', (req, res) => {
|
this.get('/tests', (req, res) => {
|
||||||
res.render('tests');
|
res.formatViewData('tests');
|
||||||
}, 'tests');
|
}, 'tests');
|
||||||
this.get('/design', (req, res) => {
|
this.get('/design', (req, res) => {
|
||||||
req.flash('success', 'Success.');
|
req.flash('success', 'Success.');
|
||||||
@ -159,7 +159,7 @@ export default class TestApp extends Application {
|
|||||||
req.flash('warning', 'Warning.');
|
req.flash('warning', 'Warning.');
|
||||||
req.flash('error', 'Error.');
|
req.flash('error', 'Error.');
|
||||||
req.flash('error-alert', 'Error alert.');
|
req.flash('error-alert', 'Error alert.');
|
||||||
res.render('design');
|
res.formatViewData('design');
|
||||||
}, 'design');
|
}, 'design');
|
||||||
}
|
}
|
||||||
}());
|
}());
|
||||||
|
@ -57,7 +57,7 @@ export default class AccountController extends Controller {
|
|||||||
const nameChangedAt = nameComponent?.getNameChangedAt()?.getTime() || Date.now();
|
const nameChangedAt = nameComponent?.getNameChangedAt()?.getTime() || Date.now();
|
||||||
const nameChangeRemainingTime = new Date(nameChangedAt + nameChangeWaitPeriod);
|
const nameChangeRemainingTime = new Date(nameChangedAt + nameChangeWaitPeriod);
|
||||||
|
|
||||||
res.render('auth/account/account', {
|
res.formatViewData('auth/account/account', {
|
||||||
user_personal_info_fields: user.getPersonalInfoFields(),
|
user_personal_info_fields: user.getPersonalInfoFields(),
|
||||||
main_email: await user.mainEmail.get(),
|
main_email: await user.mainEmail.get(),
|
||||||
emails: await user.emails.get(),
|
emails: await user.emails.get(),
|
||||||
|
@ -35,7 +35,7 @@ export default class AuthController extends Controller {
|
|||||||
|
|
||||||
const userModelFactory = ModelFactory.get(User);
|
const userModelFactory = ModelFactory.get(User);
|
||||||
const hasUsername = userModelFactory.hasComponent(UserNameComponent);
|
const hasUsername = userModelFactory.hasComponent(UserNameComponent);
|
||||||
res.render('auth/auth', {
|
res.formatViewData('auth/auth', {
|
||||||
auth_methods: authGuard.getAuthMethodNames(),
|
auth_methods: authGuard.getAuthMethodNames(),
|
||||||
has_username: hasUsername,
|
has_username: hasUsername,
|
||||||
register_with_password: hasUsername && userModelFactory.hasComponent(UserPasswordComponent),
|
register_with_password: hasUsername && userModelFactory.hasComponent(UserPasswordComponent),
|
||||||
|
@ -147,7 +147,7 @@ export default class MagicLinkController<A extends Application> extends Controll
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
res.render('magic_link_lobby', {
|
res.formatViewData('magic_link_lobby', {
|
||||||
email: validLink.getOrFail('email'),
|
email: validLink.getOrFail('email'),
|
||||||
type: validLink.getOrFail('action_type'),
|
type: validLink.getOrFail('action_type'),
|
||||||
validUntil: validLink.getExpirationDate().getTime(),
|
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,
|
magicLink: magicLink,
|
||||||
err: err,
|
err: err,
|
||||||
success: success && err === null,
|
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.');
|
if (!middleware) throw new Error('Middleware ' + type.name + ' not present in this request.');
|
||||||
return middleware as M;
|
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();
|
next();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -53,7 +53,7 @@ export default class BackendController extends Controller {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected async getIndex(req: Request, res: Response): Promise<void> {
|
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 => ({
|
menu: await Promise.all(BackendController.menu.map(async m => ({
|
||||||
link: await m.getLink(),
|
link: await m.getLink(),
|
||||||
display_string: await m.getDisplayString(),
|
display_string: await m.getDisplayString(),
|
||||||
@ -66,7 +66,7 @@ export default class BackendController extends Controller {
|
|||||||
const accounts = await User.paginate(req, 20, User.select()
|
const accounts = await User.paginate(req, 20, User.select()
|
||||||
.where('approved', 0)
|
.where('approved', 0)
|
||||||
.with('mainEmail'));
|
.with('mainEmail'));
|
||||||
res.render('backend/accounts_approval', {
|
res.formatViewData('backend/accounts_approval', {
|
||||||
accounts: accounts.map(account => Object.assign({
|
accounts: accounts.map(account => Object.assign({
|
||||||
mainEmailStr: account.mainEmail.getOrFail()?.email,
|
mainEmailStr: account.mainEmail.getOrFail()?.email,
|
||||||
created_at_iso: account.created_at?.toISOString(),
|
created_at_iso: account.created_at?.toISOString(),
|
||||||
|
@ -7,8 +7,8 @@ export default class MailController extends Controller {
|
|||||||
this.get("/mail/:template", this.getMail, 'mail');
|
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'];
|
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 {
|
export interface Response {
|
||||||
setLazyLocal(key: string, valueProvider: () => unknown): void;
|
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
|
// Authenticate
|
||||||
await agent.post('/auth/login?' + querystring.stringify({redirect_uri: '/redirect-uri'}))
|
await agent.post('/auth/login?' + querystring.stringify({redirect_uri: '/redirect-uri'}))
|
||||||
|
.accept('json')
|
||||||
.set('Cookie', cookies)
|
.set('Cookie', cookies)
|
||||||
.send({
|
.send({
|
||||||
csrf: csrf,
|
csrf: csrf,
|
||||||
|
@ -35,6 +35,7 @@ describe('Test CSRF protection', () => {
|
|||||||
test('no csrf token should be in session at first', (done) => {
|
test('no csrf token should be in session at first', (done) => {
|
||||||
const agent = supertest(app.getExpressApp());
|
const agent = supertest(app.getExpressApp());
|
||||||
agent.post('/')
|
agent.post('/')
|
||||||
|
.accept('json')
|
||||||
.expect(401)
|
.expect(401)
|
||||||
.then(res => {
|
.then(res => {
|
||||||
expect(res.text).toContain(`You weren't assigned any CSRF token.`);
|
expect(res.text).toContain(`You weren't assigned any CSRF token.`);
|
||||||
@ -55,6 +56,7 @@ describe('Test CSRF protection', () => {
|
|||||||
|
|
||||||
const agent = supertest(app.getExpressApp());
|
const agent = supertest(app.getExpressApp());
|
||||||
agent.post('/')
|
agent.post('/')
|
||||||
|
.accept('json')
|
||||||
.set('Cookie', cookies)
|
.set('Cookie', cookies)
|
||||||
.expect(401)
|
.expect(401)
|
||||||
.then((res) => {
|
.then((res) => {
|
||||||
@ -68,6 +70,7 @@ describe('Test CSRF protection', () => {
|
|||||||
|
|
||||||
const agent = supertest(app.getExpressApp());
|
const agent = supertest(app.getExpressApp());
|
||||||
agent.post('/')
|
agent.post('/')
|
||||||
|
.accept('json')
|
||||||
.set('Cookie', cookies)
|
.set('Cookie', cookies)
|
||||||
.set('Content-Type', 'application/json')
|
.set('Content-Type', 'application/json')
|
||||||
.send({csrf: 'not_a_valid_csrf'})
|
.send({csrf: 'not_a_valid_csrf'})
|
||||||
|
@ -23,8 +23,10 @@ export async function followMagicLinkFromMail(
|
|||||||
expect(query).toBeDefined();
|
expect(query).toBeDefined();
|
||||||
|
|
||||||
await agent.get('/magic/link?' + query)
|
await agent.get('/magic/link?' + query)
|
||||||
|
.accept('json')
|
||||||
.expect(200);
|
.expect(200);
|
||||||
await agent.get('/magic/lobby')
|
await agent.get('/magic/lobby')
|
||||||
|
.accept('json')
|
||||||
.set('Cookie', cookies)
|
.set('Cookie', cookies)
|
||||||
.expect(302)
|
.expect(302)
|
||||||
.expect('Location', expectedRedirectUrl);
|
.expect('Location', expectedRedirectUrl);
|
||||||
@ -55,7 +57,7 @@ export function authAppProvider(withUsername: boolean = true, approvalMode: bool
|
|||||||
this.use(new class extends Controller {
|
this.use(new class extends Controller {
|
||||||
public routes(): void {
|
public routes(): void {
|
||||||
this.get('/', (req, res) => {
|
this.get('/', (req, res) => {
|
||||||
res.render('home');
|
res.formatViewData('home');
|
||||||
}, 'home');
|
}, 'home');
|
||||||
this.get('/csrf', (req, res) => {
|
this.get('/csrf', (req, res) => {
|
||||||
res.send(this.getApp().as(CsrfProtectionComponent).getSessionCsrfToken(req.getSession()));
|
res.send(this.getApp().as(CsrfProtectionComponent).getSessionCsrfToken(req.getSession()));
|
||||||
|
Loading…
Reference in New Issue
Block a user