From 7930fe1242f47d602634d6208f415f2d83fd0338 Mon Sep 17 00:00:00 2001 From: Ian Jepp Date: Thu, 17 Feb 2022 12:39:06 +0000 Subject: [PATCH] Implement basic contact list API operations --- .../Api/ContactList/Dto/ContactListModel.cs | 35 ++++++++ .../ContactList/Dto/ContactListUpdateModel.cs | 27 ++++++ .../Dto/ContactListUpdateResponseModel.cs | 33 ++++++++ .../ContactList/Dto/ListContactListModel.cs | 51 ++++++++++++ .../Api/ContactList/HubSpotContactListApi.cs | 83 +++++++++++++++++++ HubSpot.NET/Api/ContactList/ListOptions.cs | 42 ++++++++++ HubSpot.NET/Core/HubSpotApi.cs | 3 + .../Core/Interfaces/IHubSpotContactListApi.cs | 19 +++++ 8 files changed, 293 insertions(+) create mode 100644 HubSpot.NET/Api/ContactList/Dto/ContactListModel.cs create mode 100644 HubSpot.NET/Api/ContactList/Dto/ContactListUpdateModel.cs create mode 100644 HubSpot.NET/Api/ContactList/Dto/ContactListUpdateResponseModel.cs create mode 100644 HubSpot.NET/Api/ContactList/Dto/ListContactListModel.cs create mode 100644 HubSpot.NET/Api/ContactList/HubSpotContactListApi.cs create mode 100644 HubSpot.NET/Api/ContactList/ListOptions.cs create mode 100644 HubSpot.NET/Core/Interfaces/IHubSpotContactListApi.cs diff --git a/HubSpot.NET/Api/ContactList/Dto/ContactListModel.cs b/HubSpot.NET/Api/ContactList/Dto/ContactListModel.cs new file mode 100644 index 00000000..274f38a9 --- /dev/null +++ b/HubSpot.NET/Api/ContactList/Dto/ContactListModel.cs @@ -0,0 +1,35 @@ +using System.Runtime.Serialization; +using HubSpot.NET.Core.Interfaces; + +namespace HubSpot.NET.Api.ContactList.Dto +{ + [DataContract] + public class ContactListModel: IHubSpotModel + { + [DataMember(Name = "listId")] + public long ListId { get; set; } + + [DataMember(Name = "name")] + public string Name { get; set; } + + [DataMember(Name = "listType")] + public string ListType { get; set; } + + [DataMember(Name = "dynamic")] + public bool Dynamic { get; set; } + + [IgnoreDataMember] + public bool IsNameValue => true; + + public void ToHubSpotDataEntity(ref dynamic dataEntity) + { + } + + public void FromHubSpotDataEntity(dynamic hubspotData) + { + } + + [IgnoreDataMember] + public string RouteBasePath => "/contacts/v1/lists"; + } +} \ No newline at end of file diff --git a/HubSpot.NET/Api/ContactList/Dto/ContactListUpdateModel.cs b/HubSpot.NET/Api/ContactList/Dto/ContactListUpdateModel.cs new file mode 100644 index 00000000..8a826e08 --- /dev/null +++ b/HubSpot.NET/Api/ContactList/Dto/ContactListUpdateModel.cs @@ -0,0 +1,27 @@ +using System.Collections.Generic; +using System.Runtime.Serialization; +using HubSpot.NET.Core.Interfaces; + +namespace HubSpot.NET.Api.ContactList.Dto +{ + [DataContract] + public class ContactListUpdateModel : IHubSpotModel + { + [DataMember(Name = "vids")] + public List ContactIds = new List(); + + [IgnoreDataMember] + public bool IsNameValue => false; + + public void ToHubSpotDataEntity(ref dynamic dataEntity) + { + } + + public void FromHubSpotDataEntity(dynamic hubspotData) + { + } + + [IgnoreDataMember] + public string RouteBasePath => "/contacts/v1/lists"; + } +} \ No newline at end of file diff --git a/HubSpot.NET/Api/ContactList/Dto/ContactListUpdateResponseModel.cs b/HubSpot.NET/Api/ContactList/Dto/ContactListUpdateResponseModel.cs new file mode 100644 index 00000000..7cdcb464 --- /dev/null +++ b/HubSpot.NET/Api/ContactList/Dto/ContactListUpdateResponseModel.cs @@ -0,0 +1,33 @@ +using System.Collections.Generic; +using System.Runtime.Serialization; +using HubSpot.NET.Core.Interfaces; + +namespace HubSpot.NET.Api.ContactList.Dto +{ + [DataContract] + public class ContactListUpdateResponseModel : IHubSpotModel + { + [DataMember(Name = "discarded")] + public List Discarded = new List(); + + [DataMember(Name = "invalidVids")] + public List InvalidContactIds = new List(); + + [DataMember(Name = "updated")] + public List UpdatedContactIds = new List(); + + [IgnoreDataMember] + public bool IsNameValue => false; + + public void ToHubSpotDataEntity(ref dynamic dataEntity) + { + } + + public void FromHubSpotDataEntity(dynamic hubspotData) + { + } + + [IgnoreDataMember] + public string RouteBasePath => "/contacts/v1/lists"; + } +} \ No newline at end of file diff --git a/HubSpot.NET/Api/ContactList/Dto/ListContactListModel.cs b/HubSpot.NET/Api/ContactList/Dto/ListContactListModel.cs new file mode 100644 index 00000000..6913376c --- /dev/null +++ b/HubSpot.NET/Api/ContactList/Dto/ListContactListModel.cs @@ -0,0 +1,51 @@ +using System.Collections.Generic; +using System.Runtime.Serialization; +using HubSpot.NET.Core.Interfaces; + +namespace HubSpot.NET.Api.ContactList.Dto +{ + [DataContract] + public class ListContactListModel : IHubSpotModel + { + [DataMember(Name = "lists")] + public List Lists { get; set; } = new List(); + + /// + /// Gets or sets a value indicating whether more results are available. + /// + /// + /// true if [more results available]; otherwise, false. + /// + /// + /// This is a mapping of the "has-more" prop in the JSON return data from HubSpot + /// + [DataMember(Name = "has-more")] + public bool MoreResultsAvailable { get; set; } + + /// + /// Gets or sets the continuation offset. + /// + /// + /// The continuation offset. + /// + /// + /// This is a mapping of the "vid-offset" prop in the JSON reeturn data from HubSpot + /// + [DataMember(Name = "offset")] + public long ContinuationOffset { get; set; } + + [IgnoreDataMember] + public bool IsNameValue => false; + + public void ToHubSpotDataEntity(ref dynamic dataEntity) + { + } + + public void FromHubSpotDataEntity(dynamic hubspotData) + { + } + + [IgnoreDataMember] + public string RouteBasePath => "/contacts/v1/lists"; + } +} \ No newline at end of file diff --git a/HubSpot.NET/Api/ContactList/HubSpotContactListApi.cs b/HubSpot.NET/Api/ContactList/HubSpotContactListApi.cs new file mode 100644 index 00000000..1bf7405d --- /dev/null +++ b/HubSpot.NET/Api/ContactList/HubSpotContactListApi.cs @@ -0,0 +1,83 @@ +using System.Collections.Generic; +using Flurl; +using HubSpot.NET.Api.ContactList.Dto; +using HubSpot.NET.Core.Interfaces; +using RestSharp; + +namespace HubSpot.NET.Api.ContactList +{ + public class HubSpotContactListApi : IHubSpotContactListApi + { + private readonly IHubSpotClient _client; + + public HubSpotContactListApi(IHubSpotClient client) + { + _client = client; + } + + public ListContactListModel GetContactLists(ListOptions opts = null) + { + if (opts == null) + { + opts = new ListOptions(); + } + + var path = $"{new ListContactListModel().RouteBasePath}".SetQueryParam("count", opts.Limit); + if (opts.Offset.HasValue) + { + path = path.SetQueryParam("offset", opts.Offset); + } + + var data = _client.ExecuteList(path, convertToPropertiesSchema: false); + + return data; + } + + public ListContactListModel GetStaticContactLists(ListOptions opts = null) + { + if (opts == null) + { + opts = new ListOptions(); + } + + var path = $"{new ListContactListModel().RouteBasePath}/static".SetQueryParam("count", opts.Limit); + if (opts.Offset.HasValue) + { + path = path.SetQueryParam("offset", opts.Offset); + } + + var data = _client.ExecuteList(path, convertToPropertiesSchema: false); + + return data; + } + + public ContactListModel GetContactListById(long contactListId) + { + var path = $"{new ContactListModel().RouteBasePath}/{contactListId}"; + + var data = _client.ExecuteList(path, convertToPropertiesSchema: false); + + return data; + } + + public ContactListUpdateResponseModel AddContactsToList(long listId, IEnumerable contactIds) + { + var model = new ContactListUpdateModel(); + var path = $"{model.RouteBasePath}/{listId}/add"; + model.ContactIds.AddRange(contactIds); + var data = _client.Execute(path, model, Method.POST, convertToPropertiesSchema: false); + + return data; + } + + public ContactListUpdateResponseModel RemoveContactsFromList(long listId, IEnumerable contactIds) + { + var model = new ContactListUpdateModel(); + var path = $"{model.RouteBasePath}/{listId}/remove"; + model.ContactIds.AddRange(contactIds); + var data = _client.Execute(path, model, Method.POST, convertToPropertiesSchema: false); + + return data; + } + } +} \ No newline at end of file diff --git a/HubSpot.NET/Api/ContactList/ListOptions.cs b/HubSpot.NET/Api/ContactList/ListOptions.cs new file mode 100644 index 00000000..3da8e657 --- /dev/null +++ b/HubSpot.NET/Api/ContactList/ListOptions.cs @@ -0,0 +1,42 @@ +using System; + +namespace HubSpot.NET.Api.ContactList +{ + public class ListOptions + { + /// + /// Get or set the continuation offset when calling list many times to enumerate all your items + /// + /// + /// The return DTO from List contains the current "offset" that you can inject into your next list call + /// to continue the listing process + /// + public virtual long? Offset { get; set; } = null; + + private int _limit = 20; + private readonly int _upperLimit = 250; + + /// + /// Gets or sets the number of items to return. + /// + /// + /// Defaults to 20 which is also the HubSpot API default. Max value is 100 + /// + /// + /// The number of items to return. + /// + public virtual int Limit + { + get => _limit; + set + { + if (value < 1 || value > _upperLimit) + { + throw new ArgumentException( + $"Number of items to return must be a positive integer greater than 0, and less than {_upperLimit} - you provided {value}"); + } + _limit = value; + } + } + } +} \ No newline at end of file diff --git a/HubSpot.NET/Core/HubSpotApi.cs b/HubSpot.NET/Core/HubSpotApi.cs index f9ddc808..ff4f08ef 100644 --- a/HubSpot.NET/Core/HubSpotApi.cs +++ b/HubSpot.NET/Core/HubSpotApi.cs @@ -1,5 +1,6 @@ using HubSpot.NET.Api.Company; using HubSpot.NET.Api.Contact; +using HubSpot.NET.Api.ContactList; using HubSpot.NET.Api.Deal; using HubSpot.NET.Api.EmailSubscriptions; using HubSpot.NET.Api.Engagement; @@ -22,6 +23,7 @@ public class HubSpotApi : IHubSpotApi public IHubSpotCosFileApi File { get; } public IHubSpotOwnerApi Owner { get; } public IHubSpotCompanyPropertiesApi CompanyProperties { get; } + public IHubSpotContactListApi ContactLists { get; } public IHubSpotEmailSubscriptionsApi EmailSubscriptions { get; } @@ -37,6 +39,7 @@ public HubSpotApi(string apiKey) Owner = new HubSpotOwnerApi(client); CompanyProperties = new HubSpotCompaniesPropertiesApi(client); EmailSubscriptions = new HubSpotEmailSubscriptionsApi(client); + ContactLists = new HubSpotContactListApi(client); } } diff --git a/HubSpot.NET/Core/Interfaces/IHubSpotContactListApi.cs b/HubSpot.NET/Core/Interfaces/IHubSpotContactListApi.cs new file mode 100644 index 00000000..e04b6615 --- /dev/null +++ b/HubSpot.NET/Core/Interfaces/IHubSpotContactListApi.cs @@ -0,0 +1,19 @@ +using System.Collections.Generic; +using HubSpot.NET.Api.ContactList; +using HubSpot.NET.Api.ContactList.Dto; + +namespace HubSpot.NET.Core.Interfaces +{ + public interface IHubSpotContactListApi + { + ListContactListModel GetContactLists(ListOptions opts = null); + + ListContactListModel GetStaticContactLists(ListOptions opts = null); + + ContactListModel GetContactListById(long contactListId); + + ContactListUpdateResponseModel AddContactsToList(long listId, IEnumerable contactIds); + + ContactListUpdateResponseModel RemoveContactsFromList(long listId, IEnumerable contactIds); + } +} \ No newline at end of file