Skip to content

Commit

Permalink
Allow queries to return redirects #26
Browse files Browse the repository at this point in the history
  • Loading branch information
chromy committed Jun 21, 2024
1 parent 1be82c7 commit 7dd0327
Show file tree
Hide file tree
Showing 18 changed files with 102 additions and 35 deletions.
Binary file modified bun.lockb
Binary file not shown.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@
"@types/nodemailer-smtp-transport": "^2.7.5",
"@types/pubsub-js": "^1.8.3",
"@typescript-eslint/parser": "^7.0.0",
"@unsplash/sum-types": "^0.4.1",
"cookie-session": "^2.1.0",
"express": "^4.17.3",
"express-async-handler": "^1.2.0",
Expand Down
6 changes: 6 additions & 0 deletions src/http/http-response-to-express.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
//export const toExpress(response: HttpResponse) => (res: Response) => {
//// switch (response.kind) {
//// case 'page':
//// res.
//// }
//};
14 changes: 7 additions & 7 deletions src/http/query-get.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,14 @@ import {Request, Response} from 'express';
import {getUserFromSession} from '../authentication';
import {failureWithStatus} from '../types/failureWithStatus';
import {StatusCodes} from 'http-status-codes';
import {User} from '../types';
import {oopsPage, pageTemplate} from '../templates';
import {User, HttpResponse} from '../types';
import {oopsPage, templatePage} from '../templates';
import {Params, Query} from '../queries/query';
import {logInPath} from '../authentication/auth-routes';

const buildPage =
(deps: Dependencies, params: Params, query: Query) => (user: User) =>
pipe(
query(deps)(user, params),
TE.map(({title, body}) => pageTemplate(title, O.some(user))(body))
);
pipe(query(deps)(user, params), TE.map(templatePage(O.some(user))));

export const queryGet =
(deps: Dependencies, query: Query) => async (req: Request, res: Response) => {
Expand All @@ -34,7 +31,10 @@ export const queryGet =
? res.redirect(logInPath)
: res.status(failure.status).send(oopsPage(failure.message));
},
page => res.status(200).send(page)
HttpResponse.match({
Page: ({body}) => res.status(200).send(body),
Redirect: ({url}) => res.redirect(url),
})
)
)();
};
11 changes: 7 additions & 4 deletions src/queries/all-equipment/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,17 @@ import * as TE from 'fp-ts/TaskEither';
import {render} from './render';
import {constructViewModel} from './construct-view-model';
import {Query} from '../query';
import {HttpResponse} from '../../types';

export const allEquipment: Query = deps => user =>
pipe(
user,
constructViewModel(deps),
TE.map(render),
TE.map(body => ({
title: 'Equipment',
body,
}))
TE.map(body =>
HttpResponse.mk.Page({
title: 'Equipment',
body,
})
)
);
11 changes: 7 additions & 4 deletions src/queries/area/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {render} from './render';
import * as E from 'fp-ts/Either';
import {formatValidationErrors} from 'io-ts-reporters';
import {Query} from '../query';
import {HttpResponse} from '../../types';

const invalidParams = flow(
formatValidationErrors,
Expand All @@ -22,8 +23,10 @@ export const area: Query = deps => (user, params) =>
E.map(params => params.area),
TE.fromEither,
TE.chain(areaId => constructViewModel(deps)(areaId, user)),
TE.map(viewModel => ({
title: viewModel.area.name,
body: render(viewModel),
}))
TE.map(viewModel =>
HttpResponse.mk.Page({
title: viewModel.area.name,
body: render(viewModel),
})
)
);
3 changes: 2 additions & 1 deletion src/queries/areas/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,12 @@ import * as TE from 'fp-ts/TaskEither';
import {render} from './render';
import {constructViewModel} from './construct-view-model';
import {Query} from '../query';
import {HttpResponse} from '../../types';

export const areas: Query = deps => user =>
pipe(
user,
constructViewModel(deps),
TE.map(render),
TE.map(body => ({title: 'Areas', body}))
TE.map(body => HttpResponse.mk.Page({title: 'Areas', body}))
);
11 changes: 7 additions & 4 deletions src/queries/equipment/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {render} from './render';
import * as E from 'fp-ts/Either';
import {formatValidationErrors} from 'io-ts-reporters';
import {Query} from '../query';
import {HttpResponse} from '../../types';

const invalidParams = flow(
formatValidationErrors,
Expand All @@ -22,8 +23,10 @@ export const equipment: Query = deps => (user, params) =>
E.map(params => params.equipment),
TE.fromEither,
TE.chain(constructViewModel(deps, user)),
TE.map(viewModel => ({
title: viewModel.equipment.name,
body: render(viewModel),
}))
TE.map(viewModel =>
HttpResponse.mk.Page({
title: viewModel.equipment.name,
body: render(viewModel),
})
)
);
3 changes: 2 additions & 1 deletion src/queries/landing/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,12 @@ import * as TE from 'fp-ts/TaskEither';
import {render} from './render';
import {constructViewModel} from './construct-view-model';
import {Query} from '../query';
import {HttpResponse} from '../../types';

export const landing: Query = deps => user =>
pipe(
user,
constructViewModel(deps),
TE.map(render),
TE.map(body => ({title: 'Dashboard', body}))
TE.map(body => HttpResponse.mk.Page({title: 'Dashboard', body}))
);
8 changes: 7 additions & 1 deletion src/queries/log/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,17 @@ import * as TE from 'fp-ts/TaskEither';
import {render} from './render';
import {constructViewModel} from './construct-view-model';
import {Query} from '../query';
import {HttpResponse} from '../../types';

export const log: Query = deps => user =>
pipe(
user,
constructViewModel(deps),
TE.map(render),
TE.map(body => ({title: 'Event Log', body}))
TE.map(body =>
HttpResponse.mk.Page({
title: 'Event Log',
body,
})
)
);
11 changes: 7 additions & 4 deletions src/queries/member/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {failureWithStatus} from '../../types/failureWithStatus';
import {StatusCodes} from 'http-status-codes';
import {formatValidationErrors} from 'io-ts-reporters';
import * as tt from 'io-ts-types';
import {HttpResponse} from '../../types';

const invalidParams = flow(
formatValidationErrors,
Expand All @@ -24,8 +25,10 @@ export const member: Query = deps => (user, params) =>
TE.fromEither,
TE.chain(constructViewModel(deps, user)),
TE.map(render),
TE.map(body => ({
title: 'Member',
body,
}))
TE.map(body =>
HttpResponse.mk.Page({
title: 'Member',
body,
})
)
);
11 changes: 7 additions & 4 deletions src/queries/members/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,17 @@ import * as TE from 'fp-ts/TaskEither';
import {render} from './render';
import {constructViewModel} from './construct-view-model';
import {Query} from '../query';
import {HttpResponse} from '../../types';

export const members: Query = deps => user =>
pipe(
user,
constructViewModel(deps),
TE.map(render),
TE.map(body => ({
title: 'Members',
body,
}))
TE.map(body =>
HttpResponse.mk.Page({
title: 'Members',
body,
})
)
);
4 changes: 2 additions & 2 deletions src/queries/query.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import {Dependencies} from '../dependencies';
import {User} from '../types';
import {User, HttpResponse} from '../types';
import {FailureWithStatus} from '../types/failureWithStatus';
import * as TE from 'fp-ts/TaskEither';

Expand All @@ -10,4 +10,4 @@ export type Query = (
) => (
user: User,
params: Params
) => TE.TaskEither<FailureWithStatus, {body: string; title: string}>;
) => TE.TaskEither<FailureWithStatus, HttpResponse>;
3 changes: 2 additions & 1 deletion src/queries/super-users/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,12 @@ import * as TE from 'fp-ts/TaskEither';
import {render} from './render';
import {constructViewModel} from './construct-view-model';
import {Query} from '../query';
import {HttpResponse} from '../../types';

export const superUsers: Query = deps => user =>
pipe(
user,
constructViewModel(deps),
TE.map(render),
TE.map(body => ({title: 'Super Users', body}))
TE.map(body => HttpResponse.mk.Page({title: 'Super Users', body}))
);
2 changes: 1 addition & 1 deletion src/templates/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
export {pageTemplate} from './page-template';
export {pageTemplate, templatePage} from './page-template';
export {pageTemplateNoNav} from './page-template-no-nav';
export {oopsPage} from './oops';
21 changes: 20 additions & 1 deletion src/templates/page-template.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import {html} from '../types/html';
import * as O from 'fp-ts/Option';
import {navbar} from './navbar';
import {head} from './head';
import {User} from '../types';
import {User, HttpResponse} from '../types';

export const pageTemplate =
(title: string, user: O.Option<User>) => (body: string) => html`
Expand All @@ -15,3 +15,22 @@ export const pageTemplate =
</body>
</html>
`;

export const templatePage: (
user: O.Option<User>
) => (r: HttpResponse) => HttpResponse = (user: O.Option<User>) =>
HttpResponse.match({
Redirect: HttpResponse.mk.Redirect,
Page: ({title, body}) =>
HttpResponse.mk.Page({
body: html` <!doctype html>
<html lang="en">
${head(title)}
<header>${navbar(user)}</header>
<body>
${body}
</body>
</html>`,
title,
}),
});
16 changes: 16 additions & 0 deletions src/types/html.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import * as Sum from '@unsplash/sum-types';

export const html = (
literals: TemplateStringsArray,
...substitutions: ReadonlyArray<string | number>
Expand All @@ -13,3 +15,17 @@ export const html = (
result += literals[substitutions.length];
return result;
};

interface Page {
body: string;
title: string;
}

interface Redirect {
url: string;
}

export type HttpResponse =
| Sum.Member<'Redirect', Redirect>
| Sum.Member<'Page', Page>;
export const HttpResponse = Sum.create<HttpResponse>();
1 change: 1 addition & 0 deletions src/types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ export {Failure, failure} from './failure';
export {Email} from './email';
export {User} from './user';
export {Actor} from './actor';
export {HttpResponse} from './html';
export {
MemberDetails,
OptionalMemberDetails,
Expand Down

0 comments on commit 7dd0327

Please sign in to comment.