Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Reverting handlebars #53

Merged
merged 46 commits into from
Jul 21, 2024
Merged
Show file tree
Hide file tree
Changes from 40 commits
Commits
Show all changes
46 commits
Select commit Hold shift + click to select a range
8e0d933
Reverting handlebars
Lan2u Jul 19, 2024
bb47c8c
member input selector back to html template
Lan2u Jul 19, 2024
0d72cdc
Template helpers back to using template strings
Lan2u Jul 19, 2024
447c284
Continuing to switch back to template strings not handlebars
Lan2u Jul 19, 2024
512511b
Equipment back to templates
Lan2u Jul 20, 2024
d25949b
Revert auth
Lan2u Jul 20, 2024
9cc74bd
area commands -> templates
Lan2u Jul 20, 2024
70ac0e2
Revert equipment forms to templates
Lan2u Jul 20, 2024
c1083e0
Revert member number linking form to templates
Lan2u Jul 20, 2024
fdcdee2
Update equipment to be more concise using pipe
Lan2u Jul 20, 2024
b3a5f9b
Revert members command
Lan2u Jul 20, 2024
0c58ed2
Revert super-user forms to handlebars
Lan2u Jul 20, 2024
b9efc7e
Revert trainers back to html template
Lan2u Jul 20, 2024
cf694bc
Revert http section back to html templates
Lan2u Jul 20, 2024
854c21e
all equipment -> back to html templates
Lan2u Jul 20, 2024
3a67374
Update equipment render to be nicer to read
Lan2u Jul 20, 2024
6426158
area render -> html template
Lan2u Jul 20, 2024
577e461
render areas -> html template
Lan2u Jul 20, 2024
30b56c4
Try allowing UUID in html templates
Lan2u Jul 20, 2024
f3cc92f
Use UUID rather than string so that we know it doesn't need sanitised
Lan2u Jul 20, 2024
bc9e6ec
Remove unneeded sanitise
Lan2u Jul 20, 2024
e51b66d
failed imports -> back to html template
Lan2u Jul 20, 2024
c168849
Allow empty string in html templates unsanitised
Lan2u Jul 20, 2024
027a3eb
Landing page back to html template
Lan2u Jul 20, 2024
7f7ab54
Render events back to html template
Lan2u Jul 20, 2024
cfbcdea
member page -> html template
Lan2u Jul 20, 2024
322f743
members -> html template
Lan2u Jul 20, 2024
bd78607
super users back to html template
Lan2u Jul 20, 2024
3028a4b
Export HtmlSubstitution type and use UUID in more places to fix type …
Lan2u Jul 20, 2024
0266518
Use UUID in more places so we can trace that its safe for templating
Lan2u Jul 20, 2024
43e9fb0
More references that should be UUID
Lan2u Jul 20, 2024
475f32f
Re-add memberInput usage
Lan2u Jul 20, 2024
68ae923
Re-add usage of memberInput
Lan2u Jul 20, 2024
90abd84
Fix unused export
Lan2u Jul 20, 2024
f2603eb
Need to type annotate safe() return because Safe was private
Lan2u Jul 20, 2024
4cb4e70
Fix isolated pages not being rendered as templates
Lan2u Jul 20, 2024
40b4b5e
Enforce that only rendered html gets returned
Lan2u Jul 20, 2024
89427f3
Fix areas retuning non-rendered html
Lan2u Jul 20, 2024
2b8a6fa
Mark titles safe or sanitise them
Lan2u Jul 20, 2024
3a0ef26
Simplify where we can
Lan2u Jul 20, 2024
69d7cb5
Update src/authentication/log-in-page.ts
Lan2u Jul 20, 2024
6fcd401
Apply suggestions from code review
Lan2u Jul 20, 2024
9d19a28
Use shared gridjs helper for add trainer form
Lan2u Jul 20, 2024
bbf9b2c
Things spotted during self review
Lan2u Jul 20, 2024
1d36732
Missing renderMemberNumber imports
Lan2u Jul 20, 2024
6545c1c
Merge branch 'main' into revert_handlebars
Lan2u Jul 21, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file modified bun.lockb
Binary file not shown.
1 change: 0 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,6 @@
"express-async-handler": "^1.2.0",
"fp-ts": "^2.11.8",
"googleapis": "^140.0.0",
"handlebars": "^4.7.8",
"http-status-codes": "^2.2.0",
"io-ts": "^2.2.20",
"io-ts-reporters": "^2.0.1",
Expand Down
3 changes: 2 additions & 1 deletion src/authentication/auth-routes.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import {Dependencies} from '../dependencies';
import {Safe, safe} from '../types/html';
import {Route, get, post} from '../types/route';
import {auth, callback, invalidLink, logIn, logOut} from './handlers';

export const logInPath = '/log-in';
export const logInPath: Safe = safe('/log-in');
const invalidLinkPath = '/auth/invalid-magic-link';

export const authRoutes = (deps: Dependencies): ReadonlyArray<Route> => {
Expand Down
24 changes: 9 additions & 15 deletions src/authentication/check-your-mail.ts
Original file line number Diff line number Diff line change
@@ -1,22 +1,16 @@
import Handlebars from 'handlebars';
import {pipe} from 'fp-ts/lib/function';
import {isolatedPageTemplate} from '../templates/page-template';
import {html, safe, sanitizeString} from '../types/html';

const CHECK_YOUR_MAIL_TEMPLATE = Handlebars.compile(
`
export const checkYourMailPage = (submittedEmailAddress: string) =>
pipe(
html`
<h1>Check your mail</h1>
<p>
If <b>{{submittedEmailAddress}}</b> is linked to a Makespace number you
should receive an email with that number.
If <b>${sanitizeString(submittedEmailAddress)}</b> is linked to a
Makespace number you should receive an email with that number.
</p>
<p>If nothing happens please reach out to the Makespace Database Team.</p>
`
);

export const checkYourMailPage = (submittedEmailAddress: string) =>
isolatedPageTemplate('Check your mail')(
new Handlebars.SafeString(
CHECK_YOUR_MAIL_TEMPLATE({
submittedEmailAddress,
})
)
`,
isolatedPageTemplate(safe('Check your mail'))
);
47 changes: 27 additions & 20 deletions src/authentication/handlers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,35 +11,42 @@ import {logInPage} from './log-in-page';
import {checkYourMailPage} from './check-your-mail';
import {oopsPage} from '../templates';
import {StatusCodes} from 'http-status-codes';
import {SafeString} from 'handlebars';
import {getUserFromSession} from './get-user-from-session';
import {Dependencies} from '../dependencies';
import {
html,
HtmlSubstitution,
RenderedHtml,
sanitizeString,
} from '../types/html';

export const logIn = (deps: Dependencies) => (req: Request, res: Response) => {
pipe(
req.session,
getUserFromSession(deps),
O.match(
() => {
res.status(StatusCodes.OK).send(logInPage);
},
_user => res.redirect('/')
)
);
};
export const logIn =
(deps: Dependencies) => (req: Request, res: Response<RenderedHtml>) => {
pipe(
req.session,
getUserFromSession(deps),
O.match(
() => {
res.status(StatusCodes.OK).send(logInPage);
},
_user => res.redirect('/')
)
);
};

export const logOut = (req: Request, res: Response) => {
export const logOut = (req: Request, res: Response<RenderedHtml>) => {
req.session = null;
res.redirect('/');
};

export const auth = (req: Request, res: Response) => {
export const auth = (req: Request, res: Response<RenderedHtml>) => {
pipe(
req.body,
parseEmailAddressFromBody,
E.mapLeft(() => "You entered something that isn't a valid email address"),
E.matchW(
msg => res.status(StatusCodes.BAD_REQUEST).send(oopsPage(msg)),
msg =>
res.status(StatusCodes.BAD_REQUEST).send(oopsPage(sanitizeString(msg))),
email => {
publish('send-log-in-link', email);
res.status(StatusCodes.ACCEPTED).send(checkYourMailPage(email));
Expand All @@ -49,14 +56,14 @@ export const auth = (req: Request, res: Response) => {
};

export const invalidLink =
(logInPath: string) => (req: Request, res: Response) => {
(logInPath: HtmlSubstitution) =>
(req: Request, res: Response<RenderedHtml>) => {
res
.status(StatusCodes.UNAUTHORIZED)
.send(
oopsPage(
new SafeString(
`The link you have used is (no longer) valid. Go back to the <a href=${logInPath}>log in</a>`
)
html`The link you have used is (no longer) valid. Go back to the
<a href=${logInPath}>log in</a>`
)
);
};
Expand Down
28 changes: 13 additions & 15 deletions src/authentication/log-in-page.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,16 @@
import Handlebars, {SafeString} from 'handlebars';
import {pipe} from 'fp-ts/lib/function';
import {html, safe} from '../types/html';
import {isolatedPageTemplate} from '../templates/page-template';

const LOGIN_PAGE_TEMPLATE = Handlebars.compile(
`
<h1>Log in</h1>
<form action="/auth" method="post">
<label for="email">E-Mail: </label>
<input id="email" type="email" required name="email" value="" />
<p>We will email you a magic log in link.</p>
<button type="submit">Email me a link</button>
</form>
`
);

export const logInPage = isolatedPageTemplate('MakeSpace Members App')(
new SafeString(LOGIN_PAGE_TEMPLATE({}))
export const logInPage = pipe(
html`
<h1>Log in</h1>
<form action="/auth" method="post">
<label for="email">E-Mail: </label>
<input id="email" type="email" required name="email" value="" />
<p>We will email you a magic log in link.</p>
<button type="submit">Email me a link</button>
</form>
`,
isolatedPageTemplate(safe('Login'))
Lan2u marked this conversation as resolved.
Show resolved Hide resolved
);
8 changes: 2 additions & 6 deletions src/commands/area/add-owner-form.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@ import {
import {Form} from '../../types/form';
import {AreaOwners} from '../../read-models/members/get-potential-owners';
import {readModels} from '../../read-models';
import {pageTemplateHandlebarlessBody} from '../../templates/page-template';
import {html, joinHtml, safe, sanitizeString} from '../../types/html';
import {Member} from '../../read-models/members/member';
import {pageTemplate} from '../../templates';

type ViewModel = {
user: User;
Expand Down Expand Up @@ -108,11 +108,7 @@ const renderBody = (viewModel: ViewModel) => html`
`;

const renderForm = (viewModel: ViewModel) =>
pipe(
viewModel,
renderBody,
pageTemplateHandlebarlessBody('Add Owner', viewModel.user)
);
pipe(viewModel, renderBody, pageTemplate(safe('Add Owner'), viewModel.user));

const paramsCodec = t.strict({
area: t.string,
Expand Down
29 changes: 11 additions & 18 deletions src/commands/area/create-form.ts
Original file line number Diff line number Diff line change
@@ -1,36 +1,29 @@
import * as E from 'fp-ts/Either';
import {pageTemplate} from '../../templates';
import {User} from '../../types';
import {v4} from 'uuid';
import {Form} from '../../types/form';
import Handlebars, {SafeString} from 'handlebars';
import {pipe} from 'fp-ts/lib/function';
import {html, safe} from '../../types/html';
import {v4} from 'uuid';
import {UUID} from 'io-ts-types';

type ViewModel = {
user: User;
};

const CREATE_FORM_TEMPLATE = Handlebars.compile(
`
const renderForm = (viewModel: ViewModel) =>
pipe(
viewModel,
() => html`
<h1>Create an area</h1>
<form action="#" method="post">
<label for="name">What is this area called</label>
<input type="text" name="name" id="name" />
<input type="hidden" name="id" value="{{areaId}}" />
<input type="hidden" name="id" value="${v4() as UUID}" />
<button type="submit">Confirm and send</button>
</form>
`
);

const renderForm = (viewModel: ViewModel) =>
pageTemplate(
'Create Area',
viewModel.user
)(
new SafeString(
CREATE_FORM_TEMPLATE({
areaId: v4(),
})
)
`,
pageTemplate(safe('Create Area'), viewModel.user)
);

export const createForm: Form<ViewModel> = {
Expand Down
41 changes: 19 additions & 22 deletions src/commands/equipment/add-form.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,49 +2,47 @@ import {pipe} from 'fp-ts/lib/function';
import * as t from 'io-ts';
import * as E from 'fp-ts/Either';
import {pageTemplate} from '../../templates';
import {html, safe, sanitizeString} from '../../types/html';
import {DomainEvent, User} from '../../types';
import {v4} from 'uuid';
import {Form} from '../../types/form';
import {formatValidationErrors} from 'io-ts-reporters';
import {failureWithStatus} from '../../types/failure-with-status';
import {StatusCodes} from 'http-status-codes';
import {readModels} from '../../read-models';
import Handlebars, {SafeString} from 'handlebars';
import {UUID} from 'io-ts-types';

type ViewModel = {
user: User;
areaId: string;
areaId: UUID;
areaName: string;
newEquipmentId: string;
};

const RENDER_ADD_EQUIPMENT_FORM_TEMPLATE = Handlebars.compile(`
<h1>Add equipment to {{areaName}}</h1>
<form action="/equipment/add" method="post">
<label for="name">What is this Equipment called</label>
<input type="text" name="name" id="name" />
<input type="hidden" name="id" value="{{newEquipmentId}}" />
<input type="hidden" name="areaId" value="{{areaId}}" />
<button type="submit">Confirm and send</button>
</form>
`);

const renderForm = (viewModel: ViewModel) =>
pageTemplate(
'Create Equipment',
viewModel.user
)(new SafeString(RENDER_ADD_EQUIPMENT_FORM_TEMPLATE(viewModel)));
pipe(
html`
<h1>Add equipment to ${sanitizeString(viewModel.areaName)}</h1>
<form action="/equipment/add" method="post">
<label for="name">What is this Equipment called</label>
<input type="text" name="name" id="name" />
<input type="hidden" name="id" value="${v4() as UUID}" />
<input type="hidden" name="areaId" value="${viewModel.areaId}" />
<button type="submit">Confirm and send</button>
</form>
`,
pageTemplate(safe('Create Equipment'), viewModel.user)
);

const getAreaId = (input: unknown) =>
pipe(
input,
t.strict({area: t.string}).decode,
t.strict({area: UUID}).decode,
E.mapLeft(formatValidationErrors),
E.mapLeft(failureWithStatus('Invalid parameters', StatusCodes.BAD_REQUEST)),
E.map(({area}) => area)
);

const getAreaName = (events: ReadonlyArray<DomainEvent>, areaId: string) =>
const getAreaName = (events: ReadonlyArray<DomainEvent>, areaId: UUID) =>
pipe(
areaId,
readModels.areas.getArea(events),
Expand All @@ -61,8 +59,7 @@ const constructForm: Form<ViewModel>['constructForm'] =
E.Do,
E.bind('areaId', () => getAreaId(input)),
E.bind('areaName', ({areaId}) => getAreaName(events, areaId)),
E.bind('user', () => E.right(user)),
E.bind('newEquipmentId', () => E.right(v4()))
E.bind('user', () => E.right(user))
);

export const addForm: Form<ViewModel> = {
Expand Down
3 changes: 2 additions & 1 deletion src/commands/equipment/get-equipment-id-from-form.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
import {pipe} from 'fp-ts/lib/function';
import * as t from 'io-ts';
import * as tt from 'io-ts-types';
Lan2u marked this conversation as resolved.
Show resolved Hide resolved
import * as E from 'fp-ts/Either';
import {formatValidationErrors} from 'io-ts-reporters';
import {failureWithStatus} from '../../types/failure-with-status';
import {StatusCodes} from 'http-status-codes';

const getEquipmentIdCodec = t.strict({
equipmentId: t.string,
equipmentId: tt.UUID,
Lan2u marked this conversation as resolved.
Show resolved Hide resolved
});

export const getEquipmentIdFromForm = (input: unknown) =>
Expand Down
27 changes: 13 additions & 14 deletions src/commands/equipment/register-training-sheet-form.ts
Original file line number Diff line number Diff line change
@@ -1,39 +1,38 @@
import {pipe} from 'fp-ts/lib/function';
import * as E from 'fp-ts/Either';
import {html, safe, sanitizeString} from '../../types/html';
import {User} from '../../types';
import {Form} from '../../types/form';
import {pageTemplate} from '../../templates';
import {getEquipmentName} from './get-equipment-name';
import {getEquipmentIdFromForm} from './get-equipment-id-from-form';
import Handlebars, {SafeString} from 'handlebars';
import {UUID} from 'io-ts-types';

type ViewModel = {
user: User;
equipmentId: string;
equipmentId: UUID;
equipmentName: string;
};

const RENDER_REGISTER_TRAINING_SHEET_TEMPLATE = Handlebars.compile(
`
<h1>Register training sheet for {{equipmentName}}</h1>
const renderForm = (viewModel: ViewModel) =>
pipe(
html`
<h1>
Register training sheet for ${sanitizeString(viewModel.equipmentName)}
</h1>
<form action="/equipment/add-training-sheet" method="post">
<label for="trainingSheetId">What is the sheet id?</label>
<input type="text" name="trainingSheetId" id="trainingSheetId" />
<input
type="hidden"
name="equipmentId"
value="{{equipmentId}}"
value="${viewModel.equipmentId}"
/>
<button type="submit">Confirm and send</button>
</form>
`
);

const renderForm = (viewModel: ViewModel) =>
pageTemplate(
'Register training sheet',
viewModel.user
)(new SafeString(RENDER_REGISTER_TRAINING_SHEET_TEMPLATE(viewModel)));
`,
pageTemplate(safe('Register training sheet'), viewModel.user)
);

const constructForm: Form<ViewModel>['constructForm'] =
input =>
Expand Down
Loading