-
Notifications
You must be signed in to change notification settings - Fork 5
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
Add generate link to book appointment #390
base: master
Are you sure you want to change the base?
Changes from all commits
b4a6dd3
9013582
5067524
d0d5c6c
dcee7db
1af0828
2f68bbe
aef9c67
1f86419
d00d1f5
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -113,16 +113,33 @@ export async function getAppointmentsByHospital( | |
return toDbAppointments(appointments); | ||
} | ||
|
||
export async function getAvailableAppointments() { | ||
const now = new Date(); | ||
export async function getAvailableAppointments( | ||
hospitals?: Hospital[], | ||
fromTime?: Date, | ||
toTime?: Date | ||
) { | ||
if (!fromTime) { | ||
fromTime = new Date(); | ||
} | ||
|
||
const appointments = (await admin | ||
let request = admin | ||
.firestore() | ||
.collection(Collections.APPOINTMENTS) | ||
.where("status", "==", AppointmentStatus.AVAILABLE) | ||
.where("donationStartTime", ">", now) | ||
.orderBy("donationStartTime") | ||
.get()) as FirebaseFirestore.QuerySnapshot<DbAppointment>; | ||
.where("donationStartTime", ">=", fromTime); | ||
|
||
if (hospitals) { | ||
request = request.where("hospital", "in", hospitals); | ||
} | ||
|
||
if (toTime) { | ||
request = request.where("donationStartTime", "<=", toTime); | ||
} | ||
|
||
request = request.orderBy("donationStartTime"); | ||
|
||
const appointments = | ||
(await request.get()) as FirebaseFirestore.QuerySnapshot<DbAppointment>; | ||
|
||
return toDbAppointments(appointments); | ||
} | ||
|
@@ -151,6 +168,33 @@ export async function getAppointmentsByStatus( | |
return toDbAppointments(appointments); | ||
} | ||
|
||
export async function getAppointmentByShareLink( | ||
shareLink: string | ||
): Promise<DbAppointment> { | ||
if (!shareLink) { | ||
evbambly marked this conversation as resolved.
Show resolved
Hide resolved
|
||
throw Error("you have to give a value for share link id"); | ||
} | ||
|
||
let request = admin | ||
.firestore() | ||
.collection(Collections.APPOINTMENTS) | ||
.where("shareLink", "==", shareLink); | ||
|
||
const appointments = | ||
(await request.get()) as FirebaseFirestore.QuerySnapshot<DbAppointment>; | ||
|
||
const ret = toDbAppointments(appointments); | ||
if (ret.length > 1) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. See previous comment. |
||
throw Error("there is more then one appointment with this share link!"); | ||
} | ||
|
||
if (ret.length == 0) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. See previous comment. |
||
throw Error("There is no appointment with this share link!"); | ||
} | ||
|
||
return ret[0]; | ||
} | ||
|
||
export async function getAllAppointments() { | ||
const appointments = (await admin | ||
.firestore() | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,108 @@ | ||
import firebaseFunctionsTest from "../testUtils/FirebaseTestUtils"; | ||
import { | ||
FunctionsApi, | ||
Hospital, | ||
AppointmentStatus, | ||
} from "@zm-blood-components/common"; | ||
import * as Functions from "../index"; | ||
import { | ||
deleteAppointmentsByIds, | ||
setAppointment, | ||
} from "../dal/AppointmentDataAccessLayer"; | ||
import * as admin from "firebase-admin"; | ||
import { DbAppointment } from "../function-types"; | ||
import { saveTestDonor } from "../testUtils/TestSamples"; | ||
import { deleteDonor } from "../dal/DonorDataAccessLayer"; | ||
|
||
const wrapped = firebaseFunctionsTest.wrap( | ||
Functions[FunctionsApi.GetSharedLinkAppointmentFunctionName] | ||
); | ||
|
||
const CREATING_USER_ID = "GetAvailableAppointmentsHandlerCreatingUserId"; | ||
const DONOR_ID = "GetAvailableAppointmentsHandlerDonorId"; | ||
const SHARED_DONOR_ID = "SHARED_DONOR_ID"; | ||
|
||
const SHARE_LINK = "JUST_A_Random_Share_link"; | ||
|
||
const SHARED_APPOINTMENT = "GetAvailableAppointmentsHandlerAppointment1"; | ||
const APPOINTMENT_IN_SAME_TIME = "GetAvailableAppointmentsHandlerAppointment2"; | ||
const APPOINTMENT_IN_SAME_TIME_BOOKED = | ||
"GetAvailableAppointmentsHandlerAppointment4"; | ||
const DIFFRENT_APPOINTMENT = "GetAvailableAppointmentsHandlerAppointment3"; | ||
|
||
const ALL_TEST_APPOINTMENTS_IDS = [ | ||
SHARED_APPOINTMENT, | ||
APPOINTMENT_IN_SAME_TIME, | ||
APPOINTMENT_IN_SAME_TIME_BOOKED, | ||
DIFFRENT_APPOINTMENT, | ||
]; | ||
|
||
beforeAll(reset); | ||
afterEach(reset); | ||
|
||
async function reset() { | ||
await deleteDonor(SHARED_DONOR_ID); | ||
await deleteDonor(DONOR_ID); | ||
await deleteAppointmentsByIds(ALL_TEST_APPOINTMENTS_IDS); | ||
} | ||
|
||
async function saveAppointment( | ||
id: string, | ||
donationStartTime: Date, | ||
booked: boolean, | ||
shared: boolean | ||
) { | ||
const appointment: DbAppointment = { | ||
id: id, | ||
creationTime: admin.firestore.Timestamp.fromDate(donationStartTime), | ||
creatorUserId: CREATING_USER_ID, | ||
donationStartTime: admin.firestore.Timestamp.fromDate(donationStartTime), | ||
hospital: Hospital.ASAF_HAROFE, | ||
donorId: "", | ||
status: booked ? AppointmentStatus.BOOKED : AppointmentStatus.AVAILABLE, | ||
}; | ||
|
||
if (shared) { | ||
appointment.shareLink = SHARE_LINK; | ||
} | ||
|
||
if (booked) { | ||
appointment.donorId = DONOR_ID; | ||
appointment.bookingTime = admin.firestore.Timestamp.now(); | ||
} | ||
|
||
await setAppointment(appointment); | ||
return appointment; | ||
} | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What about the logic test cases, |
||
test("Not authenticated", async () => { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. As per previous, this should not stop users from accessing the API. |
||
await saveTestDonor(DONOR_ID); | ||
|
||
await saveAppointment(SHARED_APPOINTMENT, new Date(), true, true); | ||
await saveAppointment(APPOINTMENT_IN_SAME_TIME, new Date(), false, false); | ||
|
||
await expect( | ||
wrapped({ donorId: SHARED_DONOR_ID, shareLink: SHARE_LINK }) | ||
).rejects.toThrow(Error); | ||
}); | ||
|
||
test("Returns available appointments is ascending start time order", async () => { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm not sure I understand the test title. |
||
await saveTestDonor(SHARED_DONOR_ID); | ||
await saveTestDonor(DONOR_ID); | ||
|
||
await saveAppointment(SHARED_APPOINTMENT, new Date(), true, true); | ||
await saveAppointment(APPOINTMENT_IN_SAME_TIME, new Date(), false, false); | ||
|
||
const appointment = (await callTarget()).appointment; | ||
|
||
expect(appointment).not.toBeNaN(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do you mean to test "not to be undefined"? |
||
expect(appointment.id).toEqual(SHARED_APPOINTMENT); | ||
expect(appointment.shareLink).toEqual(SHARE_LINK); | ||
}); | ||
|
||
async function callTarget() { | ||
return (await wrapped( | ||
{ donorId: SHARED_DONOR_ID, shareLink: SHARE_LINK }, | ||
{ auth: { uid: SHARED_DONOR_ID } } | ||
)) as FunctionsApi.GetSharedLinkAppointmentResponse; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
import { getAppointmentByShareLink } from "../dal/AppointmentDataAccessLayer"; | ||
import { FunctionsApi } from "@zm-blood-components/common"; | ||
import * as DbAppointmentUtils from "../utils/DbAppointmentUtils"; | ||
|
||
export default async function ( | ||
request: FunctionsApi.GetSharedLinkAppointmentRequest, | ||
callerId: string | ||
): Promise<FunctionsApi.GetSharedLinkAppointmentResponse> { | ||
if (callerId !== request.donorId) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Could this API be called by an unregistered user? |
||
throw Error("Unauthorized to access user"); | ||
} | ||
|
||
const appointment = await getAppointmentByShareLink(request.shareLink); | ||
|
||
const result = await DbAppointmentUtils.toBookedAppointmentAsync(appointment); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. As mentioned in the design doc, |
||
|
||
return { | ||
appointment: result, | ||
}; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why not use a library to generate UIDs?