Skip to content

Commit

Permalink
Merge branch '631-frontend-connect-the-policy-to-sanity' of https://g…
Browse files Browse the repository at this point in the history
…ithub.com/UoaWDCC/uasc-web into 631-frontend-connect-the-policy-to-sanity
  • Loading branch information
Kartik-M24 committed Sep 11, 2024
2 parents bd00110 + dd2051e commit 79f3c70
Show file tree
Hide file tree
Showing 12 changed files with 778 additions and 23 deletions.
46 changes: 46 additions & 0 deletions client/src/models/__generated__/schema.d.ts

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

45 changes: 45 additions & 0 deletions server/src/data-layer/adapters/Firestore.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { admin } from "business-layer/security/Firebase"

const converter = <T>() => ({
toFirestore: (data: any) => data,
fromFirestore: (doc: any) => doc.data() as T
})

/**
* Firestore adapter for the application.
*/
const firestore = Object.assign(
() => {
return admin.firestore()
},
{
doc: <T>(path: string) => {
return admin.firestore().doc(path).withConverter<T>(converter<T>())
},
/**
* Collection adapter for Firestore.
* @param path The path to the collection.
* @returns The collection adapter.
*/
collection: <T>(path: string) => {
return admin.firestore().collection(path).withConverter<T>(converter<T>())
},
/**
* Subcollection adapter for Firestore.
* @param path The path to the main collection.
* @param docId The document ID from the main collection to retrieve.
* @param subpath The path to the subcollection.
* @returns The subcollection adapter.
*/
subcollection: <T>(path: string, docId: string, subpath: string) => {
return admin
.firestore()
.collection(path) // The main collection
.doc(docId) // The document
.collection(subpath) // The sub collection
.withConverter<T>(converter<T>())
}
}
)

export default firestore
29 changes: 6 additions & 23 deletions server/src/data-layer/adapters/FirestoreCollections.ts
Original file line number Diff line number Diff line change
@@ -1,37 +1,20 @@
// credit https://plainenglish.io/blog/using-firestore-with-typescript-in-the-v9-sdk-cf36851bb099
import "dotenv/config"
import firestore from "./Firestore"
import {
Booking,
BookingHistoryEvent,
BookingSlot,
Event,
UserAdditionalInfo
} from "data-layer/models/firebase"
import { admin } from "business-layer/security/Firebase"

const converter = <T>() => ({
toFirestore: (data: any) => data,
fromFirestore: (doc: any) => doc.data() as T
})

const firestore = Object.assign(
() => {
return admin.firestore()
},
{
doc: <T>(path: string) => {
return admin.firestore().doc(path).withConverter<T>(converter<T>())
},
collection: <T>(path: string) => {
return admin.firestore().collection(path).withConverter<T>(converter<T>())
}
}
)

const db = {
const FirestoreCollections = {
users: firestore.collection<UserAdditionalInfo>("users"),
bookings: firestore.collection<Booking>("bookings"),
bookingSlots: firestore.collection<BookingSlot>("booking_slots"),
bookingHistory: firestore.collection<BookingHistoryEvent>("booking_history")
bookingHistory: firestore.collection<BookingHistoryEvent>("booking_history"),
events: firestore.collection<Event>("events")
} as const

export default db
export default FirestoreCollections
11 changes: 11 additions & 0 deletions server/src/data-layer/adapters/FirestoreSubcollections.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// credit https://plainenglish.io/blog/using-firestore-with-typescript-in-the-v9-sdk-cf36851bb099
import "dotenv/config"
import firestore from "./Firestore"
import { EventReservation } from "data-layer/models/firebase"

const FirestoreSubcollections = {
reservations: (eventId: string) =>
firestore.subcollection<EventReservation>("events", eventId, "reservations")
} as const

export default FirestoreSubcollections
230 changes: 230 additions & 0 deletions server/src/data-layer/services/EventService.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,230 @@
import { cleanFirestore } from "test-config/TestUtils"
import EventService from "./EventService"
import {
dateToFirestoreTimeStamp,
removeUnderscoresFromTimestamp
} from "data-layer/adapters/DateUtils"
import { Event, EventReservation } from "data-layer/models/firebase"
import FirestoreCollections from "data-layer/adapters/FirestoreCollections"

const eventService = new EventService()

const startDate = dateToFirestoreTimeStamp(new Date(2024, 1, 1))
const endDate = dateToFirestoreTimeStamp(new Date(2024, 1, 2))

const event1: Event = {
title: "UASC new event",
description: "Grand opening of the website.",
location: "Virtual pizza event",
start_date: startDate,
end_date: endDate
}
const event2: Event = {
title: "Snowboard racing",
description: "Race and see who's the fastest!",
location: "Snowsport club",
start_date: startDate,
end_date: endDate
}

const reservation1: EventReservation = {
first_name: "John",
last_name: "Appleseed",
email: "[email protected]",
is_member: true
}
const reservation2: EventReservation = {
first_name: "Jane",
last_name: "Pearseed",
email: "[email protected]",
is_member: false
}

describe("EventService integration tests", () => {
afterEach(async () => {
await cleanFirestore()
})

it("Should be able to add an event", async () => {
const newEvent = await eventService.createEvent(event1)

const fetchedEvent = await FirestoreCollections.events
.doc(newEvent.id)
.get()

const data = fetchedEvent.data()

expect({
...data,
end_date: removeUnderscoresFromTimestamp(data.end_date),
start_date: removeUnderscoresFromTimestamp(data.start_date)
}).toEqual(event1)
})

it("Should be able to get an event", async () => {
const newEvent = await eventService.createEvent(event1)

const fetchedEvent = await eventService.getEventById(newEvent.id)

expect({
...fetchedEvent,
end_date: removeUnderscoresFromTimestamp(fetchedEvent.end_date),
start_date: removeUnderscoresFromTimestamp(fetchedEvent.start_date)
}).toEqual(event1)
})

it("Should be able to update an event", async () => {
const newEvent = await eventService.createEvent(event1)

await eventService.updateEvent(newEvent.id, {
title: "Wow pizza???"
})

const fetchedEvent = await eventService.getEventById(newEvent.id)

expect(fetchedEvent.title).toBe("Wow pizza???")
})

it("Should be able to delete an event", async () => {
const newEvent = await eventService.createEvent(event1)
await eventService.deleteEvent(newEvent.id)

const fetchedEvent = await eventService.getEventById(newEvent.id)

expect(fetchedEvent).toBe(undefined)
})

it("Should delete an event and also all reservations", async () => {
const newEvent = await eventService.createEvent(event1)
const newReservation1 = await eventService.addReservation(
newEvent.id,
reservation1
)
const newReservation2 = await eventService.addReservation(
newEvent.id,
reservation2
)

await eventService.deleteEvent(newEvent.id)

const fetchedReservation1 = await eventService.getReservationById(
newEvent.id,
newReservation1.id
)
expect(fetchedReservation1).toBe(undefined)
const fetchedReservation2 = await eventService.getReservationById(
newEvent.id,
newReservation2.id
)
expect(fetchedReservation2).toBe(undefined)
})

it("Should not delete other reservations when deleting an event document", async () => {
const newEvent = await eventService.createEvent(event1)
await eventService.addReservation(newEvent.id, reservation1)
await eventService.addReservation(newEvent.id, reservation2)
const newEvent2 = await eventService.createEvent(event2)
const newReservation3 = await eventService.addReservation(
newEvent2.id,
reservation1
)
const newReservation4 = await eventService.addReservation(
newEvent2.id,
reservation2
)

await eventService.deleteEvent(newEvent.id)
const fetchedReservation3 = await eventService.getReservationById(
newEvent2.id,
newReservation3.id
)
expect(fetchedReservation3).toEqual(reservation1)
const fetchedReservation4 = await eventService.getReservationById(
newEvent2.id,
newReservation4.id
)
expect(fetchedReservation4).toEqual(reservation2)
})

/**
* Event reservation nested collection methods
*/
describe("EventReservation integration tests", () => {
it("Should be able to add a event reservation", async () => {
const newEvent = await eventService.createEvent(event1)

const reservation = await eventService.addReservation(
newEvent.id,
reservation1
)
const fetchedReservation = await FirestoreCollections.events
.doc(newEvent.id)
.collection("reservations") // subject to place as a constant somewhere
.doc(reservation.id)
.get()
expect(fetchedReservation.data()).toEqual(reservation1)
})

it("Should be able to get an event reservation", async () => {
const newEvent = await eventService.createEvent(event1)
const reservation = await eventService.addReservation(
newEvent.id,
reservation1
)
const fetchedReservation = await eventService.getReservationById(
newEvent.id,
reservation.id
)
expect(fetchedReservation).toEqual(reservation1)
})

it("Should get all event reservations", async () => {
const newEvent = await eventService.createEvent(event1)
await eventService.addReservation(newEvent.id, reservation1)
await eventService.addReservation(newEvent.id, reservation2)
const reservations = await eventService.getAllReservations(newEvent.id)
expect(reservations.length).toBe(2)
expect(reservations).toContainEqual(reservation1)
expect(reservations).toContainEqual(reservation2)
})

it("Should be able to update an event reservation", async () => {
const newEvent = await eventService.createEvent(event1)

const reservation = await eventService.addReservation(
newEvent.id,
reservation1
)

await eventService.updateReservation(newEvent.id, reservation.id, {
first_name: "Jan"
})

const fetchedReservation = await FirestoreCollections.events
.doc(newEvent.id)
.collection("reservations") // subject to place as a constant somewhere
.doc(reservation.id)
.get()

expect(fetchedReservation.data().first_name).toBe("Jan")
})

it("Should be able to delete an event reservation", async () => {
const newEvent = await eventService.createEvent(event1)

const reservation = await eventService.addReservation(
newEvent.id,
reservation1
)

await eventService.deleteReservation(newEvent.id, reservation.id)

const fetchedReservation = await FirestoreCollections.events
.doc(newEvent.id)
.collection("reservations") // subject to place as a constant somewhere
.doc(reservation.id)
.get()
expect(fetchedReservation.data()).toBe(undefined)
})
})
})
Loading

0 comments on commit 79f3c70

Please sign in to comment.