Skip to content

Commit 6777e4f

Browse files
authored
Merge pull request #23 from SwEnt-Group13/feature/event-repository-model
feat(model/event): Implement event repository
2 parents 2296638 + bab279a commit 6777e4f

File tree

6 files changed

+328
-0
lines changed

6 files changed

+328
-0
lines changed
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
package com.android.unio.model.event
2+
3+
import com.android.unio.model.map.Location
4+
import com.google.firebase.Timestamp
5+
import java.util.Date
6+
7+
data class Event(
8+
val uid: String = "",
9+
val title: String = "",
10+
val organisers: List<String> = mutableListOf<String>(),
11+
val taggedAssociations: List<String> = mutableListOf<String>(),
12+
val image: String = "",
13+
val description: String = "",
14+
val catchyDescription: String = "",
15+
val price: Double = 0.0,
16+
val date: Timestamp = Timestamp(Date()),
17+
val location: Location = Location(),
18+
val types: List<String> = mutableListOf<String>()
19+
)
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
package com.android.unio.model.event
2+
3+
import com.google.firebase.Timestamp
4+
5+
interface EventRepository {
6+
fun getEventsOfAssociation(
7+
association: String,
8+
onSuccess: (List<Event>) -> Unit,
9+
onFailure: (Exception) -> Unit
10+
)
11+
12+
fun getNextEventsFromDateToDate(
13+
startDate: Timestamp,
14+
endDate: Timestamp,
15+
onSuccess: (List<Event>) -> Unit,
16+
onFailure: (Exception) -> Unit
17+
)
18+
19+
fun getEvents(onSuccess: (List<Event>) -> Unit, onFailure: (Exception) -> Unit)
20+
21+
fun getNewUid(): String
22+
23+
fun addEvent(event: Event, onSuccess: () -> Unit, onFailure: (Exception) -> Unit)
24+
25+
fun deleteEventById(id: String, onSuccess: () -> Unit, onFailure: (Exception) -> Unit)
26+
}
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
package com.android.unio.model.event
2+
3+
import android.util.Log
4+
import com.google.firebase.Timestamp
5+
import com.google.firebase.firestore.DocumentSnapshot
6+
import com.google.firebase.firestore.FirebaseFirestore
7+
8+
class EventRepositoryFirestore(private val db: FirebaseFirestore) : EventRepository {
9+
10+
override fun getEventsOfAssociation(
11+
association: String,
12+
onSuccess: (List<Event>) -> Unit,
13+
onFailure: (Exception) -> Unit
14+
) {
15+
db.collection(EVENT_PATH)
16+
.whereArrayContains("organisers", association)
17+
.get()
18+
.addOnSuccessListener { result ->
19+
val events = result.mapNotNull { event -> hydrate(event) }
20+
onSuccess(events)
21+
}
22+
.addOnFailureListener { exception -> onFailure(exception) }
23+
}
24+
25+
override fun getNextEventsFromDateToDate(
26+
startDate: Timestamp,
27+
endDate: Timestamp,
28+
onSuccess: (List<Event>) -> Unit,
29+
onFailure: (Exception) -> Unit
30+
) {
31+
db.collection(EVENT_PATH)
32+
.whereGreaterThanOrEqualTo("date", startDate)
33+
.whereLessThan("date", endDate)
34+
.get()
35+
.addOnSuccessListener { result ->
36+
val events = result.mapNotNull { event -> hydrate(event) }
37+
onSuccess(events)
38+
}
39+
.addOnFailureListener { exception -> onFailure(exception) }
40+
}
41+
42+
override fun getEvents(onSuccess: (List<Event>) -> Unit, onFailure: (Exception) -> Unit) {
43+
db.collection(EVENT_PATH)
44+
.get()
45+
.addOnSuccessListener { result ->
46+
val events = result.mapNotNull { doc -> hydrate(doc) }
47+
onSuccess(events)
48+
}
49+
.addOnFailureListener { exception -> onFailure(exception) }
50+
}
51+
52+
override fun getNewUid(): String {
53+
return db.collection(EVENT_PATH).document().id
54+
}
55+
56+
override fun addEvent(event: Event, onSuccess: () -> Unit, onFailure: (Exception) -> Unit) {
57+
if (event.uid.isBlank()) {
58+
onFailure(IllegalArgumentException("No event id was provided"))
59+
} else {
60+
db.collection(EVENT_PATH).document(event.uid).set(event).addOnCompleteListener { task ->
61+
if (task.isSuccessful) {
62+
onSuccess()
63+
} else {
64+
onFailure(task.exception ?: Exception("Failed to add an event"))
65+
}
66+
}
67+
}
68+
}
69+
70+
override fun deleteEventById(id: String, onSuccess: () -> Unit, onFailure: (Exception) -> Unit) {
71+
db.collection(EVENT_PATH).document(id).delete().addOnCompleteListener { task ->
72+
if (task.isSuccessful) {
73+
onSuccess()
74+
} else {
75+
onFailure(task.exception ?: Exception("Failed to delete event"))
76+
}
77+
}
78+
}
79+
80+
private fun hydrate(doc: DocumentSnapshot): Event? {
81+
82+
val event = doc.toObject(Event::class.java)
83+
if (event == null) {
84+
Log.e("EventRepositoryFirestore", "Error while converting db document to Event object")
85+
}
86+
return event
87+
}
88+
89+
companion object {
90+
private const val EVENT_PATH = "events"
91+
}
92+
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
package com.android.unio.model.map
2+
3+
data class Location(val latitude: Double = 0.0, val longitude: Double = 0.0, val name: String = "")
Lines changed: 187 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,187 @@
1+
package com.android.unio.model.event
2+
3+
import com.android.unio.model.map.Location
4+
import com.google.android.gms.tasks.OnSuccessListener
5+
import com.google.android.gms.tasks.Task
6+
import com.google.firebase.Timestamp
7+
import com.google.firebase.firestore.CollectionReference
8+
import com.google.firebase.firestore.DocumentReference
9+
import com.google.firebase.firestore.FirebaseFirestore
10+
import com.google.firebase.firestore.Query
11+
import com.google.firebase.firestore.QueryDocumentSnapshot
12+
import com.google.firebase.firestore.QuerySnapshot
13+
import java.util.GregorianCalendar
14+
import junit.framework.TestCase.assertEquals
15+
import org.junit.Assert.assertThrows
16+
import org.junit.Before
17+
import org.junit.Test
18+
import org.mockito.Mock
19+
import org.mockito.Mockito.`when`
20+
import org.mockito.MockitoAnnotations
21+
import org.mockito.kotlin.any
22+
import org.mockito.kotlin.eq
23+
24+
class EventRepositoryFirestoreTest {
25+
@Mock private lateinit var db: FirebaseFirestore
26+
27+
@Mock private lateinit var collectionReference: CollectionReference
28+
29+
@Mock private lateinit var documentReference: DocumentReference
30+
31+
@Mock private lateinit var query: Query
32+
33+
@Mock private lateinit var querySnapshot: QuerySnapshot
34+
35+
@Mock private lateinit var queryDocumentSnapshot1: QueryDocumentSnapshot
36+
37+
@Mock private lateinit var queryDocumentSnapshot2: QueryDocumentSnapshot
38+
39+
@Mock private lateinit var queryDocumentSnapshot3: QueryDocumentSnapshot
40+
41+
@Mock private lateinit var getTask: Task<QuerySnapshot>
42+
43+
@Mock private lateinit var voidTask: Task<Void>
44+
45+
private lateinit var repository: EventRepositoryFirestore
46+
private val defaultEvent = Event()
47+
private val event1 =
48+
Event(
49+
uid = "1",
50+
title = "Balelec",
51+
organisers = mutableListOf("Balelec, EPFL"),
52+
image = "",
53+
description = "Plus grand festival du monde (non contractuel)",
54+
price = 40.5,
55+
date = Timestamp(GregorianCalendar(2004, 7, 1).time),
56+
location = Location(1.2345, 2.3455, "Somewhere"))
57+
private val event3 =
58+
Event(
59+
uid = "3",
60+
title = "Tremplin Sysmic",
61+
organisers = mutableListOf("Sysmic, EPFL"),
62+
image = "",
63+
description = "Plus grand festival du monde (non contractuel)",
64+
price = 40.5,
65+
date = Timestamp(GregorianCalendar(2008, 7, 1).time),
66+
location = Location(1.2345, 2.3455, "Somewhere"))
67+
68+
@Before
69+
fun setUp() {
70+
MockitoAnnotations.openMocks(this)
71+
72+
// When getting the collection, return the task
73+
`when`(db.collection(eq("events"))).thenReturn(collectionReference)
74+
`when`(collectionReference.get()).thenReturn(getTask)
75+
76+
// When the task is successful, return the query snapshot
77+
`when`(getTask.addOnSuccessListener(any())).thenAnswer { invocation ->
78+
val callback = invocation.arguments[0] as OnSuccessListener<QuerySnapshot>
79+
callback.onSuccess(querySnapshot)
80+
getTask
81+
}
82+
83+
// When the query snapshot is iterated, return the two query document snapshots
84+
`when`(querySnapshot.iterator())
85+
.thenReturn(
86+
mutableListOf(queryDocumentSnapshot1, queryDocumentSnapshot2, queryDocumentSnapshot3)
87+
.iterator())
88+
89+
`when`(queryDocumentSnapshot1.toObject(Event::class.java)).thenReturn(event1)
90+
`when`(queryDocumentSnapshot2.toObject(Event::class.java)).thenReturn(defaultEvent)
91+
`when`(queryDocumentSnapshot3.toObject(Event::class.java)).thenReturn(event3)
92+
93+
repository = EventRepositoryFirestore(db)
94+
}
95+
96+
/** Asserts that getEvents returns all events */
97+
@Test
98+
fun testGetEvents() {
99+
100+
repository.getEvents(
101+
onSuccess = { events ->
102+
assertEquals(3, events.size)
103+
assert(events.contains(event1))
104+
assert(events.contains(defaultEvent))
105+
assert(events.contains(event3))
106+
},
107+
onFailure = { e -> throw e })
108+
}
109+
110+
/** Asserts that getEventsOfAssociation calls the right methods. */
111+
@Test
112+
fun testGetEventsOfAssociation() {
113+
val asso1 = "Balelec"
114+
val asso2 = "EPFL"
115+
`when`(collectionReference.whereArrayContains("organisers", asso1)).thenReturn(query)
116+
`when`(query.get()).thenReturn(getTask)
117+
`when`(querySnapshot.iterator()).thenReturn(mutableListOf(queryDocumentSnapshot1).iterator())
118+
119+
repository.getEventsOfAssociation(
120+
"Balelec",
121+
onSuccess = { events ->
122+
assertEquals(1, events.size)
123+
assertEquals(event1, events[0])
124+
},
125+
onFailure = { e -> throw e })
126+
127+
`when`(collectionReference.whereArrayContains("organisers", asso2)).thenReturn(query)
128+
`when`(querySnapshot.iterator())
129+
.thenReturn(mutableListOf(queryDocumentSnapshot1, queryDocumentSnapshot3).iterator())
130+
131+
repository.getEventsOfAssociation(
132+
"EPFL",
133+
onSuccess = { events ->
134+
assertEquals(2, events.size)
135+
assert(events.contains(event1))
136+
assert(events.contains(event3))
137+
},
138+
onFailure = { e -> throw e })
139+
}
140+
141+
/** Asserts that getNextEventsFromDateToDate calls the right methods. */
142+
@Test
143+
fun testGetNextEventsFromDateToDate() {
144+
val startDate = Timestamp(GregorianCalendar(2003, 7, 1).time)
145+
val endDate = Timestamp(GregorianCalendar(2005, 7, 1).time)
146+
`when`(collectionReference.whereGreaterThanOrEqualTo("date", startDate)).thenReturn(query)
147+
`when`(query.whereLessThan("date", endDate)).thenReturn(query)
148+
`when`(query.get()).thenReturn(getTask)
149+
`when`(querySnapshot.iterator()).thenReturn(mutableListOf(queryDocumentSnapshot1).iterator())
150+
151+
repository.getNextEventsFromDateToDate(
152+
startDate,
153+
endDate,
154+
{ events ->
155+
assertEquals(events.size, 1)
156+
assert(events.contains(event1))
157+
},
158+
{ e -> throw e })
159+
}
160+
161+
/** Asserts that db.collection(EVENT_PATH).document(event.uid).set(event) is called */
162+
@Test
163+
fun testAddEvent() {
164+
`when`(collectionReference.document(event1.uid)).thenReturn(documentReference)
165+
`when`(documentReference.set(event1)).thenReturn(voidTask)
166+
repository.addEvent(event1, {}, { e -> throw e })
167+
}
168+
169+
/**
170+
* Assert that calling addEvent with an event that has a blank id return an
171+
* IllegalArgumentException.
172+
*/
173+
@Test
174+
fun testAddEventBlankId() {
175+
repository.addEvent(defaultEvent, {}) { e ->
176+
assertThrows(IllegalArgumentException::class.java) { throw e }
177+
}
178+
}
179+
180+
/** Assert that deleteEventById calls db.collection(EVENT_PATH).document(id).delete() */
181+
@Test
182+
fun testDeleteEventById() {
183+
`when`(collectionReference.document(event1.uid)).thenReturn(documentReference)
184+
`when`(documentReference.delete()).thenReturn(voidTask)
185+
repository.deleteEventById(event1.uid, {}, { e -> throw e })
186+
}
187+
}

gradle/libs.versions.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ lifecycleRuntimeKtx = "2.8.6"
7474
fragmentKtx = "1.8.3"
7575
kotlinxSerializationJson = "1.6.3"
7676
androidxCoreKtx = "1.6.1"
77+
firebaseCommonKtx = "21.0.0"
7778

7879
[libraries]
7980
compose-bom = { group = "androidx.compose", name = "compose-bom", version.ref = "composeBom" }

0 commit comments

Comments
 (0)