Skip to content

Commit 5498f3e

Browse files
authored
fix(analytics): allow user attributes in identifyUser (#1306)
1 parent 0aaa84c commit 5498f3e

File tree

4 files changed

+249
-31
lines changed

4 files changed

+249
-31
lines changed

aws-analytics-pinpoint/src/androidTest/java/com/amplifyframework/analytics/pinpoint/AnalyticsPinpointInstrumentedTest.java

Lines changed: 65 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
import com.amplifyframework.analytics.AnalyticsEvent;
2424
import com.amplifyframework.analytics.AnalyticsProperties;
2525
import com.amplifyframework.analytics.UserProfile;
26+
import com.amplifyframework.analytics.pinpoint.models.AWSPinpointUserProfile;
2627
import com.amplifyframework.core.Amplify;
2728
import com.amplifyframework.logging.Logger;
2829
import com.amplifyframework.testutils.Sleep;
@@ -50,6 +51,7 @@
5051
import static androidx.test.core.app.ApplicationProvider.getApplicationContext;
5152
import static org.junit.Assert.assertEquals;
5253
import static org.junit.Assert.assertFalse;
54+
import static org.junit.Assert.assertNull;
5355
import static org.junit.Assert.assertTrue;
5456
import static org.junit.Assert.fail;
5557

@@ -268,19 +270,9 @@ public void unregisterGlobalPropertiesRemovesGivenProperties() {
268270
* all provided Amplify attributes.
269271
*/
270272
@Test
271-
public void testIdentifyUser() {
272-
UserProfile.Location location = UserProfile.Location.builder()
273-
.latitude(47.6154086)
274-
.longitude(-122.3349685)
275-
.postalCode("98122")
276-
.city("Seattle")
277-
.region("WA")
278-
.country("USA")
279-
.build();
280-
AnalyticsProperties properties = AnalyticsProperties.builder()
281-
.add("TestStringProperty", "TestStringValue")
282-
.add("TestDoubleProperty", 1.0)
283-
.build();
273+
public void testIdentifyUserWithDefaultProfile() {
274+
UserProfile.Location location = getTestLocation();
275+
AnalyticsProperties properties = getEndpointProperties();
284276
UserProfile userProfile = UserProfile.builder()
285277
.name("test-user")
286278
@@ -292,6 +284,42 @@ public void testIdentifyUser() {
292284
Amplify.Analytics.identifyUser("userId", userProfile);
293285

294286
EndpointProfile endpointProfile = targetingClient.currentEndpoint();
287+
assertCommonEndpointProfileProperties(endpointProfile);
288+
assertNull(endpointProfile.getUser().getUserAttributes());
289+
}
290+
291+
/**
292+
* {@link AWSPinpointUserProfile} extends {@link UserProfile} to include
293+
* {@link AWSPinpointUserProfile#userAttributes} which is specific to Pinpoint. This test is very
294+
* similar to testIdentifyUserWithDefaultProfile, but it adds user attributes in additional
295+
* to the endpoint attributes.
296+
*/
297+
@Test
298+
public void testIdentifyUserWithUserAtrributes() {
299+
UserProfile.Location location = getTestLocation();
300+
AnalyticsProperties properties = getEndpointProperties();
301+
AnalyticsProperties userAttributes = getUserAttributes();
302+
AWSPinpointUserProfile pinpointUserProfile = AWSPinpointUserProfile.builder()
303+
.name("test-user")
304+
305+
.plan("test-plan")
306+
.location(location)
307+
.customProperties(properties)
308+
.userAttributes(userAttributes)
309+
.build();
310+
311+
Amplify.Analytics.identifyUser("userId", pinpointUserProfile);
312+
313+
EndpointProfile endpointProfile = targetingClient.currentEndpoint();
314+
assertCommonEndpointProfileProperties(endpointProfile);
315+
316+
assertEquals("User attribute value", endpointProfile.getUser()
317+
.getUserAttributes()
318+
.get("SomeUserAttribute")
319+
.get(0));
320+
}
321+
322+
private void assertCommonEndpointProfileProperties(EndpointProfile endpointProfile) {
295323
EndpointProfileLocation endpointProfileLocation = endpointProfile.getLocation();
296324
assertEquals("[email protected]", endpointProfile.getAttribute("email").get(0));
297325
assertEquals("test-user", endpointProfile.getAttribute("name").get(0));
@@ -306,6 +334,30 @@ public void testIdentifyUser() {
306334
assertEquals((Double) 1.0, endpointProfile.getMetric("TestDoubleProperty"));
307335
}
308336

337+
private AnalyticsProperties getUserAttributes() {
338+
return AnalyticsProperties.builder()
339+
.add("SomeUserAttribute", "User attribute value")
340+
.build();
341+
}
342+
343+
private AnalyticsProperties getEndpointProperties() {
344+
return AnalyticsProperties.builder()
345+
.add("TestStringProperty", "TestStringValue")
346+
.add("TestDoubleProperty", 1.0)
347+
.build();
348+
}
349+
350+
private UserProfile.Location getTestLocation() {
351+
return UserProfile.Location.builder()
352+
.latitude(47.6154086)
353+
.longitude(-122.3349685)
354+
.postalCode("98122")
355+
.city("Seattle")
356+
.region("WA")
357+
.country("USA")
358+
.build();
359+
}
360+
309361
private void waitForAutoFlush(AnalyticsClient analyticsClient) {
310362
long timeSleptSoFar = 0;
311363
while (timeSleptSoFar < TimeUnit.SECONDS.toMillis(EVENT_FLUSH_TIMEOUT)) {

aws-analytics-pinpoint/src/main/java/com/amplifyframework/analytics/pinpoint/AWSPinpointAnalyticsPlugin.java

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
import com.amplifyframework.analytics.AnalyticsPropertyBehavior;
3333
import com.amplifyframework.analytics.AnalyticsStringProperty;
3434
import com.amplifyframework.analytics.UserProfile;
35+
import com.amplifyframework.analytics.pinpoint.models.AWSPinpointUserProfile;
3536
import com.amplifyframework.core.Amplify;
3637

3738
import com.amazonaws.auth.AWSCredentialsProvider;
@@ -124,13 +125,19 @@ public void identifyUser(@NonNull String userId, @Nullable UserProfile userProfi
124125
// Assign userId to the endpoint.
125126
EndpointProfileUser user = new EndpointProfileUser();
126127
user.setUserId(userId);
128+
if (userProfile instanceof AWSPinpointUserProfile) {
129+
AWSPinpointUserProfile pinpointUserProfile = (AWSPinpointUserProfile) userProfile;
130+
if (pinpointUserProfile.getUserAttributes() != null) {
131+
addUserAttributes(user, pinpointUserProfile.getUserAttributes());
132+
}
133+
}
127134
endpointProfile.setUser(user);
128135
// Add user-specific data to the endpoint
129136
if (userProfile != null) {
130137
addUserProfileToEndpoint(endpointProfile, userProfile);
131138
}
132139
// update endpoint
133-
targetingClient.updateEndpointProfile();
140+
targetingClient.updateEndpointProfile(endpointProfile);
134141
}
135142

136143
/**
@@ -204,6 +211,28 @@ private void addCustomProperties(@NonNull EndpointProfile endpointProfile,
204211
}
205212
}
206213

214+
private void addUserAttributes(@NonNull EndpointProfileUser user,
215+
@NonNull AnalyticsProperties userAttributes) {
216+
for (Map.Entry<String, AnalyticsPropertyBehavior<?>> entry : userAttributes) {
217+
String key = entry.getKey();
218+
AnalyticsPropertyBehavior<?> property = entry.getValue();
219+
220+
if (property instanceof AnalyticsStringProperty) {
221+
String value = ((AnalyticsStringProperty) property).getValue();
222+
user.addUserAttribute(key, Collections.singletonList(value));
223+
} else if (property instanceof AnalyticsBooleanProperty) {
224+
String value = ((AnalyticsBooleanProperty) property).getValue().toString();
225+
user.addUserAttribute(key, Collections.singletonList(value));
226+
} else if (property instanceof AnalyticsDoubleProperty) {
227+
Double value = ((AnalyticsDoubleProperty) property).getValue();
228+
user.addUserAttribute(entry.getKey(), Collections.singletonList(value.toString()));
229+
} else if (property instanceof AnalyticsIntegerProperty) {
230+
Double value = ((AnalyticsIntegerProperty) property).getValue().doubleValue();
231+
user.addUserAttribute(entry.getKey(), Collections.singletonList(value.toString()));
232+
}
233+
}
234+
}
235+
207236
/**
208237
* Add location details to the endpoint profile location.
209238
*
Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
/*
2+
* Copyright 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License").
5+
* You may not use this file except in compliance with the License.
6+
* A copy of the License is located at
7+
*
8+
* http://aws.amazon.com/apache2.0
9+
*
10+
* or in the "license" file accompanying this file. This file is distributed
11+
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
12+
* express or implied. See the License for the specific language governing
13+
* permissions and limitations under the License.
14+
*/
15+
16+
package com.amplifyframework.analytics.pinpoint.models;
17+
18+
import androidx.annotation.NonNull;
19+
import androidx.annotation.Nullable;
20+
import androidx.core.util.ObjectsCompat;
21+
22+
import com.amplifyframework.analytics.AnalyticsProperties;
23+
import com.amplifyframework.analytics.UserProfile;
24+
25+
import java.util.Objects;
26+
27+
/**
28+
* Extends the category-defined UserProfile class to include features supported
29+
* relevant to Pinpoint only.
30+
*/
31+
public final class AWSPinpointUserProfile extends UserProfile {
32+
private final AnalyticsProperties userAttributes;
33+
34+
/**
35+
* Constructor that mirrors the parent class.
36+
* @param builder An instance of the builder with the desired properties set.
37+
*/
38+
protected AWSPinpointUserProfile(@NonNull Builder builder) {
39+
super(builder);
40+
this.userAttributes = builder.userAttributes;
41+
}
42+
43+
/**
44+
* Gets all the available user attributes.
45+
* @return The user's attributes.
46+
*/
47+
@Nullable
48+
public AnalyticsProperties getUserAttributes() {
49+
return userAttributes;
50+
}
51+
52+
/**
53+
* Begins construction of an {@link AWSPinpointUserProfile} using a builder pattern.
54+
* @return An {@link AWSPinpointUserProfile.Builder} instance
55+
*/
56+
@NonNull
57+
public static Builder builder() {
58+
return new AWSPinpointUserProfile.Builder();
59+
}
60+
61+
@Override
62+
public boolean equals(@Nullable Object object) {
63+
boolean isEquals = super.equals(object);
64+
AWSPinpointUserProfile that = (AWSPinpointUserProfile) object;
65+
return isEquals && ObjectsCompat.equals(userAttributes, that.userAttributes);
66+
}
67+
68+
@Override
69+
public int hashCode() {
70+
return 31 * super.hashCode() + (userAttributes != null ? userAttributes.hashCode() : 0);
71+
}
72+
73+
@NonNull
74+
@Override
75+
public String toString() {
76+
return "UserProfile{" +
77+
"name='" + getName() + '\'' +
78+
", email='" + getEmail() + '\'' +
79+
", plan='" + getPlan() + '\'' +
80+
", location=" + getLocation() +
81+
", customProperties=" + getCustomProperties() +
82+
", userProperties=" + userAttributes +
83+
'}';
84+
}
85+
86+
/**
87+
* Builder for the {@link AWSPinpointUserProfile} class.
88+
*/
89+
public static final class Builder extends UserProfile.Builder<Builder, AWSPinpointUserProfile> {
90+
private AnalyticsProperties userAttributes;
91+
92+
/**
93+
* Sets the user's attributes of the builder instance.
94+
* @param userAttributes The collection of attributes.
95+
* @return Current builder instance, for method chaining.
96+
*/
97+
@NonNull
98+
public Builder userAttributes(@NonNull final AnalyticsProperties userAttributes) {
99+
Objects.requireNonNull(userAttributes);
100+
this.userAttributes = userAttributes;
101+
return this;
102+
}
103+
104+
/**
105+
* Builds an instance of {@link UserProfile}, using the provided values.
106+
* @return An {@link UserProfile}
107+
*/
108+
@NonNull
109+
public AWSPinpointUserProfile build() {
110+
return new AWSPinpointUserProfile(this);
111+
}
112+
}
113+
}

0 commit comments

Comments
 (0)