Skip to content

Commit 9aa6e19

Browse files
committed
Add test for User.bookAppointment().
1 parent b457649 commit 9aa6e19

9 files changed

+140
-30
lines changed

Makefile

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ eslint:
88
npx eslint . --ext .ts
99

1010
test:
11-
npx mocha
11+
npx mocha $(args)
1212

1313
build:
1414
npx tsc --build

src/backend/appointments.ts

+1
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,7 @@ export class AppointmentsBackend extends JSONRPCBackend {
148148
},
149149
keyPair: KeyPair
150150
) {
151+
console.log(signedTokenData)
151152
return this.call<Booking>(
152153
"bookAppointment",
153154
{ providerID, id, encryptedData, signedTokenData },

src/interfaces/appointments.ts

+8-2
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,8 @@ export interface Slot {
1616
}
1717

1818
export interface AcceptedAppointment {
19-
appointment: SignedAppointment
20-
provider: SignedProviderData
19+
appointment: Appointment
20+
provider: PublicProviderData
2121
booking: Booking
2222
}
2323

@@ -51,6 +51,7 @@ export interface SignedProviderData {
5151
}
5252

5353
export interface PublicProviderData {
54+
id: string
5455
name: string
5556
street: string
5657
city: string
@@ -87,3 +88,8 @@ export interface ProviderAppointments {
8788
appointments: SignedAppointment[]
8889
keyChain: KeyChain
8990
}
91+
92+
export interface VerifiedProviderAppointments {
93+
provider: PublicProviderData
94+
appointments: Appointment[]
95+
}

src/user/book-appointment.spec.ts

+88
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
// Kiebitz - Privacy-Friendly Appointments
2+
// Copyright (C) 2021-2021 The Kiebitz Authors
3+
// README.md contains license information.
4+
5+
import { Status } from "../interfaces"
6+
import { equal } from "assert"
7+
import { formatDatetime } from "../helpers/time"
8+
import {
9+
backend,
10+
adminKeys,
11+
resetDB,
12+
mediator,
13+
verifiedProvider,
14+
} from "../testing/fixtures"
15+
import { User } from "./"
16+
17+
beforeEach(async function () {
18+
this.backend = backend()
19+
20+
const keys = await adminKeys()
21+
// we reset the database
22+
await resetDB(this.backend, keys)
23+
// we create a mediator
24+
const med = await mediator(this.backend, keys)
25+
// we create an unverified provider
26+
const vp = await verifiedProvider(this.backend, keys, med)
27+
28+
let date = new Date()
29+
30+
// tomorrow 3 pm
31+
32+
date.setDate(date.getDate() + 1)
33+
date.setHours(15)
34+
date.setMinutes(0)
35+
date.setSeconds(0)
36+
date.setMilliseconds(0)
37+
38+
var app = await vp.createAppointment(15, "moderna", 5, date.toISOString())
39+
40+
const publishResult = await vp.publishAppointments([app])
41+
42+
if (publishResult.status !== Status.Succeeded)
43+
throw new Error("cannot create appointment")
44+
45+
this.user = new User("main", this.backend)
46+
// we generate a secret etc.
47+
await this.user.initialize()
48+
// we set the queue data
49+
this.user.queueData = {
50+
zipCode: "10707",
51+
}
52+
// we set the contact data
53+
this.user.contactData = {
54+
name: "Max Mustermann",
55+
}
56+
})
57+
58+
describe("User.bookAppointment()", function () {
59+
it("we should be able to book an appointment", async function () {
60+
const tokenResult = await this.user.getToken({})
61+
62+
if (tokenResult.status !== Status.Succeeded)
63+
throw new Error("cannot get token")
64+
65+
const fromDate = new Date()
66+
// 24 hours in the future
67+
const toDate = new Date(new Date().getTime() + 48 * 60 * 60 * 1000)
68+
const getResult = await this.user.getAppointments({
69+
from: formatDatetime(fromDate),
70+
to: formatDatetime(toDate),
71+
zipCode: this.user.queueData!.zipCode,
72+
})
73+
74+
if (getResult.status !== Status.Succeeded)
75+
throw new Error("should not fail")
76+
77+
if (getResult.appointments.length !== 1)
78+
throw new Error("should return one appointment")
79+
80+
const bookResult = await this.user.bookAppointment(
81+
getResult.appointments[0].appointments[0],
82+
getResult.appointments[0].provider
83+
)
84+
85+
if (bookResult.status !== Status.Succeeded)
86+
throw new Error("should not fail")
87+
})
88+
})

src/user/book-appointment.ts

+5-7
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@ import {
88
OK,
99
Result,
1010
AcceptedAppointment,
11-
SignedProviderData,
12-
SignedAppointment,
11+
PublicProviderData,
12+
Appointment,
1313
Error,
1414
} from "../interfaces"
1515
import { User } from "./"
@@ -20,16 +20,14 @@ interface BookAppointmentResult extends Result {
2020

2121
export async function bookAppointment(
2222
this: User,
23-
signedAppointment: SignedAppointment,
24-
provider: SignedProviderData
23+
appointment: Appointment,
24+
provider: PublicProviderData
2525
): Promise<BookAppointmentResult | Error> {
2626
const providerData = {
2727
signedToken: this.tokenData!.signedToken,
2828
userToken: this.tokenData!.userToken,
2929
}
3030

31-
const appointment = signedAppointment.json!
32-
3331
const encryptedDataAndPublicKey = await ephemeralECDHEncrypt(
3432
JSON.stringify(providerData),
3533
appointment.publicKey
@@ -55,7 +53,7 @@ export async function bookAppointment(
5553
}
5654

5755
const acceptedAppointment: AcceptedAppointment = {
58-
appointment: signedAppointment,
56+
appointment: appointment,
5957
provider: provider,
6058
booking: response,
6159
}

src/user/cancel-appointment.ts

+7-4
Original file line numberDiff line numberDiff line change
@@ -3,17 +3,20 @@
33
// README.md contains license information.
44

55
import { ecdhEncrypt } from "../crypto"
6-
import { Result, Error, Status } from "../interfaces"
6+
import { Result, Error, Status, AcceptedAppointment } from "../interfaces"
77
import { User } from "./"
88

9-
export async function cancelAppointment(this: User): Promise<Result | Error> {
10-
const id = this.acceptedAppointment!.appointment.json.id
9+
export async function cancelAppointment(
10+
this: User,
11+
acceptedAppointment: AcceptedAppointment
12+
): Promise<Result | Error> {
13+
const id = acceptedAppointment.appointment.id
1114

1215
const result = await this.backend.appointments.cancelAppointment(
1316
{
1417
id: id,
1518
signedTokenData: this.tokenData!.signedToken,
16-
providerID: this.acceptedAppointment!.provider.id,
19+
providerID: acceptedAppointment.provider.id,
1720
},
1821
this.tokenData!.keyPairs.signing
1922
)

src/user/get-appointments.ts

+27-12
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,13 @@
22
// Copyright (C) 2021-2021 The Kiebitz Authors
33
// README.md contains license information.
44

5-
import { Status, Result, Error, ProviderAppointments } from "../interfaces"
5+
import {
6+
Status,
7+
Result,
8+
Error,
9+
Appointment,
10+
VerifiedProviderAppointments,
11+
} from "../interfaces"
612
import { verify } from "../crypto"
713
import { User } from "./"
814

@@ -42,7 +48,7 @@ async function verifyProviderData(item: any) {
4248
}
4349

4450
interface GetAppointmentsResult extends Result {
45-
appointments: ProviderAppointments[]
51+
appointments: VerifiedProviderAppointments[]
4652
}
4753

4854
interface GetAppointmentsParams {
@@ -67,29 +73,38 @@ export async function getAppointments(
6773
error: response,
6874
}
6975

70-
const verifiedAppointments: ProviderAppointments[] = []
76+
const verifiedAppointments: VerifiedProviderAppointments[] = []
7177

7278
for (const item of response) {
7379
item.provider.json = await verifyProviderData(item)
74-
const verifiedProviderAppointments = []
75-
for (const appointment of item.appointments) {
76-
const verifiedAppointment = await verifyAppointment(
77-
appointment,
80+
// we copy the ID for convenience
81+
item.provider.json.id = item.provider.id
82+
const verifiedProviderAppointments: Appointment[] = []
83+
for (const signedAppointment of item.appointments) {
84+
const appointment: Appointment = await verifyAppointment(
85+
signedAppointment,
7886
item
7987
)
80-
for (const slot of verifiedAppointment.slotData) {
81-
if (appointment.bookedSlots!.some((id: any) => id === slot.id))
88+
for (const slot of appointment.slotData) {
89+
if (
90+
signedAppointment.bookedSlots!.some(
91+
(id: any) => id === slot.id
92+
)
93+
)
8294
slot.open = false
8395
else slot.open = true
8496
}
85-
verifiedProviderAppointments.push(verifiedAppointment)
97+
verifiedProviderAppointments.push(appointment)
8698
}
8799
item.appointments = verifiedProviderAppointments
88-
verifiedAppointments.push(item)
100+
verifiedAppointments.push({
101+
provider: item.provider.json,
102+
appointments: verifiedProviderAppointments,
103+
} as VerifiedProviderAppointments)
89104
}
90105

91106
verifiedAppointments.sort((a, b) =>
92-
a.provider.json!.name > b.provider.json!.name ? 1 : -1
107+
a.provider.name > b.provider.name ? 1 : -1
93108
)
94109

95110
return {

src/user/get-token.spec.ts

+2-3
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,11 @@ import { formatDate } from "../helpers/time"
88
import { backend } from "../testing/fixtures"
99
import { User } from "./"
1010

11-
beforeEach(function () {
11+
beforeEach(async function () {
1212
this.backend = backend()
1313
this.user = new User("main", this.backend)
1414
// we generate a secret etc.
15-
this.user.initialize()
15+
await this.user.initialize()
1616
// we set the queue data
1717
this.user.queueData = {
1818
zipCode: "10707",
@@ -25,7 +25,6 @@ beforeEach(function () {
2525

2626
describe("User.getToken()", function () {
2727
it("we should be able to get a token", async function () {
28-
const today = formatDate(new Date())
2928
const result = await this.user.getToken({})
3029
equal(result.status, Status.Succeeded)
3130
equal(result.tokenData.userToken.version, "0.3")

src/user/index.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -42,8 +42,8 @@ export class User extends Actor {
4242
}
4343

4444
public async initialize() {
45-
await this.generateKeyPairs()
4645
this.generateSecret()
46+
await this.generateKeyPairs()
4747
}
4848

4949
public get queueData(): QueueData | null {

0 commit comments

Comments
 (0)