Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
6 changes: 6 additions & 0 deletions src/commands/equipment/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import {registerTrainingSheet} from './register-training-sheet';
import {registerTrainingSheetForm} from './register-training-sheet-form';
import {removeTrainingSheet} from './remove-training-sheet';
import {removeTrainingSheetForm} from './remove-training-sheet-form';
import {removeEquipment} from './remove';
import {removeEquipmentForm} from './remove-form';

export const equipment = {
add: {
Expand All @@ -18,4 +20,8 @@ export const equipment = {
...removeTrainingSheet,
...removeTrainingSheetForm,
},
remove: {
...removeEquipment,
...removeEquipmentForm,
},
};
43 changes: 43 additions & 0 deletions src/commands/equipment/remove-form.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import * as E from 'fp-ts/Either';
import {Form} from '../../types/form';
import {pipe} from 'fp-ts/lib/function';
import {html, safe, sanitizeString, toLoggedInContent} from '../../types/html';
import {getEquipmentIdFromForm} from './get-equipment-id-from-form';
import {getEquipmentName} from './get-equipment-name';

type ViewModel = {
equipmentId: string;
equipmentName: string;
};

const renderForm = (viewModel: ViewModel) =>
pipe(
html`
<div class="stack-large">
<h1>Remove '${sanitizeString(viewModel.equipmentName)}'?</h1>
<form action="#" method="post">
<input
type="hidden"
name="id"
value="${safe(viewModel.equipmentId)}"
/>
<button type="submit">Confirm and send</button>
</form>
</div>
`,
toLoggedInContent(safe('Remove Equipment'))
);

export const removeEquipmentForm: Form<ViewModel> = {
renderForm,
constructForm:
input =>
({readModel}) =>
pipe(
E.Do,
E.bind('equipmentId', () => getEquipmentIdFromForm(input)),
E.bind('equipmentName', ({equipmentId}) =>
getEquipmentName(readModel, equipmentId)
)
),
};
40 changes: 40 additions & 0 deletions src/commands/equipment/remove.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import {constructEvent, isEventOfType} from '../../types';
import * as RA from 'fp-ts/ReadonlyArray';
import * as t from 'io-ts';
import * as tt from 'io-ts-types';
import * as O from 'fp-ts/Option';
import {pipe} from 'fp-ts/lib/function';
import {Command} from '../command';
import {isAdminOrSuperUser} from '../is-admin-or-super-user';

const codec = t.strict({
id: tt.UUID,
});

type RemoveEquipment = t.TypeOf<typeof codec>;

const process: Command<RemoveEquipment>['process'] = input => {
if (input.events.length === 0) {
return O.none;
}
return pipe(
input.events,
RA.filter(isEventOfType('EquipmentRemoved')),
RA.match(
() => O.some(constructEvent('EquipmentRemoved')(input.command)),
() => O.none
)
);
};

const resource: Command<RemoveEquipment>['resource'] = command => ({
type: 'Equipment',
id: command.id,
});

export const removeEquipment: Command<RemoveEquipment> = {
process,
resource,
decode: codec.decode,
isAuthorized: isAdminOrSuperUser,
};
19 changes: 19 additions & 0 deletions src/queries/equipment/render.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,24 @@ const adminMarkTrainedBy = (viewModel: ViewModel) =>
O.getOrElse(() => html``)
);

const adminRemoveEquipment = (viewModel: ViewModel) =>
pipe(
viewModel,
O.of,
O.filter(viewModel => viewModel.isSuperUser),
O.map(viewModel => viewModel.equipment.id),
O.map(
id =>
html` <li>
<a href="/equipment/remove?equipmentId=${id}"
>[Admin] Remove equipment</a
>
${tooltip(safe('Only admins can remove equipment'))}
</li>`
),
O.getOrElse(() => html``)
);

const addTrainer = (viewModel: ViewModel) =>
pipe(
viewModel,
Expand Down Expand Up @@ -141,6 +159,7 @@ const equipmentActions = (viewModel: ViewModel) => html`
${trainMember(viewModel)} ${adminMarkTrainedBy(viewModel)}
${addTrainer(viewModel)} ${registerSheet(viewModel)}
${currentSheet(viewModel)} ${removeTrainingSheet(viewModel)}
${adminRemoveEquipment(viewModel)}
</ul>
`;

Expand Down
9 changes: 9 additions & 0 deletions src/read-models/shared-state/update-state.ts
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,15 @@ export const updateState =
.values({id: event.id, name: event.name, areaId: event.areaId})
.run();
break;
case 'EquipmentRemoved':
db.delete(trainersTable)
.where(eq(trainersTable.equipmentId, event.id))
.run();
db.delete(trainedMemberstable)
.where(eq(trainedMemberstable.equipmentId, event.id))
.run();
db.delete(equipmentTable).where(eq(equipmentTable.id, event.id)).run();
break;
case 'TrainerAdded': {
if (
isOwnerOfAreaContainingEquipment(db, linking)(
Expand Down
1 change: 1 addition & 0 deletions src/routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ export const initRoutes = (
'remove-training-sheet',
commands.equipment.removeTrainingSheet
),
...command('equipment', 'remove', commands.equipment.remove),
...command(
'equipment',
'mark-member-trained',
Expand Down
6 changes: 6 additions & 0 deletions src/types/domain-event.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,10 @@ const EquipmentAdded = defineEvent('EquipmentAdded', {
areaId: tt.UUID,
});

const EquipmentRemoved = defineEvent('EquipmentRemoved', {
id: tt.UUID,
});

const OwnerAdded = defineEvent('OwnerAdded', {
areaId: tt.UUID,
memberNumber: t.number,
Expand Down Expand Up @@ -202,6 +206,7 @@ export const events = [
AreaRemoved,
AreaEmailUpdated,
EquipmentAdded,
EquipmentRemoved,
OwnerAdded,
OwnerRemoved,
SuperUserDeclared,
Expand Down Expand Up @@ -233,6 +238,7 @@ export const DomainEvent = t.union([
AreaRemoved.codec,
AreaEmailUpdated.codec,
EquipmentAdded.codec,
EquipmentRemoved.codec,
OwnerAdded.codec,
OwnerRemoved.codec,
SuperUserDeclared.codec,
Expand Down
1 change: 1 addition & 0 deletions tests/read-models/test-framework.ts
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,7 @@ export const initTestFramework = async (): Promise<TestFramework> => {
removeTrainingSheet: frameworkify(
commands.equipment.removeTrainingSheet
),
remove: frameworkify(commands.equipment.remove),
},
trainers: {
add: frameworkify(commands.trainers.add),
Expand Down