Skip to content

Commit df4e05e

Browse files
authored
Add get notification endpoint (#190)
1 parent 836c55d commit df4e05e

File tree

6 files changed

+285
-0
lines changed

6 files changed

+285
-0
lines changed

library/src/commonMain/kotlin/com/ioki/passenger/api/IokiService.kt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ import com.ioki.passenger.api.models.ApiLogPayAccountRequest
3737
import com.ioki.passenger.api.models.ApiLogPayType
3838
import com.ioki.passenger.api.models.ApiLogPayUrlResponse
3939
import com.ioki.passenger.api.models.ApiMarketingResponse
40+
import com.ioki.passenger.api.models.ApiNotificationResponse
4041
import com.ioki.passenger.api.models.ApiPassengerSelectionRequest
4142
import com.ioki.passenger.api.models.ApiPaymentMethodCreationRequest
4243
import com.ioki.passenger.api.models.ApiPaymentMethodResponse
@@ -214,6 +215,8 @@ public interface NotificationService {
214215
request: ApiUpdateUserNotificationSettingsRequest,
215216
userId: String,
216217
): ApiResult<ApiUserNotificationSettingsResponse>
218+
219+
public suspend fun getNotification(id: String): ApiResult<ApiNotificationResponse>
217220
}
218221

219222
public interface CurrentRideService {
@@ -879,6 +882,11 @@ private class DefaultIokiService(
879882
geocodingDetails(id = sessionId, body = ApiBody(request))
880883
}
881884

885+
override suspend fun getNotification(id: String): ApiResult<ApiNotificationResponse> =
886+
apiCall<ApiBody<ApiNotificationResponse>, ApiNotificationResponse> {
887+
getNotification(id)
888+
}
889+
882890
private suspend inline fun <reified R, reified T> apiCall(
883891
crossinline block: suspend IokiApi.() -> HttpResponse,
884892
): ApiResult<T> {

library/src/commonMain/kotlin/com/ioki/passenger/api/internal/api/IokiApi.kt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -527,6 +527,10 @@ internal class IokiApi(
527527
header("Authorization", accessToken)
528528
setBody(body)
529529
}
530+
531+
suspend fun getNotification(id: String): HttpResponse = client.get(urlString = "/api/passenger/notifications/$id") {
532+
header("Authorization", accessToken)
533+
}
530534
}
531535

532536
private fun ApiPurchaseFilter.toStringValues(): StringValues = StringValues.build {
Lines changed: 194 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,194 @@
1+
package com.ioki.passenger.api.models
2+
3+
import com.ioki.passenger.api.models.ApiNotificationResponse.NotificationType
4+
import kotlin.time.Instant
5+
import kotlinx.serialization.KSerializer
6+
import kotlinx.serialization.SerialName
7+
import kotlinx.serialization.Serializable
8+
import kotlinx.serialization.builtins.serializer
9+
import kotlinx.serialization.encoding.Decoder
10+
import kotlinx.serialization.encoding.Encoder
11+
12+
@Serializable
13+
public data class ApiNotificationResponse(
14+
val id: String,
15+
val body: String,
16+
val channels: List<String>,
17+
@SerialName(value = "notification_type") val notificationType: NotificationType,
18+
@SerialName(value = "created_at") val createdAt: Instant,
19+
@SerialName(value = "updated_at") val updatedAt: Instant?,
20+
@SerialName(value = "delivered_at") val deliveredAt: Instant?,
21+
) {
22+
@Serializable(with = ApiNotificationResponseNotificationTypeSerializer::class)
23+
public enum class NotificationType {
24+
@SerialName(value = "vehicle_soon_reaches_pickup")
25+
VEHICLE_SOON_REACHES_PICKUP,
26+
27+
@SerialName(value = "vehicle_soon_reaches_dropoff")
28+
VEHICLE_SOON_REACHES_DROP_OFF,
29+
30+
@SerialName(value = "vehicle_waiting_at_pickup")
31+
VEHICLE_WAITING_AT_PICKUP,
32+
33+
@SerialName(value = "vehicle_reached_pickup")
34+
VEHICLE_REACHED_PICKUP,
35+
36+
@SerialName(value = "pickup_time_changed")
37+
PICKUP_TIME_CHANGED,
38+
39+
@SerialName(value = "driver_completed_dropoff")
40+
DRIVER_COMPLETED_DROP_OFF,
41+
42+
@SerialName(value = "driver_cancelled_booked_ride")
43+
DRIVER_CANCELLED_BOOKED_RIDE,
44+
45+
@SerialName(value = "driver_cancelled_charge_no_show_fee")
46+
DRIVER_CANCELLED_CHARGE_NO_SHOW_FEE,
47+
48+
@SerialName(value = "early_prebooking_reminder")
49+
EARLY_PREBOOKING_REMINDER,
50+
51+
@SerialName(value = "late_prebooking_reminder")
52+
LATE_PREBOOKING_REMINDER,
53+
54+
@SerialName(value = "passenger_booked")
55+
PASSENGER_BOOKED,
56+
57+
@SerialName(value = "passenger_cancelled_booked_ride")
58+
PASSENGER_CANCELLED_BOOKED_RIDE,
59+
60+
@SerialName(value = "operator_cancelled_notify_passenger")
61+
OPERATOR_CANCELLED_NOTIFY_PASSENGER,
62+
63+
@SerialName(value = "broadcast")
64+
BROADCAST,
65+
66+
@SerialName(value = "end_of_pause_reminder")
67+
END_OF_PAUSE_REMINDER,
68+
69+
@SerialName(value = "payment_method_detached")
70+
PAYMENT_METHOD_DETACHED,
71+
72+
@SerialName(value = "referral_benefit_assigned")
73+
REFERRAL_BENEFIT_ASSIGNED,
74+
75+
@SerialName(value = "missing_ticket_reminder")
76+
MISSING_TICKET_REMINDER,
77+
78+
@SerialName(value = "pooling_incoming")
79+
POOLING_INCOMING,
80+
81+
@SerialName(value = "cancelled_because_of_paypal_reservation_failure")
82+
CANCELLED_BECAUSE_OF_PAYPAL_RESERVATION_FAILURE,
83+
84+
@SerialName(value = "cancelled_because_of_failed_logpay_active_customer_check")
85+
CANCELLED_BECAUSE_OF_FAILED_LOGPAY_ACTIVE_CUSTOMER_CHECK,
86+
87+
@SerialName(value = "booking_confirmed")
88+
BOOKING_CONFIRMED,
89+
90+
@SerialName(value = "booking_confirmed_by_operator")
91+
BOOKING_CONFIRMED_BY_OPERATOR,
92+
93+
@SerialName(value = "payment_failed")
94+
PAYMENT_FAILED,
95+
96+
@SerialName(value = "renewable_ticketing_voucher")
97+
RENEWABLE_TICKETING_VOUCHER,
98+
99+
@SerialName(value = "ride_series_will_expire")
100+
RIDE_SERIES_WILL_EXPIRE,
101+
102+
@SerialName(value = "ticket_purchase_failed")
103+
TICKET_PURCHASE_FAILED,
104+
105+
@SerialName(value = "user_inactivity_reminder")
106+
USER_INACTIVITY_REMINDER,
107+
108+
@SerialName(value = "final_user_inactivity_reminder")
109+
FINAL_USER_INACTIVITY_REMINDER,
110+
111+
@SerialName(value = "user_inactivity_discontinued")
112+
USER_INACTIVITY_DISCONTINUED,
113+
UNSUPPORTED,
114+
}
115+
}
116+
117+
internal object ApiNotificationResponseNotificationTypeSerializer : KSerializer<NotificationType> {
118+
override val descriptor = String.serializer().descriptor
119+
override fun deserialize(decoder: Decoder): NotificationType = when (decoder.decodeString()) {
120+
"vehicle_soon_reaches_pickup" -> NotificationType.VEHICLE_SOON_REACHES_PICKUP
121+
"vehicle_soon_reaches_dropoff" -> NotificationType.VEHICLE_SOON_REACHES_DROP_OFF
122+
"vehicle_waiting_at_pickup" -> NotificationType.VEHICLE_WAITING_AT_PICKUP
123+
"vehicle_reached_pickup" -> NotificationType.VEHICLE_REACHED_PICKUP
124+
"pickup_time_changed" -> NotificationType.PICKUP_TIME_CHANGED
125+
"driver_completed_dropoff" -> NotificationType.DRIVER_COMPLETED_DROP_OFF
126+
"driver_cancelled_booked_ride" -> NotificationType.DRIVER_CANCELLED_BOOKED_RIDE
127+
"driver_cancelled_charge_no_show_fee" -> NotificationType.DRIVER_CANCELLED_CHARGE_NO_SHOW_FEE
128+
"early_prebooking_reminder" -> NotificationType.EARLY_PREBOOKING_REMINDER
129+
"late_prebooking_reminder" -> NotificationType.LATE_PREBOOKING_REMINDER
130+
"passenger_booked" -> NotificationType.PASSENGER_BOOKED
131+
"passenger_cancelled_booked_ride" -> NotificationType.PASSENGER_CANCELLED_BOOKED_RIDE
132+
"operator_cancelled_notify_passenger" -> NotificationType.OPERATOR_CANCELLED_NOTIFY_PASSENGER
133+
"broadcast" -> NotificationType.BROADCAST
134+
"end_of_pause_reminder" -> NotificationType.END_OF_PAUSE_REMINDER
135+
"payment_method_detached" -> NotificationType.PAYMENT_METHOD_DETACHED
136+
"referral_benefit_assigned" -> NotificationType.REFERRAL_BENEFIT_ASSIGNED
137+
"missing_ticket_reminder" -> NotificationType.MISSING_TICKET_REMINDER
138+
"pooling_incoming" -> NotificationType.POOLING_INCOMING
139+
"booking_confirmed" -> NotificationType.BOOKING_CONFIRMED
140+
"booking_confirmed_by_operator" -> NotificationType.BOOKING_CONFIRMED_BY_OPERATOR
141+
"payment_failed" -> NotificationType.PAYMENT_FAILED
142+
"renewable_ticketing_voucher" -> NotificationType.RENEWABLE_TICKETING_VOUCHER
143+
"ride_series_will_expire" -> NotificationType.RIDE_SERIES_WILL_EXPIRE
144+
"ticket_purchase_failed" -> NotificationType.TICKET_PURCHASE_FAILED
145+
"user_inactivity_reminder" -> NotificationType.USER_INACTIVITY_REMINDER
146+
"final_user_inactivity_reminder" -> NotificationType.FINAL_USER_INACTIVITY_REMINDER
147+
"user_inactivity_discontinued" -> NotificationType.USER_INACTIVITY_DISCONTINUED
148+
"cancelled_because_of_paypal_reservation_failure" ->
149+
NotificationType.CANCELLED_BECAUSE_OF_PAYPAL_RESERVATION_FAILURE
150+
"cancelled_because_of_failed_logpay_active_customer_check" ->
151+
NotificationType.CANCELLED_BECAUSE_OF_FAILED_LOGPAY_ACTIVE_CUSTOMER_CHECK
152+
else -> NotificationType.UNSUPPORTED
153+
}
154+
155+
override fun serialize(encoder: Encoder, value: NotificationType) {
156+
encoder.encodeString(
157+
when (value) {
158+
NotificationType.VEHICLE_SOON_REACHES_PICKUP -> "vehicle_soon_reaches_pickup"
159+
NotificationType.VEHICLE_SOON_REACHES_DROP_OFF -> "vehicle_soon_reaches_dropoff"
160+
NotificationType.VEHICLE_WAITING_AT_PICKUP -> "vehicle_waiting_at_pickup"
161+
NotificationType.VEHICLE_REACHED_PICKUP -> "vehicle_reached_pickup"
162+
NotificationType.PICKUP_TIME_CHANGED -> "pickup_time_changed"
163+
NotificationType.DRIVER_COMPLETED_DROP_OFF -> "driver_completed_dropoff"
164+
NotificationType.DRIVER_CANCELLED_BOOKED_RIDE -> "driver_cancelled_booked_ride"
165+
NotificationType.DRIVER_CANCELLED_CHARGE_NO_SHOW_FEE -> "driver_cancelled_charge_no_show_fee"
166+
NotificationType.EARLY_PREBOOKING_REMINDER -> "early_prebooking_reminder"
167+
NotificationType.LATE_PREBOOKING_REMINDER -> "late_prebooking_reminder"
168+
NotificationType.PASSENGER_BOOKED -> "passenger_booked"
169+
NotificationType.PASSENGER_CANCELLED_BOOKED_RIDE -> "passenger_cancelled_booked_ride"
170+
NotificationType.OPERATOR_CANCELLED_NOTIFY_PASSENGER -> "operator_cancelled_notify_passenger"
171+
NotificationType.BROADCAST -> "broadcast"
172+
NotificationType.END_OF_PAUSE_REMINDER -> "end_of_pause_reminder"
173+
NotificationType.PAYMENT_METHOD_DETACHED -> "payment_method_detached"
174+
NotificationType.REFERRAL_BENEFIT_ASSIGNED -> "referral_benefit_assigned"
175+
NotificationType.MISSING_TICKET_REMINDER -> "missing_ticket_reminder"
176+
NotificationType.POOLING_INCOMING -> "pooling_incoming"
177+
NotificationType.BOOKING_CONFIRMED -> "booking_confirmed"
178+
NotificationType.BOOKING_CONFIRMED_BY_OPERATOR -> "booking_confirmed_by_operator"
179+
NotificationType.PAYMENT_FAILED -> "payment_failed"
180+
NotificationType.RENEWABLE_TICKETING_VOUCHER -> "renewable_ticketing_voucher"
181+
NotificationType.RIDE_SERIES_WILL_EXPIRE -> "ride_series_will_expire"
182+
NotificationType.TICKET_PURCHASE_FAILED -> "ticket_purchase_failed"
183+
NotificationType.USER_INACTIVITY_REMINDER -> "user_inactivity_reminder"
184+
NotificationType.FINAL_USER_INACTIVITY_REMINDER -> "final_user_inactivity_reminder"
185+
NotificationType.USER_INACTIVITY_DISCONTINUED -> "user_inactivity_discontinued"
186+
NotificationType.CANCELLED_BECAUSE_OF_PAYPAL_RESERVATION_FAILURE ->
187+
"cancelled_because_of_paypal_reservation_failure"
188+
NotificationType.CANCELLED_BECAUSE_OF_FAILED_LOGPAY_ACTIVE_CUSTOMER_CHECK ->
189+
"cancelled_because_of_failed_logpay_active_customer_check"
190+
NotificationType.UNSUPPORTED -> "unsupported"
191+
},
192+
)
193+
}
194+
}
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
package com.ioki.passenger.api.models
2+
3+
import kotlin.test.Test
4+
import kotlin.time.Instant
5+
6+
internal class ApiNotificationResponseTest : IokiApiModelTest() {
7+
@Test
8+
fun serialization() {
9+
testJsonStringCanBeConvertedToModel(
10+
ApiNotificationResponse(
11+
id = "notificationId",
12+
body = "This is the body of the notification.",
13+
notificationType = ApiNotificationResponse.NotificationType.PASSENGER_BOOKED,
14+
createdAt = Instant.parse("2023-07-19T13:17:42Z"),
15+
updatedAt = Instant.parse("2023-07-19T13:18:42Z"),
16+
deliveredAt = Instant.parse("2023-07-19T13:19:42Z"),
17+
channels = listOf("push"),
18+
),
19+
notificationResponse,
20+
)
21+
}
22+
23+
@Test
24+
fun serializationMinimal() {
25+
testJsonStringCanBeConvertedToModel(
26+
ApiNotificationResponse(
27+
id = "notificationId",
28+
body = "This is the body of the notification.",
29+
notificationType = ApiNotificationResponse.NotificationType.PICKUP_TIME_CHANGED,
30+
createdAt = Instant.parse("2023-07-19T13:17:42Z"),
31+
updatedAt = null,
32+
deliveredAt = null,
33+
channels = emptyList(),
34+
),
35+
notificationResponseMinimal,
36+
)
37+
}
38+
}
39+
40+
private val notificationResponse =
41+
"""
42+
{
43+
"id": "notificationId",
44+
"created_at": "2023-07-19T13:17:42Z",
45+
"updated_at": "2023-07-19T13:18:42Z",
46+
"delivered_at": "2023-07-19T13:19:42Z",
47+
"notification_type": "passenger_booked",
48+
"body": "This is the body of the notification.",
49+
"channels": ["push"]
50+
}
51+
"""
52+
53+
private val notificationResponseMinimal =
54+
"""
55+
{
56+
"id": "notificationId",
57+
"created_at": "2023-07-19T13:17:42Z",
58+
"notification_type": "pickup_time_changed",
59+
"body": "This is the body of the notification.",
60+
"channels": []
61+
}
62+
"""

test/src/commonMain/kotlin/com/ioki/passenger/api/test/FakeNotificationService.kt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package com.ioki.passenger.api.test
22

33
import com.ioki.passenger.api.NotificationService
4+
import com.ioki.passenger.api.models.ApiNotificationResponse
45
import com.ioki.passenger.api.models.ApiProviderNotificationSettingsResponse
56
import com.ioki.passenger.api.models.ApiUpdateUserNotificationSettingsRequest
67
import com.ioki.passenger.api.models.ApiUserNotificationSettingsResponse
@@ -22,4 +23,6 @@ public open class FakeNotificationService : NotificationService {
2223
request: ApiUpdateUserNotificationSettingsRequest,
2324
userId: String,
2425
): ApiResult<ApiUserNotificationSettingsResponse> = error("Not overridden")
26+
27+
override suspend fun getNotification(id: String): ApiResult<ApiNotificationResponse> = error("Not overridden")
2528
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
package com.ioki.passenger.api.test.models
2+
3+
import com.ioki.passenger.api.models.ApiNotificationResponse
4+
import kotlin.time.Instant
5+
6+
public fun createApiNotificationResponse(): ApiNotificationResponse = ApiNotificationResponse(
7+
id = "",
8+
body = "",
9+
createdAt = Instant.DISTANT_PAST,
10+
updatedAt = null,
11+
deliveredAt = null,
12+
notificationType = ApiNotificationResponse.NotificationType.UNSUPPORTED,
13+
channels = emptyList(),
14+
)

0 commit comments

Comments
 (0)