package io.intercom.api; import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonProperty; import com.google.common.annotations.VisibleForTesting; import com.google.common.collect.Maps; import java.net.URI; import java.util.HashMap; import java.util.List; import java.util.Map; @SuppressWarnings("UnusedDeclaration") @JsonIgnoreProperties(ignoreUnknown = true) @JsonInclude(JsonInclude.Include.NON_DEFAULT) public class Contact extends TypedData implements Replier { private static final Map<String, String> SENTINEL = Maps.newHashMap(); public static Contact findByID(String id) throws AuthorizationException, ClientException, ServerException, InvalidException, RateLimitException { return new HttpClient(contactURI(id)).get(Contact.class); } public static Contact findByUserID(String userID) throws AuthorizationException, ClientException, ServerException, InvalidException, RateLimitException { final Map<String, String> params = Maps.newHashMap(); params.put("user_id", userID); return DataResource.find(params, "contacts", Contact.class); } public static ContactCollection listByEmail(String email) throws AuthorizationException, ClientException, ServerException, InvalidException, RateLimitException { final Map<String, String> params = Maps.newHashMap(); params.put("email", email); return list(params); } public static ContactCollection list(Map<String, String> params) throws AuthorizationException, ClientException, ServerException, InvalidException, RateLimitException { return DataResource.list(params, "contacts", ContactCollection.class); } public static ContactCollection list() throws AuthorizationException, ClientException, ServerException, InvalidException, RateLimitException { return DataResource.list(SENTINEL, "contacts", ContactCollection.class); } public static ScrollableContactCollection scroll() throws AuthorizationException, ClientException, ServerException, InvalidException, RateLimitException { return DataResource.scroll(null, "contacts", ScrollableContactCollection.class); } public static Contact create(Contact c) throws AuthorizationException, ClientException, ServerException, InvalidException, RateLimitException { return DataResource.create(ContactUpdate.buildFrom(c), "contacts", Contact.class); } public static Contact update(Contact c) throws AuthorizationException, ClientException, ServerException, InvalidException, RateLimitException { return DataResource.update(ContactUpdate.buildFrom(c), "contacts", Contact.class); } public static Contact delete(Contact c) throws AuthorizationException, ClientException, ServerException, InvalidException, RateLimitException { return DataResource.delete(c.getID(), "contacts", Contact.class); } public static User convert(Contact c, User u) throws AuthorizationException, ClientException, ServerException, InvalidException, RateLimitException { return DataResource.post(ContactConvertBuilder.buildConvert(c, u), convertURI(), User.class); } private static URI contactURI(String id) { return UriBuilder.newBuilder().path("contacts").path(id).build(); } private static URI convertURI() { return UriBuilder.newBuilder().path("contacts").path("convert").build(); } static class ContactConvertBuilder { static ContactConvert buildConvert(Contact c, User u) throws InvalidException { return new ContactConvertBuilder().build(c, u); } ContactConvert build(Contact c, User u) throws InvalidException { return new ContactConvert(buildConvertContact(c), buildConvertUser(u)); } HashMap<String, String> buildConvertUser(User u) { final HashMap<String, String> convertUser = Maps.newHashMap(); if (u.getId() != null) { convertUser.put("id", u.getId()); } if (u.getUserId() != null) { convertUser.put("user_id", u.getUserId()); } if (u.getEmail() != null) { convertUser.put("email", u.getEmail()); } checkValidConvertContact(convertUser); return convertUser; } void checkValidConvertContact(HashMap<String, String> convertUser) { if ((!convertUser.containsKey("id")) && (!convertUser.containsKey("user_id")) && (!convertUser.containsKey("email"))) { throw new InvalidException("a convert user must include at least one of, an id, user_id or email parameter"); } } HashMap<String, String> buildConvertContact(Contact c) { final HashMap<String, String> convertContact = Maps.newHashMap(); if (c.getID() != null) { convertContact.put("id", c.getID()); } if (c.getUserID() != null) { convertContact.put("user_id", c.getUserID()); } checkValidConvertUser(convertContact); return convertContact; } void checkValidConvertUser(HashMap<String, String> convertContact) { if ((!convertContact.containsKey("id")) && (!convertContact.containsKey("user_id"))) { throw new InvalidException("a convert contact must include at least one of, an id or a user_id parameter"); } } } @SuppressWarnings("UnusedDeclaration") @JsonIgnoreProperties(ignoreUnknown = true) @JsonInclude(JsonInclude.Include.NON_DEFAULT) static class ContactConvert { @JsonProperty("contact") private Map<String, String> contact; @JsonProperty("user") private Map<String, String> user; public ContactConvert() { } public ContactConvert(Map<String, String> contact, Map<String, String> user) { this.contact = contact; this.user = user; } public Map<String, String> getContact() { return contact; } public void setContact(Map<String, String> contact) { this.contact = contact; } public Map<String, String> getUser() { return user; } public void setUser(Map<String, String> user) { this.user = user; } } @SuppressWarnings("UnusedDeclaration") @JsonIgnoreProperties(ignoreUnknown = true) @JsonInclude(JsonInclude.Include.NON_DEFAULT) static class ContactUpdate extends TypedData { static ContactUpdate buildFrom(Contact c) { final ContactUpdate contactUpdate = new ContactUpdate(); contactUpdate.id = c.getID(); // propagated, noset contactUpdate.userID = c.getUserID(); // propagated, noset contactUpdate.email = c.getEmail(); contactUpdate.phone = c.getPhone(); contactUpdate.name = c.getName(); contactUpdate.lastSeenIP = c.getLastSeenIP(); contactUpdate.customAttributes = c.getCustomAttributes(); contactUpdate.lastRequestAt = c.getLastRequestAt(); contactUpdate.unsubscribedFromEmails = c.getUnsubscribedFromEmails(); return contactUpdate; } @JsonProperty("type") @JsonInclude(JsonInclude.Include.NON_DEFAULT) private String type; @JsonProperty("id") private String id; @JsonProperty("user_id") private String userID; @JsonProperty("email") private String email; @JsonProperty("phone") private String phone; @JsonProperty("name") private String name; @JsonProperty("last_seen_ip") private String lastSeenIP; @JsonIgnoreProperties(ignoreUnknown = false) @JsonProperty("custom_attributes") private Map<String, CustomAttribute> customAttributes = Maps.newHashMap(); @JsonProperty("last_seen_user_agent") private String lastSeenUserAgent; @JsonProperty("companies") private List<CompanyWithStringPlan> companyCollection; @JsonProperty("last_request_at") private long lastRequestAt; @JsonProperty("signed_up_at") private long signedUpAt; /* * Making these Booleans allows us to send true or false as set * values leaving null the ignored field for NON_DEFAULT. A * primitive would result in false not being sent */ @JsonProperty("unsubscribed_from_emails") @JsonInclude(JsonInclude.Include.NON_DEFAULT) private Boolean unsubscribedFromEmails; @JsonProperty("update_last_request_at") @JsonInclude(JsonInclude.Include.NON_DEFAULT) private Boolean updateLastRequestAt; @JsonProperty("new_session") @JsonInclude(JsonInclude.Include.NON_DEFAULT) private Boolean newSession; public ContactUpdate() { } public String getType() { return type; } public String getID() { return id; } public String getUserID() { return userID; } public String getEmail() { return email; } public String getPhone() { return phone; } public String getName() { return name; } public String getLastSeenIP() { return lastSeenIP; } public Map<String, CustomAttribute> getCustomAttributes() { return customAttributes; } public String getLastSeenUserAgent() { return lastSeenUserAgent; } public List<CompanyWithStringPlan> getCompanyCollection() { return companyCollection; } public long getLastRequestAt() { return lastRequestAt; } public Boolean getUnsubscribedFromEmails() { return unsubscribedFromEmails; } public Boolean isUpdateLastRequestAt() { return updateLastRequestAt; } public Boolean isNewSession() { return newSession; } } @JsonProperty("type") @JsonInclude(JsonInclude.Include.ALWAYS) private final String type = "contact"; @JsonProperty("id") private String id; @JsonProperty("user_id") private String userID; @JsonProperty("email") private String email; @JsonProperty("phone") private String phone; @JsonProperty("name") private String name; @JsonProperty("pseudonym") private String pseudonym; @JsonProperty("avatar") private Avatar avatar; @JsonProperty("created_at") private long createdAt; @JsonProperty("updated_at") private long updatedAt; @JsonProperty("unsubscribed_from_emails") private Boolean unsubscribedFromEmails; @JsonProperty("session_count") private int sessionCount; @JsonProperty("last_request_at") private long lastRequestAt; @JsonProperty("last_seen_ip") private String lastSeenIP; @JsonIgnoreProperties(ignoreUnknown = false) @JsonProperty("custom_attributes") private Map<String, CustomAttribute> customAttributes = Maps.newHashMap(); @JsonProperty("user_agent_data") private String userAgentData; @JsonProperty("location_data") private LocationData locationData; @JsonIgnoreProperties(ignoreUnknown = false) @JsonProperty("companies") private CompanyCollection companyCollection = new CompanyCollection(); @JsonProperty("social_profiles") private SocialProfileCollection socialProfileCollection = new SocialProfileCollection(); @JsonProperty("segments") private SegmentCollection segmentCollection = new SegmentCollection(); @JsonProperty("tags") private TagCollection tagCollection = new TagCollection(); @JsonProperty("update_last_request_at") private Boolean updateLastRequestAt; @JsonProperty("new_session") private Boolean newSession; private Boolean untag; public Contact() { } public Contact untag() { untag = Boolean.TRUE; return this; } boolean isUntag() { return untag == null ? false : untag; } @JsonIgnore public String getReplyType() { return getType() + "_reply"; } public String getType() { return type; } public String getID() { return id; } @VisibleForTesting Contact setID(String id) { this.id = id; return this; } public String getName() { return name; } public Contact setName(String name) { this.name = name; return this; } public String getPseudonym() { return pseudonym; } public String getEmail() { return email; } public Contact setEmail(String email) { this.email = email; return this; } public String getPhone() { return phone; } public Contact setPhone(String phone) { this.phone = phone; return this; } public String getUserID() { return userID; } public Avatar getAvatar() { return avatar; } public long getCreatedAt() { return createdAt; } public long getUpdatedAt() { return updatedAt; } public Boolean getUnsubscribedFromEmails() { return unsubscribedFromEmails; } public Contact setUnsubscribedFromEmails(boolean unsubscribedFromEmails) { this.unsubscribedFromEmails = unsubscribedFromEmails; return this; } public int getSessionCount() { return sessionCount; } public long getLastRequestAt() { return lastRequestAt; } public Contact setLastRequestAt(long lastRequestAt) { this.lastRequestAt = lastRequestAt; return this; } public String getLastSeenIP() { return lastSeenIP; } public Contact setLastSeenIP(String lastSeenIP) { this.lastSeenIP = lastSeenIP; return this; } public Map<String, CustomAttribute> getCustomAttributes() { return customAttributes; } public Contact setCustomAttributes(Map<String, CustomAttribute> customAttributes) { this.customAttributes = customAttributes; return this; } public Contact addCustomAttribute(CustomAttribute customAttribute) { this.customAttributes.put(customAttribute.getName(), customAttribute); return this; } public String getUserAgentData() { return userAgentData; } public LocationData getLocationData() { return locationData; } public CompanyCollection getCompanyCollection() { return companyCollection; } public SocialProfileCollection getSocialProfileCollection() { return socialProfileCollection; } public SegmentCollection getSegmentCollection() { return segmentCollection; } public TagCollection getTagCollection() { return tagCollection; } public Boolean isUpdateLastRequestAt() { return updateLastRequestAt; } public Boolean isNewSession() { return newSession; } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; Contact contact = (Contact) o; if (createdAt != contact.createdAt) return false; if (updatedAt != contact.updatedAt) return false; if (sessionCount != contact.sessionCount) return false; if (lastRequestAt != contact.lastRequestAt) return false; if (!type.equals(contact.type)) return false; if (id != null ? !id.equals(contact.id) : contact.id != null) return false; if (name != null ? !name.equals(contact.name) : contact.name != null) return false; if (email != null ? !email.equals(contact.email) : contact.email != null) return false; if (phone != null ? !phone.equals(contact.phone) : contact.phone != null) return false; if (userID != null ? !userID.equals(contact.userID) : contact.userID != null) return false; if (avatar != null ? !avatar.equals(contact.avatar) : contact.avatar != null) return false; if (unsubscribedFromEmails != null ? !unsubscribedFromEmails.equals(contact.unsubscribedFromEmails) : contact.unsubscribedFromEmails != null) return false; if (lastSeenIP != null ? !lastSeenIP.equals(contact.lastSeenIP) : contact.lastSeenIP != null) return false; if (customAttributes != null ? !customAttributes.equals(contact.customAttributes) : contact.customAttributes != null) return false; if (userAgentData != null ? !userAgentData.equals(contact.userAgentData) : contact.userAgentData != null) return false; if (locationData != null ? !locationData.equals(contact.locationData) : contact.locationData != null) return false; if (companyCollection != null ? !companyCollection.equals(contact.companyCollection) : contact.companyCollection != null) return false; if (socialProfileCollection != null ? !socialProfileCollection.equals(contact.socialProfileCollection) : contact.socialProfileCollection != null) return false; if (segmentCollection != null ? !segmentCollection.equals(contact.segmentCollection) : contact.segmentCollection != null) return false; if (tagCollection != null ? !tagCollection.equals(contact.tagCollection) : contact.tagCollection != null) return false; if (updateLastRequestAt != null ? !updateLastRequestAt.equals(contact.updateLastRequestAt) : contact.updateLastRequestAt != null) return false; //noinspection SimplifiableIfStatement if (newSession != null ? !newSession.equals(contact.newSession) : contact.newSession != null) return false; return !(untag != null ? !untag.equals(contact.untag) : contact.untag != null); } @Override public int hashCode() { int result = type.hashCode(); result = 31 * result + (id != null ? id.hashCode() : 0); result = 31 * result + (name != null ? name.hashCode() : 0); result = 31 * result + (email != null ? email.hashCode() : 0); result = 31 * result + (phone != null ? phone.hashCode() : 0); result = 31 * result + (userID != null ? userID.hashCode() : 0); result = 31 * result + (avatar != null ? avatar.hashCode() : 0); result = 31 * result + (int) (createdAt ^ (createdAt >>> 32)); result = 31 * result + (int) (updatedAt ^ (updatedAt >>> 32)); result = 31 * result + (unsubscribedFromEmails != null ? unsubscribedFromEmails.hashCode() : 0); result = 31 * result + sessionCount; result = 31 * result + (int) (lastRequestAt ^ (lastRequestAt >>> 32)); result = 31 * result + (lastSeenIP != null ? lastSeenIP.hashCode() : 0); result = 31 * result + (customAttributes != null ? customAttributes.hashCode() : 0); result = 31 * result + (userAgentData != null ? userAgentData.hashCode() : 0); result = 31 * result + (locationData != null ? locationData.hashCode() : 0); result = 31 * result + (companyCollection != null ? companyCollection.hashCode() : 0); result = 31 * result + (socialProfileCollection != null ? socialProfileCollection.hashCode() : 0); result = 31 * result + (segmentCollection != null ? segmentCollection.hashCode() : 0); result = 31 * result + (tagCollection != null ? tagCollection.hashCode() : 0); result = 31 * result + (updateLastRequestAt != null ? updateLastRequestAt.hashCode() : 0); result = 31 * result + (newSession != null ? newSession.hashCode() : 0); result = 31 * result + (untag != null ? untag.hashCode() : 0); return result; } @Override public String toString() { return "Contact{" + "type='" + type + '\'' + ", id='" + id + '\'' + ", name='" + name + '\'' + ", email='" + email + '\'' + ", phone='" + phone + '\'' + ", userID='" + userID + '\'' + ", avatar=" + avatar + ", createdAt=" + createdAt + ", updatedAt=" + updatedAt + ", unsubscribedFromEmails=" + unsubscribedFromEmails + ", sessionCount=" + sessionCount + ", lastRequestAt=" + lastRequestAt + ", lastSeenIP='" + lastSeenIP + '\'' + ", customAttributes=" + customAttributes + ", userAgentData='" + userAgentData + '\'' + ", locationData=" + locationData + ", companyCollection=" + companyCollection + ", socialProfileCollection=" + socialProfileCollection + ", segmentCollection=" + segmentCollection + ", tagCollection=" + tagCollection + ", updateLastRequestAt=" + updateLastRequestAt + ", newSession=" + newSession + ", untag=" + untag + "} " + super.toString(); } }