Skip to content

Commit 6839f4c

Browse files
authored
Merge pull request #1842 from OneSignal/fix/timezone_id_not_set
Fix timezone_id not being set
2 parents 2de5c46 + 7bd784f commit 6839f4c

File tree

6 files changed

+46
-35
lines changed

6 files changed

+46
-35
lines changed

OneSignalSDK/onesignal/core/src/main/java/com/onesignal/common/TimeUtils.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ object TimeUtils {
1717
return offset / 1000
1818
}
1919

20-
fun getTimeZoneId(): String? {
20+
fun getTimeZoneId(): String {
2121
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
2222
ZoneId.systemDefault().id
2323
} else {

OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/internal/backend/IUserBackendService.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,11 @@ interface IUserBackendService {
1414
* the application.
1515
* @param subscriptions The subscriptions that should also be created and associated with the user. If subscriptions are already owned by a different user
1616
* they will be transferred to this user.
17+
* @param properties The properties for this user. For new users this should include the timezone_id property.
1718
*
1819
* @return The backend response
1920
*/
20-
suspend fun createUser(appId: String, identities: Map<String, String>, subscriptions: List<SubscriptionObject>): CreateUserResponse
21+
suspend fun createUser(appId: String, identities: Map<String, String>, subscriptions: List<SubscriptionObject>, properties: Map<String, String>): CreateUserResponse
2122
// TODO: Change to send only the push subscription, optimally
2223

2324
/**

OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/internal/backend/impl/UserBackendService.kt

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ internal class UserBackendService(
1414
private val _httpClient: IHttpClient,
1515
) : IUserBackendService {
1616

17-
override suspend fun createUser(appId: String, identities: Map<String, String>, subscriptions: List<SubscriptionObject>): CreateUserResponse {
17+
override suspend fun createUser(appId: String, identities: Map<String, String>, subscriptions: List<SubscriptionObject>, properties: Map<String, String>): CreateUserResponse {
1818
val requestJSON = JSONObject()
1919

2020
if (identities.isNotEmpty()) {
@@ -26,6 +26,10 @@ internal class UserBackendService(
2626
.put("subscriptions", JSONConverter.convertToJSON(subscriptions))
2727
}
2828

29+
if (properties.isNotEmpty()) {
30+
requestJSON.put("properties", JSONObject().putMap(properties))
31+
}
32+
2933
val response = _httpClient.post("apps/$appId/users", requestJSON)
3034

3135
if (!response.isSuccess) {

OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/internal/operations/impl/executors/LoginUserOperationExecutor.kt

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,7 @@
11
package com.onesignal.user.internal.operations.impl.executors
22

33
import android.os.Build
4-
import com.onesignal.common.AndroidUtils
5-
import com.onesignal.common.DeviceUtils
6-
import com.onesignal.common.NetworkUtils
7-
import com.onesignal.common.OneSignalUtils
8-
import com.onesignal.common.RootToolsInternalMethods
4+
import com.onesignal.common.*
95
import com.onesignal.common.exceptions.BackendException
106
import com.onesignal.common.modeling.ModelChangeTags
117
import com.onesignal.core.internal.application.IApplicationService
@@ -16,10 +12,8 @@ import com.onesignal.core.internal.operations.ExecutionResult
1612
import com.onesignal.core.internal.operations.IOperationExecutor
1713
import com.onesignal.core.internal.operations.Operation
1814
import com.onesignal.debug.internal.logging.Logging
19-
import com.onesignal.user.internal.backend.IUserBackendService
15+
import com.onesignal.user.internal.backend.*
2016
import com.onesignal.user.internal.backend.IdentityConstants
21-
import com.onesignal.user.internal.backend.SubscriptionObject
22-
import com.onesignal.user.internal.backend.SubscriptionObjectType
2317
import com.onesignal.user.internal.identity.IdentityModelStore
2418
import com.onesignal.user.internal.operations.CreateSubscriptionOperation
2519
import com.onesignal.user.internal.operations.DeleteSubscriptionOperation
@@ -106,6 +100,8 @@ internal class LoginUserOperationExecutor(
106100
private suspend fun createUser(createUserOperation: LoginUserOperation, operations: List<Operation>): ExecutionResponse {
107101
var identities = mapOf<String, String>()
108102
var subscriptions = mapOf<String, SubscriptionObject>()
103+
val properties = mutableMapOf<String, String>()
104+
properties["timezone_id"] = TimeUtils.getTimeZoneId()
109105

110106
if (createUserOperation.externalId != null) {
111107
val mutableIdentities = identities.toMutableMap()
@@ -125,7 +121,7 @@ internal class LoginUserOperationExecutor(
125121

126122
try {
127123
val subscriptionList = subscriptions.toList()
128-
val response = _userBackend.createUser(createUserOperation.appId, identities, subscriptionList.map { it.second })
124+
val response = _userBackend.createUser(createUserOperation.appId, identities, subscriptionList.map { it.second }, properties)
129125
val idTranslations = mutableMapOf<String, String>()
130126
// Add the "local-to-backend" ID translation to the IdentifierTranslator for any operations that were
131127
// *not* executed but still reference the locally-generated IDs.

OneSignalSDK/onesignal/core/src/test/java/com/onesignal/user/internal/backend/UserBackendServiceTests.kt

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -28,11 +28,12 @@ class UserBackendServiceTests : FunSpec({
2828
coEvery { spyHttpClient.post(any(), any()) } returns HttpResponse(403, "FORBIDDEN")
2929
val userBackendService = UserBackendService(spyHttpClient)
3030
val identities = mapOf<String, String>()
31+
val properties = mapOf<String, String>()
3132
val subscriptions = listOf<SubscriptionObject>()
3233

3334
/* When */
3435
val exception = shouldThrowUnit<BackendException> {
35-
userBackendService.createUser("appId", identities, subscriptions)
36+
userBackendService.createUser("appId", identities, subscriptions, properties)
3637
}
3738

3839
/* Then */
@@ -44,17 +45,19 @@ class UserBackendServiceTests : FunSpec({
4445
/* Given */
4546
val osId = "11111111-1111-1111-1111-111111111111"
4647
val spyHttpClient = mockk<IHttpClient>()
47-
coEvery { spyHttpClient.post(any(), any()) } returns HttpResponse(202, "{identity:{onesignal_id: \"$osId\", aliasLabel1: \"aliasValue1\"}}")
48+
coEvery { spyHttpClient.post(any(), any()) } returns HttpResponse(202, "{identity:{onesignal_id: \"$osId\", aliasLabel1: \"aliasValue1\"}, properties:{timezone_id: \"testTimeZone\"}}")
4849
val userBackendService = UserBackendService(spyHttpClient)
4950
val identities = mapOf("aliasLabel1" to "aliasValue1")
51+
val properties = mapOf("timzone_id" to "testTimeZone")
5052
val subscriptions = listOf<SubscriptionObject>()
5153

5254
/* When */
53-
val response = userBackendService.createUser("appId", identities, subscriptions)
55+
val response = userBackendService.createUser("appId", identities, subscriptions, properties)
5456

5557
/* Then */
5658
response.identities["onesignal_id"] shouldBe osId
5759
response.identities["aliasLabel1"] shouldBe "aliasValue1"
60+
response.properties.timezoneId shouldBe "testTimeZone"
5861
response.subscriptions.count() shouldBe 0
5962
coVerify {
6063
spyHttpClient.post(
@@ -63,7 +66,7 @@ class UserBackendServiceTests : FunSpec({
6366
it.has("identity") shouldBe true
6467
it.getJSONObject("identity").has("aliasLabel1") shouldBe true
6568
it.getJSONObject("identity").getString("aliasLabel1") shouldBe "aliasValue1"
66-
it.has("properties") shouldBe false
69+
it.has("properties") shouldBe true
6770
it.has("subscriptions") shouldBe false
6871
},
6972
)
@@ -74,17 +77,19 @@ class UserBackendServiceTests : FunSpec({
7477
/* Given */
7578
val osId = "11111111-1111-1111-1111-111111111111"
7679
val spyHttpClient = mockk<IHttpClient>()
77-
coEvery { spyHttpClient.post(any(), any()) } returns HttpResponse(202, "{identity:{onesignal_id: \"$osId\"}, subscriptions:[{id:\"subscriptionId1\", type:\"AndroidPush\"}]}")
80+
coEvery { spyHttpClient.post(any(), any()) } returns HttpResponse(202, "{identity:{onesignal_id: \"$osId\"}, subscriptions:[{id:\"subscriptionId1\", type:\"AndroidPush\"}], properties:{timezone_id: \"testTimeZone\"}}")
7881
val userBackendService = UserBackendService(spyHttpClient)
7982
val identities = mapOf<String, String>()
8083
val subscriptions = mutableListOf<SubscriptionObject>()
84+
val properties = mapOf("timzone_id" to "testTimeZone")
8185
subscriptions.add(SubscriptionObject("SHOULDNOTUSE", SubscriptionObjectType.ANDROID_PUSH))
8286

8387
/* When */
84-
val response = userBackendService.createUser("appId", identities, subscriptions)
88+
val response = userBackendService.createUser("appId", identities, subscriptions, properties)
8589

8690
/* Then */
8791
response.identities["onesignal_id"] shouldBe osId
92+
response.properties.timezoneId shouldBe "testTimeZone"
8893
response.subscriptions.count() shouldBe 1
8994
response.subscriptions[0].id shouldBe "subscriptionId1"
9095
response.subscriptions[0].type shouldBe SubscriptionObjectType.ANDROID_PUSH
@@ -94,7 +99,7 @@ class UserBackendServiceTests : FunSpec({
9499
"apps/appId/users",
95100
withArg {
96101
it.has("identity") shouldBe false
97-
it.has("properties") shouldBe false
102+
it.has("properties") shouldBe true
98103
it.has("subscriptions") shouldBe true
99104
it.getJSONArray("subscriptions").length() shouldBe 1
100105
it.getJSONArray("subscriptions").getJSONObject(0).has("type") shouldBe true

OneSignalSDK/onesignal/core/src/test/java/com/onesignal/user/internal/operations/LoginUserOperationExecutorTests.kt

Lines changed: 21 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ class LoginUserOperationExecutorTests : FunSpec({
4646
test("login anonymous user successfully creates user") {
4747
/* Given */
4848
val mockUserBackendService = mockk<IUserBackendService>()
49-
coEvery { mockUserBackendService.createUser(any(), any(), any()) } returns
49+
coEvery { mockUserBackendService.createUser(any(), any(), any(), any()) } returns
5050
CreateUserResponse(
5151
mapOf(IdentityConstants.ONESIGNAL_ID to remoteOneSignalId),
5252
PropertiesObject(),
@@ -80,14 +80,15 @@ class LoginUserOperationExecutorTests : FunSpec({
8080
appId,
8181
mapOf(),
8282
any(),
83+
any(),
8384
)
8485
}
8586
}
8687

8788
test("login anonymous user fails with retry when network condition exists") {
8889
/* Given */
8990
val mockUserBackendService = mockk<IUserBackendService>()
90-
coEvery { mockUserBackendService.createUser(any(), any(), any()) } throws BackendException(408, "TIMEOUT")
91+
coEvery { mockUserBackendService.createUser(any(), any(), any(), any()) } throws BackendException(408, "TIMEOUT")
9192

9293
val mockIdentityOperationExecutor = mockk<IdentityOperationExecutor>()
9394

@@ -103,13 +104,13 @@ class LoginUserOperationExecutorTests : FunSpec({
103104

104105
/* Then */
105106
response.result shouldBe ExecutionResult.FAIL_RETRY
106-
coVerify(exactly = 1) { mockUserBackendService.createUser(appId, mapOf(), any()) }
107+
coVerify(exactly = 1) { mockUserBackendService.createUser(appId, mapOf(), any(), any()) }
107108
}
108109

109110
test("login anonymous user fails with no retry when backend error condition exists") {
110111
/* Given */
111112
val mockUserBackendService = mockk<IUserBackendService>()
112-
coEvery { mockUserBackendService.createUser(any(), any(), any()) } throws BackendException(404, "NOT FOUND")
113+
coEvery { mockUserBackendService.createUser(any(), any(), any(), any()) } throws BackendException(404, "NOT FOUND")
113114

114115
val mockIdentityOperationExecutor = mockk<IdentityOperationExecutor>()
115116

@@ -125,13 +126,13 @@ class LoginUserOperationExecutorTests : FunSpec({
125126

126127
/* Then */
127128
response.result shouldBe ExecutionResult.FAIL_NORETRY
128-
coVerify(exactly = 1) { mockUserBackendService.createUser(appId, mapOf(), any()) }
129+
coVerify(exactly = 1) { mockUserBackendService.createUser(appId, mapOf(), any(), any()) }
129130
}
130131

131132
test("login identified user without association successfully creates user") {
132133
/* Given */
133134
val mockUserBackendService = mockk<IUserBackendService>()
134-
coEvery { mockUserBackendService.createUser(any(), any(), any()) } returns
135+
coEvery { mockUserBackendService.createUser(any(), any(), any(), any()) } returns
135136
CreateUserResponse(mapOf(IdentityConstants.ONESIGNAL_ID to remoteOneSignalId), PropertiesObject(), listOf())
136137

137138
val mockIdentityOperationExecutor = mockk<IdentityOperationExecutor>()
@@ -148,7 +149,7 @@ class LoginUserOperationExecutorTests : FunSpec({
148149

149150
/* Then */
150151
response.result shouldBe ExecutionResult.SUCCESS
151-
coVerify(exactly = 1) { mockUserBackendService.createUser(appId, mapOf(IdentityConstants.EXTERNAL_ID to "externalId"), any()) }
152+
coVerify(exactly = 1) { mockUserBackendService.createUser(appId, mapOf(IdentityConstants.EXTERNAL_ID to "externalId"), any(), any()) }
152153
}
153154

154155
test("login identified user with association succeeds when association is successful") {
@@ -187,7 +188,7 @@ class LoginUserOperationExecutorTests : FunSpec({
187188
test("login identified user with association fails with retry when association fails with retry") {
188189
/* Given */
189190
val mockUserBackendService = mockk<IUserBackendService>()
190-
coEvery { mockUserBackendService.createUser(any(), any(), any()) } returns
191+
coEvery { mockUserBackendService.createUser(any(), any(), any(), any()) } returns
191192
CreateUserResponse(mapOf(IdentityConstants.ONESIGNAL_ID to remoteOneSignalId), PropertiesObject(), listOf())
192193

193194
val mockIdentityOperationExecutor = mockk<IdentityOperationExecutor>()
@@ -222,7 +223,7 @@ class LoginUserOperationExecutorTests : FunSpec({
222223
test("login identified user with association successfully creates user when association fails with no retry") {
223224
/* Given */
224225
val mockUserBackendService = mockk<IUserBackendService>()
225-
coEvery { mockUserBackendService.createUser(any(), any(), any()) } returns
226+
coEvery { mockUserBackendService.createUser(any(), any(), any(), any()) } returns
226227
CreateUserResponse(mapOf(IdentityConstants.ONESIGNAL_ID to remoteOneSignalId), PropertiesObject(), listOf())
227228

228229
val mockIdentityOperationExecutor = mockk<IdentityOperationExecutor>()
@@ -252,13 +253,13 @@ class LoginUserOperationExecutorTests : FunSpec({
252253
},
253254
)
254255
}
255-
coVerify(exactly = 1) { mockUserBackendService.createUser(appId, mapOf(IdentityConstants.EXTERNAL_ID to "externalId"), any()) }
256+
coVerify(exactly = 1) { mockUserBackendService.createUser(appId, mapOf(IdentityConstants.EXTERNAL_ID to "externalId"), any(), any()) }
256257
}
257258

258259
test("login identified user with association fails with retry when association fails with no retry and network condition exists") {
259260
/* Given */
260261
val mockUserBackendService = mockk<IUserBackendService>()
261-
coEvery { mockUserBackendService.createUser(any(), any(), any()) } throws BackendException(408, "TIMEOUT")
262+
coEvery { mockUserBackendService.createUser(any(), any(), any(), any()) } throws BackendException(408, "TIMEOUT")
262263

263264
val mockIdentityOperationExecutor = mockk<IdentityOperationExecutor>()
264265
coEvery { mockIdentityOperationExecutor.execute(any()) } returns ExecutionResponse(ExecutionResult.FAIL_NORETRY)
@@ -287,13 +288,13 @@ class LoginUserOperationExecutorTests : FunSpec({
287288
},
288289
)
289290
}
290-
coVerify(exactly = 1) { mockUserBackendService.createUser(appId, mapOf(IdentityConstants.EXTERNAL_ID to "externalId"), any()) }
291+
coVerify(exactly = 1) { mockUserBackendService.createUser(appId, mapOf(IdentityConstants.EXTERNAL_ID to "externalId"), any(), any()) }
291292
}
292293

293294
test("creating user will merge operations into one backend call") {
294295
/* Given */
295296
val mockUserBackendService = mockk<IUserBackendService>()
296-
coEvery { mockUserBackendService.createUser(any(), any(), any()) } returns
297+
coEvery { mockUserBackendService.createUser(any(), any(), any(), any()) } returns
297298
CreateUserResponse(
298299
mapOf(IdentityConstants.ONESIGNAL_ID to remoteOneSignalId),
299300
PropertiesObject(),
@@ -357,14 +358,15 @@ class LoginUserOperationExecutorTests : FunSpec({
357358
it[0].token shouldBe "pushToken2"
358359
it[0].notificationTypes shouldBe SubscriptionStatus.SUBSCRIBED
359360
},
361+
any(),
360362
)
361363
}
362364
}
363365

364366
test("creating user will hydrate when the user hasn't changed") {
365367
/* Given */
366368
val mockUserBackendService = mockk<IUserBackendService>()
367-
coEvery { mockUserBackendService.createUser(any(), any(), any()) } returns
369+
coEvery { mockUserBackendService.createUser(any(), any(), any(), any()) } returns
368370
CreateUserResponse(
369371
mapOf(IdentityConstants.ONESIGNAL_ID to remoteOneSignalId),
370372
PropertiesObject(),
@@ -423,14 +425,15 @@ class LoginUserOperationExecutorTests : FunSpec({
423425
appId,
424426
mapOf(),
425427
any(),
428+
any(),
426429
)
427430
}
428431
}
429432

430433
test("creating user will not hydrate when the user has changed") {
431434
/* Given */
432435
val mockUserBackendService = mockk<IUserBackendService>()
433-
coEvery { mockUserBackendService.createUser(any(), any(), any()) } returns
436+
coEvery { mockUserBackendService.createUser(any(), any(), any(), any()) } returns
434437
CreateUserResponse(
435438
mapOf(IdentityConstants.ONESIGNAL_ID to remoteOneSignalId),
436439
PropertiesObject(),
@@ -489,14 +492,15 @@ class LoginUserOperationExecutorTests : FunSpec({
489492
appId,
490493
mapOf(),
491494
any(),
495+
any(),
492496
)
493497
}
494498
}
495499

496500
test("creating user will provide local to remote translations") {
497501
/* Given */
498502
val mockUserBackendService = mockk<IUserBackendService>()
499-
coEvery { mockUserBackendService.createUser(any(), any(), any()) } returns
503+
coEvery { mockUserBackendService.createUser(any(), any(), any(), any()) } returns
500504
CreateUserResponse(
501505
mapOf(IdentityConstants.ONESIGNAL_ID to remoteOneSignalId),
502506
PropertiesObject(),
@@ -536,6 +540,7 @@ class LoginUserOperationExecutorTests : FunSpec({
536540
appId,
537541
mapOf(),
538542
any(),
543+
any(),
539544
)
540545
}
541546
}

0 commit comments

Comments
 (0)