├── .gitattributes ├── .gitignore ├── Build.ps1 ├── Directory.Build.props ├── LICENSE ├── README.md ├── appveyor.yml ├── dotnetcore-hubspot-client.sln ├── src ├── Associations │ ├── AssociationListRequestOptions.cs │ ├── Dto │ │ ├── AssociationHubSpotEntity.cs │ │ └── AssociationListHubSpotEntity.cs │ ├── HubSpotAssociationsClient.cs │ └── Interfaces │ │ ├── IAssociationHubSpotEntity.cs │ │ ├── IAssociationListHubSpotEntity.cs │ │ └── IHubSpotAssociationsClient.cs ├── Common │ ├── Dto │ │ └── Properties │ │ │ ├── PropertyHubSpotEntity.cs │ │ │ ├── PropertyListHubSpotEntity.cs │ │ │ └── PropertyOptionHubSpotEntity.cs │ └── Interfaces │ │ └── IPropertyHubSpotEntity.cs ├── Company │ ├── CompanyListRequestOptions.cs │ ├── CompanySearchByDomain.cs │ ├── CompanySearchOffset.cs │ ├── CompanySearchRequestOptions.cs │ ├── Dto │ │ ├── CompanyHubSpotEntity.cs │ │ ├── CompanyListHubSpotEntity.cs │ │ ├── CompanyPropertyHubSpotEntity.cs │ │ └── CompanySearchResultEntity.cs │ ├── HubSpotCompanyClient.cs │ └── Interfaces │ │ ├── ICompanyHubSpotEntity.cs │ │ ├── ICompanyListHubSpotEntity.cs │ │ ├── ICompanyPropertyHubSpotEntity.cs │ │ ├── ICompanySearchResultEntity.cs │ │ └── IHubSpotCompanyClient.cs ├── Contact │ ├── ContactFormSubmissionMode.cs │ ├── ContactGetRequestOptions.cs │ ├── ContactRequestOptions.cs │ ├── Dto │ │ ├── ContactHubSpotEntity.cs │ │ └── ContactListHubSpotEntity.cs │ ├── HubSpotContactClient.cs │ └── Interfaces │ │ ├── IContactHubSpotEntity.cs │ │ ├── IContactListHubSpotEntity.cs │ │ └── IHubSpotContactClient.cs ├── Core │ ├── HubSpotAction.cs │ ├── HubSpotAssociationDefinitions.cs │ ├── HubSpotBaseClient.cs │ ├── Interfaces │ │ └── IHubSpotEntity.cs │ ├── JsonContent.cs │ ├── NoopLogger.cs │ ├── NoopLoggerFactory.cs │ ├── ReflectionExtensions.cs │ └── Requests │ │ ├── HubspotDataEntityProp.cs │ │ ├── RequestDataConverter.cs │ │ └── RequestSerializer.cs ├── Deal │ ├── DealListRequestOptions.cs │ ├── Dto │ │ ├── DealHubSpotAssociations.cs │ │ ├── DealHubSpotEntity.cs │ │ ├── DealListHubSpotEntity.cs │ │ └── DealPropertyHubSpotEntity.cs │ ├── HubSpotDealClient.cs │ └── Interfaces │ │ ├── IDealHubSpotEntity.cs │ │ ├── IDealListHubSpotEntity.cs │ │ ├── IDealPropertyHubSpotEntity.cs │ │ └── IHubSpotDealClient.cs ├── HubSpotException.cs ├── LineItem │ ├── Dto │ │ ├── LineItemHubSpotEntity.cs │ │ └── LineItemListHubSpotEntity.cs │ ├── HubSpotLineItemClient.cs │ └── Interfaces │ │ ├── IHubSpotLineItemClient.cs │ │ ├── ILineItemHubSpotEntity.cs │ │ ├── ILineItemListHubSpotEntity.cs │ │ ├── LineItemListRequestOptions.cs │ │ ├── LineItemRequestOptions.cs │ │ └── ListOfLineItemIds.cs ├── ListOfContacts │ ├── Dto │ │ ├── ContactListFilter.cs │ │ ├── ContactListMetaData.cs │ │ ├── CreateContactListRequestHubSpotEntity.cs │ │ ├── CreateContactListResponseHubSpotEntity.cs │ │ ├── HubSpotListOfContactsEntity.cs │ │ ├── ListOfContactListsHubSpotEntity.cs │ │ └── ListOfContactsHubSpotEntity.cs │ ├── HubSpotListOfContactsClient.cs │ ├── Interfaces │ │ ├── IContactListFilter.cs │ │ ├── ICreateContactListRequestHubSpotEntity.cs │ │ ├── IHubSpotListOfContactsClient.cs │ │ ├── IHubSpotListOfContactsEntity.cs │ │ └── IListOfContactsHubSpotEntity.cs │ ├── ListOfContactListsRequestOptions.cs │ └── ListOfContactsRequestOptions.cs ├── Owner │ ├── Dto │ │ └── OwnerHubSpotEntity.cs │ ├── HubSpotOwnerClient.cs │ ├── Interfaces │ │ ├── IHubSpotOwnerClient.cs │ │ └── IOwnerHubSpotEntity.cs │ └── OwnerListRequestOptions.cs ├── Properties │ └── AssemblyInfo.cs └── hubspot-client.csproj └── test ├── functional ├── Association │ └── HubSpotAssociationClientFunctionalTest.cs ├── Company │ └── HubSpotCompanyClientFunctionalTest.cs ├── Contact │ └── HubSpotContactClientFunctionalTest.cs ├── Deal │ └── HubSpotDealClientFunctionalTest.cs ├── FunctionalTestBase.cs ├── LineItem │ └── HubSpotLineItemClientFunctionalTest.cs ├── Mocks │ ├── Association │ │ ├── CreateAssociationMockTestCase.cs │ │ ├── CreateBatchAssociationMockTestCase.cs │ │ ├── CreateBatchAssociationMockTestFailCase.cs │ │ ├── DeleteAssociationMockTestCase.cs │ │ ├── DeleteBatchAssociationMockTestCase.cs │ │ └── ListAssociationMockTestCase.cs │ ├── Company │ │ ├── CreateCompanyMockTestCase.cs │ │ ├── DeleteCompanyMockTestCase.cs │ │ ├── GetCompanyByIdNotFoundMockTestCase.cs │ │ ├── GetCompanyMockTestCase.cs │ │ ├── ListCompanyMockTestCase.cs │ │ ├── SearchByDomainMockTestCase.cs │ │ └── UpdateCompanyMockTestCase.cs │ ├── Contact │ │ ├── CreateContactMockTestCase.cs │ │ ├── CreateOrUpdateContactMockTestCase.cs │ │ ├── DeleteContactMockTestCase.cs │ │ ├── GetContactByEmailMockTestCase.cs │ │ ├── GetContactByEmailNotFoundMockTestCase.cs │ │ ├── GetContactMockTestCase.cs │ │ ├── ListContactMockTestCase.cs │ │ └── UpdateContactMockTestCase.cs │ ├── Deal │ │ ├── CreateDealMockTestCase.cs │ │ ├── DeleteDealMockTestCase.cs │ │ ├── GetDealByIdNotFoundMockTestCase.cs │ │ ├── GetDealMockTestCase.cs │ │ └── UpdateDealMockTestCase.cs │ ├── LineItem │ │ ├── CreateBatchLineItemMockTestCase.cs │ │ ├── CreateLineItemMockTestCase.cs │ │ ├── DeleteBatchLineItemMockTestCase.cs │ │ ├── DeleteLineItemMockTestCase.cs │ │ ├── GetLineItemMockTestCase.cs │ │ ├── GetLineItemNotFoundMockTestCase.cs │ │ ├── ListLineItemMockTestCase.cs │ │ ├── ReadBatchLineItemMockTestCase.cs │ │ ├── UpdateBatchLineItemMockTestCase.cs │ │ └── UpdateLineItemMockTestCase.cs │ └── Owner │ │ ├── GetOwnerByIdNotFoundMockTestCase.cs │ │ ├── GetOwnerMockTestCase.cs │ │ └── ListOwnerMockTestCase.cs ├── Owner │ └── HubSpotOwnerClientFunctionalTest.cs └── functional.csproj ├── integration ├── Company │ └── HubSpotCompanyClientIntegrationTest.cs ├── Contact │ ├── Dto │ │ └── ContactHubSpotEntityExtended.cs │ └── HubSpotContactClientIntegrationTest.cs ├── Deal │ └── HubSpotDealClientIntegrationTest.cs ├── IntegrationTestBase.cs └── integration.csproj └── unit ├── Association └── HubSpotAssociationClientTest.cs ├── Company └── HubSpotCompanyClientTest.cs ├── Contact ├── HubSpotContactClientTest.cs └── ListContactsRequestOptionsTest.cs ├── Core ├── HubspotExceptionTest.cs ├── ReflectionExtensionTest.cs └── Requests │ ├── RequestDataConverterTest.cs │ └── RequestSerializerTest.cs ├── Deal └── HubSpotDealClientTest.cs ├── LineItem └── HubSpotLineItemClientTest.cs ├── Owner └── HubSpotOwnerClientTest.cs ├── UnitTestBase.cs └── unit.csproj /.gitattributes: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Set default behavior to automatically normalize line endings. 3 | ############################################################################### 4 | * text=auto 5 | 6 | ############################################################################### 7 | # Set default behavior for command prompt diff. 8 | # 9 | # This is need for earlier builds of msysgit that does not have it on by 10 | # default for csharp files. 11 | # Note: This is only used by command line 12 | ############################################################################### 13 | #*.cs diff=csharp 14 | 15 | ############################################################################### 16 | # Set the merge driver for project and solution files 17 | # 18 | # Merging from the command prompt will add diff markers to the files if there 19 | # are conflicts (Merging from VS is not affected by the settings below, in VS 20 | # the diff markers are never inserted). Diff markers may cause the following 21 | # file extensions to fail to load in VS. An alternative would be to treat 22 | # these files as binary and thus will always conflict and require user 23 | # intervention with every merge. To do so, just uncomment the entries below 24 | ############################################################################### 25 | #*.sln merge=binary 26 | #*.csproj merge=binary 27 | #*.vbproj merge=binary 28 | #*.vcxproj merge=binary 29 | #*.vcproj merge=binary 30 | #*.dbproj merge=binary 31 | #*.fsproj merge=binary 32 | #*.lsproj merge=binary 33 | #*.wixproj merge=binary 34 | #*.modelproj merge=binary 35 | #*.sqlproj merge=binary 36 | #*.wwaproj merge=binary 37 | 38 | ############################################################################### 39 | # behavior for image files 40 | # 41 | # image files are treated as binary by default. 42 | ############################################################################### 43 | #*.jpg binary 44 | #*.png binary 45 | #*.gif binary 46 | 47 | ############################################################################### 48 | # diff behavior for common document formats 49 | # 50 | # Convert binary document formats to text before diffing them. This feature 51 | # is only available from the command line. Turn it on by uncommenting the 52 | # entries below. 53 | ############################################################################### 54 | #*.doc diff=astextplain 55 | #*.DOC diff=astextplain 56 | #*.docx diff=astextplain 57 | #*.DOCX diff=astextplain 58 | #*.dot diff=astextplain 59 | #*.DOT diff=astextplain 60 | #*.pdf diff=astextplain 61 | #*.PDF diff=astextplain 62 | #*.rtf diff=astextplain 63 | #*.RTF diff=astextplain 64 | -------------------------------------------------------------------------------- /Build.ps1: -------------------------------------------------------------------------------- 1 | # Taken from psake https://github.com/psake/psake 2 | 3 | <# 4 | .SYNOPSIS 5 | This is a helper function that runs a scriptblock and checks the PS variable $lastexitcode 6 | to see if an error occcured. If an error is detected then an exception is thrown. 7 | This function allows you to run command-line programs without having to 8 | explicitly check the $lastexitcode variable. 9 | .EXAMPLE 10 | exec { svn info $repository_trunk } "Error executing SVN. Please verify SVN command-line client is installed" 11 | #> 12 | function Exec 13 | { 14 | [CmdletBinding()] 15 | param( 16 | [Parameter(Position=0,Mandatory=1)][scriptblock]$cmd, 17 | [Parameter(Position=1,Mandatory=0)][string]$errorMessage = ($msgs.error_bad_command -f $cmd) 18 | ) 19 | & $cmd 20 | if ($lastexitcode -ne 0) { 21 | throw ("Exec: " + $errorMessage) 22 | } 23 | } 24 | 25 | if(Test-Path .\artifacts) { Remove-Item .\artifacts -Force -Recurse } 26 | 27 | exec { & dotnet restore } 28 | 29 | $revision = @{ $true = $env:APPVEYOR_BUILD_NUMBER; $false = 1 }[$env:APPVEYOR_BUILD_NUMBER -ne $NULL]; 30 | $revision = "{0:D4}" -f [convert]::ToInt32($revision, 10) 31 | 32 | exec { & dotnet build } 33 | 34 | exec { & dotnet test .\test\unit\unit.csproj -c Release } 35 | exec { & dotnet test .\test\functional\functional.csproj -c Release } 36 | exec { & dotnet test .\test\integration\integration.csproj -c Release } 37 | 38 | exec { & dotnet pack .\src\hubspot-client.csproj -c Release -o .\artifacts --include-source } 39 | -------------------------------------------------------------------------------- /Directory.Build.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | latest 5 | 6 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 SKARP ApS 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /appveyor.yml: -------------------------------------------------------------------------------- 1 | version: '{build}' 2 | # Build worker image (VM template) 3 | image: Visual Studio 2022 4 | environment: 5 | HUBSPOT_API_KEY: 6 | secure: nEkpqjqVe4G73k8gkmpYndR8GGQdK58k98IxzWwoZS4Rvq+bTOR9Yok2ISgjjNWr 7 | HUBSPOT_API_TOKEN: 8 | secure: nWXtqDplY3BMELyLFkxVlKcMECU4+rs9sJuWaNkFbHik3n9VOeRGPLOGsUN3UMAz 9 | pull_requests: 10 | do_not_increment_build_number: true 11 | branches: 12 | only: 13 | - master 14 | nuget: 15 | disable_publish_on_pr: true 16 | build_script: 17 | - ps: .\Build.ps1 18 | test: off 19 | artifacts: 20 | - path: '**\*.nupkg' 21 | name: NuGet 22 | deploy: 23 | - provider: NuGet 24 | name: production 25 | api_key: 26 | secure: ZT7fXPicb4xNWbc+ciajbmrXRTiMSjwQFkF5wrGIhcLW96WHQBFQjSZTDfn+ldbY 27 | skip_symbols: true 28 | on: 29 | appveyor_repo_tag: true -------------------------------------------------------------------------------- /src/Associations/AssociationListRequestOptions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace Skarp.HubSpotClient.Associations 6 | { 7 | public class AssociationListRequestOptions 8 | { 9 | private int _numberOfAssociationsToReturn = 100; 10 | 11 | /// 12 | /// Gets or sets the number of associations to return. 13 | /// 14 | /// 15 | /// Defaults to 20 which is also the hubspot api default. Max value is 100 16 | /// 17 | /// 18 | /// The number of contacts to return. 19 | /// 20 | public int NumberOfAssociationsToReturn 21 | { 22 | get => _numberOfAssociationsToReturn; 23 | set 24 | { 25 | if (value < 1 || value > 100) 26 | { 27 | throw new ArgumentException( 28 | $"Number of associations to return must be a positive ingeteger greater than 0 and less than 101 - you provided {value}"); 29 | } 30 | _numberOfAssociationsToReturn = value; 31 | } 32 | } 33 | 34 | public long? AssociationOffset { get; set; } = null; 35 | 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/Associations/Dto/AssociationHubSpotEntity.cs: -------------------------------------------------------------------------------- 1 | using Skarp.HubSpotClient.Associations.Interfaces; 2 | using Skarp.HubSpotClient.Core; 3 | using System.Runtime.Serialization; 4 | 5 | namespace Skarp.HubSpotClient.Associations.Dto 6 | { 7 | [DataContract] 8 | public class AssociationHubSpotEntity : IAssociationHubSpotEntity 9 | { 10 | [DataMember(Name = "fromObjectId")] 11 | public long FromObjectId { get; set; } 12 | [DataMember(Name = "toObjectId")] 13 | public long ToObjectId { get; set; } 14 | 15 | [DataMember(Name = "category")] 16 | public string Category => "HUBSPOT_DEFINED"; 17 | 18 | [DataMember(Name = "definitionId")] 19 | public int DefinitionId { get; set; } 20 | 21 | public string RouteBasePath => "/crm-associations/v1"; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/Associations/Dto/AssociationListHubSpotEntity.cs: -------------------------------------------------------------------------------- 1 | using Skarp.HubSpotClient.Associations.Interfaces; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Runtime.Serialization; 5 | using System.Text; 6 | 7 | namespace Skarp.HubSpotClient.Associations.Dto 8 | { 9 | [DataContract] 10 | public class AssociationListHubSpotEntity : IAssociationListHubSpotEntity 11 | { 12 | [DataMember(Name = "results")] 13 | public IList Results { get; set; } = new List(); 14 | [DataMember(Name = "hasMore")] 15 | public bool MoreResultsAvailable { get; set; } 16 | [DataMember(Name = "offset")] 17 | public long ContinuationOffset { get; set; } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/Associations/Interfaces/IAssociationHubSpotEntity.cs: -------------------------------------------------------------------------------- 1 | using Skarp.HubSpotClient.Core; 2 | 3 | namespace Skarp.HubSpotClient.Associations.Interfaces 4 | { 5 | // not using IHubSpotEntity because the api does not map to and from with property values. Mostly uses just ids 6 | public interface IAssociationHubSpotEntity 7 | { 8 | long FromObjectId { get; set; } 9 | long ToObjectId { get; set; } 10 | string Category { get; } 11 | int DefinitionId { get; set; } 12 | string RouteBasePath { get; } 13 | 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/Associations/Interfaces/IAssociationListHubSpotEntity.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace Skarp.HubSpotClient.Associations.Interfaces 4 | { 5 | public interface IAssociationListHubSpotEntity 6 | { 7 | /// 8 | /// Gets or sets the association results. 9 | /// 10 | /// 11 | /// The contacts. 12 | /// 13 | IList Results { get; set; } 14 | 15 | /// 16 | /// Gets or sets a value indicating whether more results are available. 17 | /// 18 | /// 19 | /// This is a mapping of the "has-more" prop in the JSON return data from HubSpot 20 | /// 21 | /// 22 | /// true if [more results available]; otherwise, false. 23 | /// 24 | bool MoreResultsAvailable { get; set; } 25 | 26 | /// 27 | /// Gets or sets the continuation offset. 28 | /// 29 | /// 30 | /// This is a mapping of the "vid-offset" prop in the JSON reeturn data from HubSpot 31 | /// 32 | /// 33 | /// The continuation offset. 34 | /// 35 | long ContinuationOffset { get; set; } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/Associations/Interfaces/IHubSpotAssociationsClient.cs: -------------------------------------------------------------------------------- 1 | using Skarp.HubSpotClient.Associations.Interfaces; 2 | using Skarp.HubSpotClient.Core; 3 | using System.Collections.Generic; 4 | using System.Threading.Tasks; 5 | 6 | namespace Skarp.HubSpotClient.Associations 7 | { 8 | public interface IHubSpotAssociationsClient 9 | { 10 | /// 11 | /// Create association based on definition id 12 | /// 13 | /// 14 | /// 15 | Task Create(T entity); 16 | /// 17 | /// Create in batch associations based on definition id 18 | /// 19 | /// 20 | /// 21 | Task CreateBatch(List entities); 22 | /// 23 | /// Delete association based on definition id 24 | /// 25 | /// 26 | /// 27 | Task Delete(T entity); 28 | /// 29 | /// Delete in batch associations based on definition id 30 | /// 31 | /// 32 | /// 33 | Task DeleteBatch(List entities); 34 | /// 35 | /// Return a list of associations for a CRM object by id from hubspot based on the association definition id 36 | /// 37 | /// Object ID for which to list its associations 38 | /// The definition ID of the associations to list 39 | /// Additional request options, use for limiting and pagination 40 | /// 41 | Task> GetListByIdAsync(long fromObjectId, HubSpotAssociationDefinitions definitionId, AssociationListRequestOptions opts = null); 42 | } 43 | } -------------------------------------------------------------------------------- /src/Common/Dto/Properties/PropertyHubSpotEntity.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Runtime.Serialization; 3 | using Skarp.HubSpotClient.Common.Interfaces; 4 | 5 | namespace Skarp.HubSpotClient.Common.Dto.Properties 6 | { 7 | [DataContract] 8 | public class PropertyHubSpotEntity : IPropertyHubSpotEntity 9 | { 10 | [DataMember(Name = "name")] 11 | public string Name { get; set; } 12 | 13 | [DataMember(Name = "label")] 14 | public string Label { get; set; } 15 | 16 | [DataMember(Name = "description")] 17 | public string Description { get; set; } 18 | 19 | [DataMember(Name = "groupName")] 20 | public string GroupName { get; set; } 21 | 22 | [DataMember(Name = "type")] 23 | public string Type { get; set; } 24 | 25 | [DataMember(Name = "fieldType")] 26 | public string FieldType { get; set; } 27 | 28 | [DataMember(Name = "options")] 29 | public List Options { get; set; } 30 | 31 | public bool IsNameValue => false; 32 | 33 | public string RouteBasePath => "/properties/v1"; 34 | 35 | public virtual void ToHubSpotDataEntity(ref dynamic dataEntity) 36 | { 37 | 38 | } 39 | 40 | public virtual void FromHubSpotDataEntity(dynamic hubspotData) 41 | { 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/Common/Dto/Properties/PropertyListHubSpotEntity.cs: -------------------------------------------------------------------------------- 1 | using System.Collections; 2 | using System.Collections.Generic; 3 | using System.Runtime.Serialization; 4 | using Skarp.HubSpotClient.Common.Interfaces; 5 | using Skarp.HubSpotClient.Core.Interfaces; 6 | 7 | namespace Skarp.HubSpotClient.Common.Dto.Properties 8 | { 9 | [DataContract] 10 | public class PropertyListHubSpotEntity : IHubSpotEntity, ICollection 11 | where T : IPropertyHubSpotEntity 12 | { 13 | private List Properties { get; } = new(); 14 | 15 | public bool IsNameValue => false; 16 | 17 | public IEnumerator GetEnumerator() 18 | => Properties.GetEnumerator(); 19 | 20 | IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); 21 | 22 | public void Add(T item) 23 | => Properties.Add(item); 24 | 25 | public void Clear() 26 | => Properties.Clear(); 27 | 28 | public bool Contains(T item) 29 | => Properties.Contains(item); 30 | 31 | public void CopyTo(T[] array, int arrayIndex) 32 | => Properties.CopyTo(array, arrayIndex); 33 | 34 | public bool Remove(T item) 35 | => Properties.Remove(item); 36 | 37 | public int Count 38 | => Properties.Count; 39 | 40 | public bool IsReadOnly 41 | => false; 42 | 43 | public virtual void ToHubSpotDataEntity(ref dynamic dataEntity) 44 | { 45 | 46 | } 47 | 48 | public virtual void FromHubSpotDataEntity(dynamic hubspotData) 49 | { 50 | 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/Common/Dto/Properties/PropertyOptionHubSpotEntity.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.Serialization; 2 | 3 | namespace Skarp.HubSpotClient.Common.Dto.Properties 4 | { 5 | [DataContract] 6 | public class PropertyOptionHubSpotEntity 7 | { 8 | [DataMember(Name = "label")] 9 | public string Label { get; set; } 10 | 11 | [DataMember(Name = "value")] 12 | public string Value { get; set; } 13 | 14 | [DataMember(Name = "description")] 15 | public string Description { get; set; } 16 | 17 | [DataMember(Name = "readOnly")] 18 | public bool? ReadOnly { get; set; } 19 | 20 | [DataMember(Name = "hidden")] 21 | public bool Hidden { get; set; } 22 | 23 | [DataMember(Name = "displayOrder")] 24 | public long DisplayOrder { get; set; } 25 | 26 | [DataMember(Name = "doubleData")] 27 | public object DoubleData { get; set; } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/Common/Interfaces/IPropertyHubSpotEntity.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using Skarp.HubSpotClient.Common.Dto.Properties; 3 | using Skarp.HubSpotClient.Core.Interfaces; 4 | 5 | namespace Skarp.HubSpotClient.Common.Interfaces 6 | { 7 | public interface IPropertyHubSpotEntity : IHubSpotEntity 8 | { 9 | string Name { get; set; } 10 | 11 | string Label { get; set; } 12 | 13 | string Description { get; set; } 14 | 15 | string GroupName { get; set; } 16 | 17 | string Type { get; set; } 18 | 19 | string FieldType { get; set; } 20 | 21 | string RouteBasePath { get; } 22 | 23 | List Options { get; set; } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/Company/CompanyListRequestOptions.cs: -------------------------------------------------------------------------------- 1 | using Skarp.HubSpotClient.Core.Interfaces; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Text; 5 | 6 | namespace Skarp.HubSpotClient.Company 7 | { 8 | public class CompanyListRequestOptions 9 | { 10 | private int _numberOfCompaniesToReturn = 100; 11 | 12 | /// 13 | /// Gets or sets the number of companies to return. 14 | /// 15 | /// 16 | /// Defaults to 20 which is also the hubspot api default. Max value is 100 17 | /// 18 | /// 19 | /// The number of companies to return. 20 | /// 21 | public int NumberOfCompaniesToReturn 22 | { 23 | get => _numberOfCompaniesToReturn; 24 | set 25 | { 26 | if (value < 1 || value > 250) 27 | { 28 | throw new ArgumentException( 29 | $"Number of companies to return must be a positive ingeteger greater than 0 and less than 251 - you provided {value}"); 30 | } 31 | _numberOfCompaniesToReturn = value; 32 | } 33 | } 34 | 35 | /// 36 | /// Get or set the continuation offset when calling list many times to enumerate all your companies 37 | /// 38 | /// 39 | /// The return DTO from List contains the current "offset" that you can inject into your next list call 40 | /// to continue the listing process 41 | /// 42 | public long? CompanyOffset { get; set; } = null; 43 | public List PropertiesToInclude { get; set; } = new List(); 44 | 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/Company/CompanySearchByDomain.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.Serialization; 2 | 3 | namespace Skarp.HubSpotClient.Company 4 | { 5 | [DataContract] 6 | public class CompanySearchByDomain 7 | { 8 | [DataMember(Name = "limit")] 9 | public int Limit { get; set; } = 100; 10 | 11 | [DataMember(Name = "requestOptions")] 12 | public CompanySearchRequestOptions RequestOptions { get; set; } = new CompanySearchRequestOptions(); 13 | 14 | [DataMember(Name = "offset")] 15 | public CompanySearchOffset Offset { get; set; } = new CompanySearchOffset(); 16 | 17 | public string RouteBasePath => "/companies/v2"; 18 | public bool IsNameValue => true; 19 | public void AcceptHubSpotDataEntity(ref object converted) 20 | { 21 | 22 | } 23 | } 24 | } -------------------------------------------------------------------------------- /src/Company/CompanySearchOffset.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.Serialization; 2 | 3 | namespace Skarp.HubSpotClient.Company 4 | { 5 | [DataContract] 6 | public class CompanySearchOffset 7 | { 8 | 9 | [DataMember(Name = "isPrimary")] 10 | public bool IsPrimary { get; set; } = true; 11 | 12 | [DataMember(Name = "companyId")] 13 | public long CompanyId { get; set; } = 0; 14 | } 15 | } -------------------------------------------------------------------------------- /src/Company/CompanySearchRequestOptions.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Runtime.Serialization; 3 | 4 | namespace Skarp.HubSpotClient.Company 5 | { 6 | [DataContract] 7 | public class CompanySearchRequestOptions 8 | { 9 | [DataMember(Name = "properties")] 10 | public List Properties { get; set; } = new List { "domain", "name", "website" }; 11 | } 12 | } -------------------------------------------------------------------------------- /src/Company/Dto/CompanyHubSpotEntity.cs: -------------------------------------------------------------------------------- 1 | using Skarp.HubSpotClient.Company.Interfaces; 2 | using System.Runtime.Serialization; 3 | 4 | namespace Skarp.HubSpotClient.Company.Dto 5 | { 6 | [DataContract] 7 | public class CompanyHubSpotEntity : ICompanyHubSpotEntity 8 | { 9 | [IgnoreDataMember] 10 | [DataMember(Name = "companyId")] 11 | public long? Id { get; set; } 12 | 13 | [DataMember(Name = "hubspot_owner_id")] 14 | public long? OwnerId { get; set; } 15 | 16 | [DataMember(Name = "name")] 17 | public string Name { get; set; } 18 | 19 | [DataMember(Name = "domain")] 20 | public string Domain { get; set; } 21 | 22 | [DataMember(Name = "website")] 23 | public string Website { get; set; } 24 | 25 | [DataMember(Name = "description")] 26 | public string Description { get; set; } 27 | 28 | public string RouteBasePath => "/companies/v2"; 29 | public bool IsNameValue => true; 30 | public virtual void ToHubSpotDataEntity(ref dynamic converted) 31 | { 32 | 33 | } 34 | 35 | public virtual void FromHubSpotDataEntity(dynamic hubspotData) 36 | { 37 | 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/Company/Dto/CompanyListHubSpotEntity.cs: -------------------------------------------------------------------------------- 1 | using Skarp.HubSpotClient.Company.Interfaces; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Runtime.Serialization; 5 | using System.Text; 6 | 7 | namespace Skarp.HubSpotClient.Company.Dto 8 | { 9 | [DataContract] 10 | public class CompanyListHubSpotEntity : ICompanyListHubSpotEntity where T : ICompanyHubSpotEntity 11 | { 12 | /// 13 | /// 14 | /// Gets or sets the companies. 15 | /// 16 | /// 17 | /// The companies. 18 | /// 19 | [DataMember(Name = "companies")] 20 | public IList Companies { get; set; } = new List(); 21 | 22 | /// 23 | /// 24 | /// Gets or sets a value indicating whether more results are available. 25 | /// 26 | /// 27 | /// true if [more results available]; otherwise, false. 28 | /// 29 | /// 30 | /// This is a mapping of the "has-more" prop in the JSON return data from HubSpot 31 | /// 32 | [DataMember(Name = "has-more")] 33 | public bool MoreResultsAvailable { get; set; } 34 | 35 | /// 36 | /// 37 | /// Gets or sets the continuation offset. 38 | /// 39 | /// 40 | /// The continuation offset. 41 | /// 42 | /// 43 | /// This is a mapping of the "offset" prop in the JSON reeturn data from HubSpot 44 | /// 45 | [DataMember(Name = "offset")] 46 | public long ContinuationOffset { get; set; } 47 | 48 | public string RouteBasePath => "/companies/v2"; 49 | 50 | public bool IsNameValue => false; 51 | public List PropertiesToInclude { get; set; } = new List(); 52 | public virtual void ToHubSpotDataEntity(ref dynamic converted) 53 | { 54 | 55 | } 56 | 57 | public virtual void FromHubSpotDataEntity(dynamic hubspotData) 58 | { 59 | 60 | } 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/Company/Dto/CompanyPropertyHubSpotEntity.cs: -------------------------------------------------------------------------------- 1 | using Skarp.HubSpotClient.Common.Dto.Properties; 2 | using Skarp.HubSpotClient.Company.Interfaces; 3 | 4 | namespace Skarp.HubSpotClient.Company.Dto 5 | { 6 | /// 7 | /// Deal Property 8 | /// 9 | /// Documentation 10 | public class CompanyPropertyHubSpotEntity : PropertyHubSpotEntity, ICompanyPropertyHubSpotEntity 11 | { 12 | 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/Company/Dto/CompanySearchResultEntity.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Runtime.Serialization; 4 | using System.Text; 5 | using Skarp.HubSpotClient.Company.Interfaces; 6 | using Skarp.HubSpotClient.Contact.Interfaces; 7 | 8 | namespace Skarp.HubSpotClient.Company.Dto 9 | { 10 | [DataContract] 11 | public class CompanySearchResultEntity : ICompanySearchResultEntity where T : ICompanyHubSpotEntity 12 | { 13 | [DataMember(Name = "results")] 14 | public IList Results { get; set; } 15 | 16 | [DataMember(Name = "hasMore")] 17 | public bool MoreResultsAvailable { get; set; } 18 | 19 | [DataMember(Name="offset")] 20 | public CompanySearchOffset Offset { get; set; } 21 | 22 | public bool IsNameValue => false; 23 | 24 | public void ToHubSpotDataEntity(ref dynamic dataEntity) 25 | { 26 | } 27 | 28 | public virtual void FromHubSpotDataEntity(dynamic hubspotData) 29 | { 30 | 31 | } 32 | } 33 | } -------------------------------------------------------------------------------- /src/Company/Interfaces/ICompanyHubSpotEntity.cs: -------------------------------------------------------------------------------- 1 | using Skarp.HubSpotClient.Core.Interfaces; 2 | 3 | namespace Skarp.HubSpotClient.Company.Interfaces 4 | { 5 | public interface ICompanyHubSpotEntity : IHubSpotEntity 6 | { 7 | long? Id { get; set; } 8 | long? OwnerId { get; set; } 9 | string Name { get; set; } 10 | string Domain { get; set; } 11 | string Website { get; set; } 12 | string Description { get; set; } 13 | string RouteBasePath { get; } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/Company/Interfaces/ICompanyListHubSpotEntity.cs: -------------------------------------------------------------------------------- 1 | using Skarp.HubSpotClient.Core.Interfaces; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Text; 5 | 6 | namespace Skarp.HubSpotClient.Company.Interfaces 7 | { 8 | public interface ICompanyListHubSpotEntity : IHubSpotEntity where T : ICompanyHubSpotEntity 9 | { 10 | /// 11 | /// Gets or sets the companies. 12 | /// 13 | /// 14 | /// The companies. 15 | /// 16 | IList Companies { get; set; } 17 | 18 | /// 19 | /// Gets or sets a value indicating whether more results are available. 20 | /// 21 | /// 22 | /// This is a mapping of the "has-more" prop in the JSON return data from HubSpot 23 | /// 24 | /// 25 | /// true if [more results available]; otherwise, false. 26 | /// 27 | bool MoreResultsAvailable { get; set; } 28 | 29 | /// 30 | /// Gets or sets the continuation offset. 31 | /// 32 | /// 33 | /// This is a mapping of the "vid-offset" prop in the JSON reeturn data from HubSpot 34 | /// 35 | /// 36 | /// The continuation offset. 37 | /// 38 | long ContinuationOffset { get; set; } 39 | 40 | string RouteBasePath { get; } 41 | List PropertiesToInclude { get; set; } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/Company/Interfaces/ICompanyPropertyHubSpotEntity.cs: -------------------------------------------------------------------------------- 1 | using Skarp.HubSpotClient.Common.Interfaces; 2 | 3 | namespace Skarp.HubSpotClient.Company.Interfaces 4 | { 5 | public interface ICompanyPropertyHubSpotEntity : IPropertyHubSpotEntity 6 | { 7 | 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/Company/Interfaces/ICompanySearchResultEntity.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | using Skarp.HubSpotClient.Core.Interfaces; 5 | 6 | namespace Skarp.HubSpotClient.Company.Interfaces 7 | { 8 | public interface ICompanySearchResultEntity : IHubSpotEntity where T : ICompanyHubSpotEntity 9 | { 10 | IList Results { get; set; } 11 | 12 | bool MoreResultsAvailable { get; set; } 13 | 14 | CompanySearchOffset Offset { get; set; } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/Company/Interfaces/IHubSpotCompanyClient.cs: -------------------------------------------------------------------------------- 1 | using Skarp.HubSpotClient.Core.Interfaces; 2 | using System.Threading.Tasks; 3 | 4 | namespace Skarp.HubSpotClient.Company.Interfaces 5 | { 6 | public interface IHubSpotCompanyClient 7 | { 8 | /// 9 | /// Creates the Company entity asynchronously. 10 | /// 11 | /// The entity. 12 | /// 13 | /// 14 | Task CreateAsync(ICompanyHubSpotEntity entity) where T : IHubSpotEntity, new(); 15 | /// 16 | /// Delete a company from hubspot by id 17 | /// 18 | /// 19 | /// 20 | Task DeleteAsync(long CompanyId); 21 | /// 22 | /// Get a Company by email address (only searches on domain) 23 | /// 24 | /// 25 | /// 26 | /// 27 | Task GetByEmailAsync(string email, CompanySearchByDomain opts = null) where T : IHubSpotEntity, new(); 28 | /// 29 | /// Return a single Company by id from hubspot 30 | /// 31 | /// 32 | /// 33 | /// 34 | Task GetByIdAsync(long CompanyId) where T : IHubSpotEntity, new(); 35 | /// 36 | /// List Companies 37 | /// 38 | /// Request options - use for pagination 39 | /// 40 | /// 41 | Task ListAsync(CompanyListRequestOptions opts = null) where T : IHubSpotEntity, new(); 42 | /// 43 | /// Update an existing company in hubspot 44 | /// 45 | /// 46 | /// 47 | /// 48 | Task UpdateAsync(ICompanyHubSpotEntity entity) where T : IHubSpotEntity, new(); 49 | /// 50 | /// List company properties 51 | /// 52 | /// 53 | /// 54 | Task GetPropertiesAsync() where T : IHubSpotEntity, new(); 55 | } 56 | } -------------------------------------------------------------------------------- /src/Contact/ContactFormSubmissionMode.cs: -------------------------------------------------------------------------------- 1 | namespace Skarp.HubSpotClient.Contact 2 | { 3 | public enum ContactFormSubmissionMode 4 | { 5 | All, 6 | None, 7 | Newest, 8 | Oldest 9 | } 10 | } -------------------------------------------------------------------------------- /src/Contact/ContactGetRequestOptions.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace Skarp.HubSpotClient.Contact 4 | { 5 | public class ContactGetRequestOptions 6 | { 7 | public List PropertiesToInclude { get; set; } = new List(); 8 | public bool IncludeHistory { get; set; } = true; // this is the default in HubSpot 9 | public ContactFormSubmissionMode FormSubmissionMode { get; set; } = ContactFormSubmissionMode.All; // this is the default in HubSpot 10 | public bool IncludeListMemberships { get; set; } = true; // this is the default in HubSpot 11 | } 12 | } -------------------------------------------------------------------------------- /src/Contact/ContactRequestOptions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | namespace Skarp.HubSpotClient.Contact 5 | { 6 | public class ContactListRequestOptions 7 | { 8 | private int _numberOfContactsToReturn = 20; 9 | 10 | /// 11 | /// Gets or sets the number of contacts to return. 12 | /// 13 | /// 14 | /// Defaults to 20 which is also the hubspot api default. Max value is 100 15 | /// 16 | /// 17 | /// The number of contacts to return. 18 | /// 19 | public int NumberOfContactsToReturn 20 | { 21 | get => _numberOfContactsToReturn; 22 | set 23 | { 24 | if (value < 1 || value > 100) 25 | { 26 | throw new ArgumentException( 27 | $"Number of contacts to return must be a positive ingeteger greater than 0 - you provided {value}"); 28 | } 29 | _numberOfContactsToReturn = value; 30 | } 31 | } 32 | 33 | /// 34 | /// Get or set the continuation offset when calling list many times to enumerate all your contacts 35 | /// 36 | /// 37 | /// The return DTO from List contains the current "offset" that you can inject into your next list call 38 | /// to continue the listing process 39 | /// 40 | public long? ContactOffset { get; set; } = null; 41 | public List PropertiesToInclude { get; set; } = new List(); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/Contact/Dto/ContactHubSpotEntity.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.Serialization; 2 | using Skarp.HubSpotClient.Contact.Interfaces; 3 | 4 | namespace Skarp.HubSpotClient.Contact.Dto 5 | { 6 | [DataContract] 7 | public class ContactHubSpotEntity : IContactHubSpotEntity 8 | { 9 | /// 10 | /// Contacts unique Id in HubSpot 11 | /// 12 | [DataMember(Name = "vid")] 13 | [IgnoreDataMember] 14 | public long? Id { get; set; } 15 | [DataMember(Name = "email")] 16 | public string Email { get; set; } 17 | [DataMember(Name = "firstname")] 18 | public string FirstName { get; set; } 19 | [DataMember(Name = "lastname")] 20 | public string Lastname { get; set; } 21 | [DataMember(Name = "website")] 22 | public string Website { get; set; } 23 | [DataMember(Name = "company")] 24 | public string Company { get; set; } 25 | [DataMember(Name = "phone")] 26 | public string Phone { get; set; } 27 | [DataMember(Name = "address")] 28 | public string Address { get; set; } 29 | [DataMember(Name = "city")] 30 | public string City { get; set; } 31 | [DataMember(Name = "state")] 32 | public string State { get; set; } 33 | [DataMember(Name = "zip")] 34 | public string ZipCode { get; set; } 35 | 36 | public string RouteBasePath => "/contacts/v1"; 37 | public bool IsNameValue => false; 38 | public virtual void ToHubSpotDataEntity(ref dynamic converted) 39 | { 40 | 41 | } 42 | 43 | public virtual void FromHubSpotDataEntity(dynamic hubspotData) 44 | { 45 | 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/Contact/Dto/ContactListHubSpotEntity.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Runtime.Serialization; 3 | using Skarp.HubSpotClient.Contact.Interfaces; 4 | 5 | namespace Skarp.HubSpotClient.Contact.Dto 6 | { 7 | [DataContract] 8 | public class ContactListHubSpotEntity : IContactListHubSpotEntity where T : IContactHubSpotEntity 9 | { 10 | /// 11 | /// 12 | /// Gets or sets the contacts. 13 | /// 14 | /// 15 | /// The contacts. 16 | /// 17 | [DataMember(Name = "contacts")] 18 | public IList Contacts { get; set; } = new List(); 19 | 20 | /// 21 | /// 22 | /// Gets or sets a value indicating whether more results are available. 23 | /// 24 | /// 25 | /// true if [more results available]; otherwise, false. 26 | /// 27 | /// 28 | /// This is a mapping of the "has-more" prop in the JSON return data from HubSpot 29 | /// 30 | [DataMember(Name = "has-more")] 31 | public bool MoreResultsAvailable { get; set; } 32 | 33 | /// 34 | /// 35 | /// Gets or sets the continuation offset. 36 | /// 37 | /// 38 | /// The continuation offset. 39 | /// 40 | /// 41 | /// This is a mapping of the "vid-offset" prop in the JSON reeturn data from HubSpot 42 | /// 43 | [DataMember(Name = "vid-offset")] 44 | public long ContinuationOffset { get; set; } 45 | 46 | public string RouteBasePath => "/contacts/v1"; 47 | 48 | public bool IsNameValue => false; 49 | public virtual void ToHubSpotDataEntity(ref dynamic converted) 50 | { 51 | 52 | } 53 | 54 | public virtual void FromHubSpotDataEntity(dynamic hubspotData) 55 | { 56 | 57 | } 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/Contact/Interfaces/IContactHubSpotEntity.cs: -------------------------------------------------------------------------------- 1 | using Skarp.HubSpotClient.Core.Interfaces; 2 | 3 | namespace Skarp.HubSpotClient.Contact.Interfaces 4 | { 5 | public interface IContactHubSpotEntity : IHubSpotEntity 6 | { 7 | long? Id { get; set; } 8 | string Email { get; set; } 9 | string FirstName { get; set; } 10 | string Lastname { get; set; } 11 | string Website { get; set; } 12 | string Company { get; set; } 13 | string Phone { get; set; } 14 | string Address { get; set; } 15 | string City { get; set; } 16 | string State { get; set; } 17 | string ZipCode { get; set; } 18 | string RouteBasePath { get; } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/Contact/Interfaces/IContactListHubSpotEntity.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using Skarp.HubSpotClient.Core.Interfaces; 3 | 4 | namespace Skarp.HubSpotClient.Contact.Interfaces 5 | { 6 | public interface IContactListHubSpotEntity : IHubSpotEntity where T : IContactHubSpotEntity 7 | { 8 | /// 9 | /// Gets or sets the contacts. 10 | /// 11 | /// 12 | /// The contacts. 13 | /// 14 | IList Contacts { get; set; } 15 | 16 | /// 17 | /// Gets or sets a value indicating whether more results are available. 18 | /// 19 | /// 20 | /// This is a mapping of the "has-more" prop in the JSON return data from HubSpot 21 | /// 22 | /// 23 | /// true if [more results available]; otherwise, false. 24 | /// 25 | bool MoreResultsAvailable { get; set; } 26 | 27 | /// 28 | /// Gets or sets the continuation offset. 29 | /// 30 | /// 31 | /// This is a mapping of the "vid-offset" prop in the JSON reeturn data from HubSpot 32 | /// 33 | /// 34 | /// The continuation offset. 35 | /// 36 | long ContinuationOffset { get; set; } 37 | 38 | string RouteBasePath { get; } 39 | } 40 | } -------------------------------------------------------------------------------- /src/Contact/Interfaces/IHubSpotContactClient.cs: -------------------------------------------------------------------------------- 1 | using Skarp.HubSpotClient.Core.Interfaces; 2 | using System.Threading.Tasks; 3 | 4 | namespace Skarp.HubSpotClient.Contact.Interfaces 5 | { 6 | public interface IHubSpotContactClient 7 | { 8 | /// 9 | /// Creates the contact entity asynchronously. 10 | /// 11 | /// The entity. 12 | /// 13 | /// 14 | Task CreateAsync(IContactHubSpotEntity entity) where T : IHubSpotEntity, new(); 15 | /// 16 | /// Creates or updates the contact entity asynchronously. 17 | /// 18 | /// The entity. 19 | /// 20 | /// 21 | Task CreateOrUpdateAsync(IContactHubSpotEntity entity) where T : IHubSpotEntity, new(); 22 | /// 23 | /// Delete an existing contact in hubspot by id 24 | /// 25 | /// 26 | /// 27 | Task DeleteAsync(long contactId); 28 | /// 29 | /// Get a contact by email address 30 | /// 31 | /// 32 | /// Options for enabling/disabling history and specifying properties 33 | /// 34 | /// 35 | Task GetByEmailAsync(string email, ContactGetRequestOptions opts = null) where T : IHubSpotEntity, new(); 36 | /// 37 | /// Return a single contact by id from hubspot 38 | /// 39 | /// 40 | /// Options for enabling/disabling history and specifying properties 41 | /// 42 | /// 43 | Task GetByIdAsync(long contactId, ContactGetRequestOptions opts = null) where T : IHubSpotEntity, new(); 44 | /// 45 | /// List contacts 46 | /// 47 | /// Request options - use for pagination 48 | /// 49 | /// 50 | Task ListAsync(ContactListRequestOptions opts = null) where T : IHubSpotEntity, new(); 51 | /// 52 | /// Update an existing contact in hubspot 53 | /// 54 | /// 55 | /// 56 | Task UpdateAsync(IContactHubSpotEntity contact); 57 | } 58 | } -------------------------------------------------------------------------------- /src/Core/HubSpotAction.cs: -------------------------------------------------------------------------------- 1 | namespace Skarp.HubSpotClient.Core 2 | { 3 | /// 4 | /// Enumerates the possible actions against the hubspot api 5 | /// 6 | public enum HubSpotAction 7 | { 8 | Create, 9 | 10 | Get, 11 | 12 | GetByEmail, 13 | 14 | List, 15 | 16 | Update, 17 | 18 | Delete, 19 | 20 | CreateOrUpdate, 21 | 22 | CreateBatch, 23 | 24 | DeleteBatch, 25 | 26 | UpdateBatch, 27 | 28 | ReadBatch, 29 | 30 | Lists 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/Core/HubSpotAssociationDefinitions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace Skarp.HubSpotClient.Core 6 | { 7 | public enum HubSpotAssociationDefinitions 8 | { 9 | 10 | ContactToCompany = 1, 11 | 12 | CompanyToContact = 2, 13 | 14 | DealToContact = 3, 15 | 16 | ContactToDeal = 4, 17 | 18 | DealToCompany = 5, 19 | 20 | CompanyToDeal = 6, 21 | 22 | CompanyToEngagement = 7, 23 | 24 | EngagementToCompany = 8, 25 | 26 | ContactToEngagement = 9, 27 | 28 | EngagementToContact = 10, 29 | 30 | DealToEngagement = 11, 31 | 32 | EngagementToDeal = 12, 33 | 34 | ParentCompanyToChildCompany = 13, 35 | 36 | ChildCompanyToParentCompany = 14, 37 | 38 | ContactToTicket = 15, 39 | 40 | TicketToContact = 16, 41 | 42 | TicketToEngagement = 17, 43 | 44 | EngagementToTicket = 18, 45 | 46 | DealToLineItem = 19, 47 | 48 | LineItemToDeal = 20, 49 | 50 | CompanyToTicket = 25, 51 | 52 | TicketToCompany = 26, 53 | 54 | DealToTicket = 27, 55 | 56 | TicketToDeal = 28, 57 | 58 | // special contact associations 59 | 60 | AdvisorToCompany = 33, 61 | 62 | CompanyToAdvisor = 34, 63 | 64 | BoardMemberToCompany = 35, 65 | 66 | CompanyToBoardMember = 36, 67 | 68 | ContractorToCompany = 37, 69 | 70 | CompanyToContractor = 38, 71 | 72 | ManagerToCompany = 39, 73 | 74 | CompanyToManager = 40, 75 | 76 | BusinessOwnerToCompany = 41, 77 | 78 | CompanyToBusinessOwner = 42, 79 | 80 | PartnerToCompany = 43, 81 | 82 | CompanyToPartner = 44, 83 | 84 | ResellerToCompany = 45, 85 | 86 | CompanyToReseller = 46 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /src/Core/Interfaces/IHubSpotEntity.cs: -------------------------------------------------------------------------------- 1 | using System.Dynamic; 2 | 3 | namespace Skarp.HubSpotClient.Core.Interfaces 4 | { 5 | public interface IHubSpotEntity 6 | { 7 | bool IsNameValue { get; } 8 | 9 | void ToHubSpotDataEntity(ref dynamic dataEntity); 10 | 11 | void FromHubSpotDataEntity(dynamic hubspotData); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/Core/JsonContent.cs: -------------------------------------------------------------------------------- 1 | using System.Net.Http; 2 | using System.Text; 3 | 4 | namespace Skarp.HubSpotClient.Core 5 | { 6 | public class JsonContent : StringContent 7 | { 8 | public JsonContent(string json) : this(json, Encoding.UTF8) 9 | { 10 | } 11 | 12 | public JsonContent(string json, Encoding encoding) : base(json, encoding, "application/json") 13 | { 14 | } 15 | } 16 | } -------------------------------------------------------------------------------- /src/Core/NoopLogger.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Microsoft.Extensions.Logging; 3 | 4 | namespace Skarp.HubSpotClient.Core 5 | { 6 | public class NoopLogger : ILogger 7 | { 8 | public void Log(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func formatter) 9 | { 10 | return; 11 | } 12 | 13 | public bool IsEnabled(LogLevel logLevel) 14 | { 15 | return false; 16 | } 17 | 18 | public IDisposable BeginScope(TState state) 19 | { 20 | return new NoopDisposable(); 21 | } 22 | } 23 | 24 | public class NoopDisposable : IDisposable 25 | { 26 | public void Dispose() 27 | { 28 | } 29 | } 30 | } -------------------------------------------------------------------------------- /src/Core/NoopLoggerFactory.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | using Microsoft.Extensions.Logging; 5 | using Microsoft.Extensions.Logging.Abstractions; 6 | 7 | namespace Skarp.HubSpotClient.Core 8 | { 9 | public static class NoopLoggerFactory 10 | { 11 | public static ILogger Get() 12 | { 13 | return new NoopLogger(); 14 | } 15 | 16 | public static ILogger Get() 17 | { 18 | return new NoopLogger(); 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/Core/ReflectionExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Reflection; 3 | using System.Runtime.Serialization; 4 | using RapidCore.Reflection; 5 | 6 | namespace Skarp.HubSpotClient.Core 7 | { 8 | internal static class ReflectionExtensions 9 | { 10 | /// 11 | /// Returns the name of a given property either by name of 12 | /// 13 | /// 14 | /// If the is defined it will try to use the prop name defined there. If no name is explictily defined in the attribute the 15 | /// name of the actual property will be returned. 16 | /// 17 | /// 18 | /// 19 | internal static string GetPropSerializedName(this PropertyInfo prop) 20 | { 21 | if (prop == null) return null; 22 | 23 | var propName = prop.Name; 24 | 25 | var dataMemberAttr = prop.GetCustomAttribute(); 26 | if (dataMemberAttr == null) return propName; 27 | if (string.IsNullOrWhiteSpace(dataMemberAttr.Name)) return propName; 28 | 29 | return dataMemberAttr.Name; 30 | } 31 | 32 | /// 33 | /// Finds the method recursively by searching in the given type and all implemented interfaces. 34 | /// 35 | /// The property. 36 | /// The name. 37 | /// The type arguments. 38 | /// 39 | /// 40 | internal static MethodInfo FindMethodRecursively(this Type prop, string name, params Type[] typeArgs) 41 | { 42 | if (prop == null) return null; 43 | 44 | // GetMethod searches base types... 45 | var method = prop.GetMethod(name, typeArgs); 46 | if (method != null) return method; 47 | 48 | 49 | foreach (var iface in prop.GetInterfaces()) 50 | { 51 | method = iface.FindMethodRecursively(name, typeArgs); 52 | if (method != null) return method; 53 | } 54 | 55 | // TODO better bailout exception? 56 | throw new ArgumentException($"Unable to locate method with name: {name}", nameof(name)); 57 | } 58 | 59 | /// 60 | /// Determines whether the given property has the 61 | /// 62 | /// The property. 63 | /// 64 | /// true if [has ignore data member attribute] [the specified property]; otherwise, false. 65 | /// 66 | internal static bool HasIgnoreDataMemberAttribute(this PropertyInfo prop) 67 | { 68 | if (prop == null) return false; 69 | 70 | return prop.HasAttribute(typeof(IgnoreDataMemberAttribute)); 71 | } 72 | 73 | /// 74 | /// Determines whether the given is a complex type or a simple ValueType 75 | /// 76 | /// The type. 77 | /// 78 | /// true if [is complex type] [the specified type]; otherwise, false. 79 | /// 80 | internal static bool IsComplexType(this Object instance) 81 | { 82 | if (instance == null) return false; 83 | 84 | var type = instance.GetType(); 85 | return type.IsComplexType(); 86 | } 87 | 88 | /// 89 | /// Determines whether [is complex type]. 90 | /// 91 | /// The type. 92 | /// 93 | /// true if [is complex type] [the specified type]; otherwise, false. 94 | /// 95 | internal static bool IsComplexType(this Type type) 96 | { 97 | if (type.GetTypeInfo().IsSubclassOf(typeof(ValueType)) || type == (typeof(string))) 98 | return false; 99 | 100 | return true; 101 | } 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /src/Core/Requests/HubspotDataEntityProp.cs: -------------------------------------------------------------------------------- 1 | namespace Skarp.HubSpotClient.Core.Requests 2 | { 3 | /// 4 | /// Represents a property value instance that can be sent to HubSpot 5 | /// 6 | public class HubspotDataEntityProp 7 | { 8 | /// 9 | /// Gets or sets the property that has a value. 10 | /// 11 | /// 12 | /// Data will only be set here if the converted DTO returns a v1 route! 13 | /// 14 | /// 15 | /// The property value 16 | /// 17 | public string Property { get; set; } 18 | 19 | /// 20 | /// Gets or sets the actual value of the given property. 21 | /// 22 | /// 23 | /// The value. 24 | /// 25 | public object Value { get; set; } 26 | 27 | /// 28 | /// Gets or sets the name of the property that has a value. 29 | /// 30 | /// 31 | /// Data will only be set here if the converted DTO returns a v2 route! 32 | /// 33 | /// 34 | /// The name. 35 | /// 36 | public object Name { get; set; } 37 | } 38 | } -------------------------------------------------------------------------------- /src/Deal/DealListRequestOptions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | namespace Skarp.HubSpotClient.Deal 5 | { 6 | public class DealListRequestOptions 7 | { 8 | private int _numberOfDealsToReturn = 100; 9 | 10 | /// 11 | /// Gets or sets the number of deals to return. 12 | /// 13 | /// 14 | /// Defaults to 20 which is also the hubspot api default. Max value is 100 15 | /// 16 | /// 17 | /// The number of deals to return. 18 | /// 19 | public int NumberOfDealsToReturn 20 | { 21 | get => _numberOfDealsToReturn; 22 | set 23 | { 24 | if (value < 1 || value > 250) 25 | { 26 | throw new ArgumentException( 27 | $"Number of deals to return must be a positive integer greater than 0 and less than 251 - you provided {value}"); 28 | } 29 | _numberOfDealsToReturn = value; 30 | } 31 | } 32 | 33 | /// 34 | /// Get or set the continuation offset when calling list many times to enumerate all your deals 35 | /// 36 | /// 37 | /// The return DTO from List contains the current "offset" that you can inject into your next list call 38 | /// to continue the listing process 39 | /// 40 | public long? DealOffset { get; set; } = null; 41 | 42 | public List PropertiesToInclude { get; set; } = new List(); 43 | 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/Deal/Dto/DealHubSpotAssociations.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.Serialization; 2 | 3 | namespace Skarp.HubSpotClient.Deal.Dto 4 | { 5 | [DataContract] 6 | public class DealHubSpotAssociations 7 | { 8 | 9 | [DataMember(Name = "associatedCompanyIds")] 10 | public long[] AssociatedCompany { get; set; } 11 | 12 | [DataMember(Name = "associatedVids")] 13 | public long[] AssociatedContacts { get; set; } 14 | } 15 | } -------------------------------------------------------------------------------- /src/Deal/Dto/DealHubSpotEntity.cs: -------------------------------------------------------------------------------- 1 | using Skarp.HubSpotClient.Deal.Interfaces; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Runtime.Serialization; 6 | using System.Text; 7 | 8 | namespace Skarp.HubSpotClient.Deal.Dto 9 | { 10 | [DataContract] 11 | public class DealHubSpotEntity : IDealHubSpotEntity 12 | { 13 | public DealHubSpotEntity() 14 | { 15 | Associations = new DealHubSpotAssociations(); 16 | } 17 | /// 18 | /// Contacts unique Id in HubSpot 19 | /// 20 | [DataMember(Name = "dealId")] 21 | [IgnoreDataMember] 22 | public long? Id { get; set; } 23 | [DataMember(Name = "dealname")] 24 | public string Name { get; set; } 25 | [DataMember(Name = "dealstage")] 26 | public string Stage { get; set; } 27 | [DataMember(Name = "pipeline")] 28 | public string Pipeline { get; set; } 29 | [DataMember(Name = "hubspot_owner_id")] 30 | public long? OwnerId { get; set; } 31 | [DataMember(Name = "closedate")] 32 | public string CloseDate { get; set; } 33 | [DataMember(Name = "amount")] 34 | public decimal Amount { get; set; } 35 | [DataMember(Name = "dealtype")] 36 | public string DealType { get; set; } 37 | [IgnoreDataMember] 38 | public DealHubSpotAssociations Associations { get; private set; } 39 | public string RouteBasePath => "/deals/v1"; 40 | public bool IsNameValue => true; 41 | public virtual void ToHubSpotDataEntity(ref dynamic converted) 42 | { 43 | converted.Associations = Associations; 44 | } 45 | 46 | public virtual void FromHubSpotDataEntity(dynamic hubspotData) 47 | { 48 | if (hubspotData.associations != null) 49 | { 50 | Associations.AssociatedContacts = ((List)hubspotData.associations.associatedVids).Cast().ToArray(); 51 | Associations.AssociatedCompany = ((List) hubspotData.associations.associatedCompanyIds).Cast().ToArray(); 52 | } 53 | } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/Deal/Dto/DealListHubSpotEntity.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Runtime.Serialization; 3 | using Skarp.HubSpotClient.Deal.Interfaces; 4 | 5 | namespace Skarp.HubSpotClient.Deal.Dto 6 | { 7 | [DataContract] 8 | public class DealListHubSpotEntity : IDealListHubSpotEntity where T : IDealHubSpotEntity 9 | { 10 | /// 11 | /// 12 | /// Gets or sets the deals. 13 | /// 14 | /// 15 | /// The deals. 16 | /// 17 | [DataMember(Name = "deals")] 18 | public IList Deals { get; set; } = new List(); 19 | 20 | /// 21 | /// 22 | /// Gets or sets a value indicating whether more results are available. 23 | /// 24 | /// 25 | /// true if [more results available]; otherwise, false. 26 | /// 27 | /// 28 | /// This is a mapping of the "hasMore" prop in the JSON return data from HubSpot 29 | /// 30 | [DataMember(Name = "hasMore")] 31 | public bool MoreResultsAvailable { get; set; } 32 | 33 | /// 34 | /// 35 | /// Gets or sets the continuation offset. 36 | /// 37 | /// 38 | /// The continuation offset. 39 | /// 40 | /// 41 | /// This is a mapping of the "offset" prop in the JSON return data from HubSpot 42 | /// 43 | [DataMember(Name = "offset")] 44 | public long ContinuationOffset { get; set; } 45 | 46 | public string RouteBasePath => "/deals/v1"; 47 | 48 | public bool IsNameValue => false; 49 | 50 | public List PropertiesToInclude { get; set; } = new List(); 51 | 52 | public virtual void ToHubSpotDataEntity(ref dynamic converted) 53 | { 54 | 55 | } 56 | 57 | public virtual void FromHubSpotDataEntity(dynamic hubspotData) 58 | { 59 | 60 | } 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/Deal/Dto/DealPropertyHubSpotEntity.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.Serialization; 2 | using Skarp.HubSpotClient.Common.Dto.Properties; 3 | using Skarp.HubSpotClient.Deal.Interfaces; 4 | 5 | namespace Skarp.HubSpotClient.Deal.Dto 6 | { 7 | /// 8 | /// Deal Property 9 | /// 10 | /// Documentation 11 | [DataContract] 12 | public class DealPropertyHubSpotEntity : PropertyHubSpotEntity, IDealPropertyHubSpotEntity 13 | { 14 | [DataMember(Name = "displayOrder")] 15 | public long DisplayOrder { get; set; } 16 | 17 | [DataMember(Name = "readOnlyValue")] 18 | public bool ReadOnlyValue { get; set; } 19 | 20 | [DataMember(Name = "readOnlyDefinition")] 21 | public bool ReadOnlyDefinition { get; set; } 22 | 23 | [DataMember(Name = "hidden")] 24 | public bool Hidden { get; set; } 25 | 26 | [DataMember(Name = "mutableDefinitionNotDeletable")] 27 | public bool MutableDefinitionNotDeletable { get; set; } 28 | 29 | [DataMember(Name = "calculated")] 30 | public bool Calculated { get; set; } 31 | 32 | [DataMember(Name = "externalOptions")] 33 | public bool ExternalOptions { get; set; } 34 | 35 | [DataMember(Name = "displayMode")] 36 | public string DisplayMode { get; set; } 37 | 38 | [DataMember(Name = "hubspotDefined")] 39 | public bool? HubSpotDefined { get; set; } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/Deal/Interfaces/IDealHubSpotEntity.cs: -------------------------------------------------------------------------------- 1 | using Skarp.HubSpotClient.Core.Interfaces; 2 | 3 | namespace Skarp.HubSpotClient.Deal.Interfaces 4 | { 5 | public interface IDealHubSpotEntity : IHubSpotEntity 6 | { 7 | long? Id { get; set; } 8 | string Name { get; set; } 9 | string Stage { get; set; } 10 | string Pipeline { get; set; } 11 | long? OwnerId { get; set; } 12 | string CloseDate { get; set; } 13 | decimal Amount { get; set; } 14 | string DealType { get; set; } 15 | string RouteBasePath { get; } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/Deal/Interfaces/IDealListHubSpotEntity.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using Skarp.HubSpotClient.Core.Interfaces; 3 | 4 | namespace Skarp.HubSpotClient.Deal.Interfaces 5 | { 6 | public interface IDealListHubSpotEntity : IHubSpotEntity where T : IDealHubSpotEntity 7 | { 8 | /// 9 | /// Gets or sets the deals. 10 | /// 11 | /// 12 | /// The deals. 13 | /// 14 | IList Deals { get; set; } 15 | 16 | /// 17 | /// Gets or sets a value indicating whether more results are available. 18 | /// 19 | /// 20 | /// This is a mapping of the "hasMore" prop in the JSON return data from HubSpot 21 | /// 22 | /// 23 | /// true if [more results available]; otherwise, false. 24 | /// 25 | bool MoreResultsAvailable { get; set; } 26 | 27 | /// 28 | /// Gets or sets the continuation offset. 29 | /// 30 | /// 31 | /// This is a mapping of the "vid-offset" prop in the JSON reeturn data from HubSpot 32 | /// 33 | /// 34 | /// The continuation offset. 35 | /// 36 | long ContinuationOffset { get; set; } 37 | 38 | string RouteBasePath { get; } 39 | 40 | List PropertiesToInclude { get; set; } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/Deal/Interfaces/IDealPropertyHubSpotEntity.cs: -------------------------------------------------------------------------------- 1 | using Skarp.HubSpotClient.Common.Interfaces; 2 | 3 | namespace Skarp.HubSpotClient.Deal.Interfaces 4 | { 5 | public interface IDealPropertyHubSpotEntity : IPropertyHubSpotEntity 6 | { 7 | long DisplayOrder { get; set; } 8 | 9 | bool ReadOnlyValue { get; set; } 10 | 11 | bool ReadOnlyDefinition { get; set; } 12 | 13 | bool Hidden { get; set; } 14 | 15 | bool MutableDefinitionNotDeletable { get; set; } 16 | 17 | bool Calculated { get; set; } 18 | 19 | bool ExternalOptions { get; set; } 20 | 21 | string DisplayMode { get; set; } 22 | 23 | bool? HubSpotDefined { get; set; } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/Deal/Interfaces/IHubSpotDealClient.cs: -------------------------------------------------------------------------------- 1 | using Skarp.HubSpotClient.Core; 2 | using Skarp.HubSpotClient.Core.Interfaces; 3 | using System.Threading.Tasks; 4 | 5 | namespace Skarp.HubSpotClient.Deal.Interfaces 6 | { 7 | public interface IHubSpotDealClient 8 | { 9 | /// 10 | /// Creates the deal entity asynchronously. 11 | /// 12 | /// The entity. 13 | /// 14 | /// 15 | Task CreateAsync(IDealHubSpotEntity entity) where T : IHubSpotEntity, new(); 16 | /// 17 | /// Delete a deal from hubspot 18 | /// 19 | /// 20 | /// 21 | Task DeleteAsync(long dealId); 22 | /// 23 | /// Return a single deal by id from hubspot 24 | /// 25 | /// 26 | /// 27 | /// 28 | Task GetByIdAsync(long dealId) where T : IHubSpotEntity, new(); 29 | /// 30 | /// List Deals 31 | /// 32 | /// Request options - use for pagination 33 | /// 34 | /// 35 | Task ListAsync(DealListRequestOptions opts = null) where T : IHubSpotEntity, new(); 36 | /// 37 | /// Update an existing deal in hubspot 38 | /// 39 | /// 40 | /// 41 | /// 42 | Task UpdateAsync(IDealHubSpotEntity entity) where T : IHubSpotEntity, new(); 43 | /// 44 | /// List deal properties 45 | /// 46 | /// 47 | /// 48 | Task GetPropertiesAsync() where T : IHubSpotEntity, new(); 49 | } 50 | } -------------------------------------------------------------------------------- /src/HubSpotException.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Net.Http; 4 | using System.Text; 5 | 6 | namespace Skarp.HubSpotClient 7 | { 8 | [Serializable] 9 | public class HubSpotException : Exception 10 | { 11 | public HttpResponseMessage Response { get; } 12 | 13 | public string RawJsonResponse { get; } 14 | public HubSpotException() 15 | { 16 | } 17 | 18 | public HubSpotException(string message) : base(message) 19 | { 20 | } 21 | 22 | public HubSpotException(string message, string jsonResponse) : base(message) 23 | { 24 | RawJsonResponse = jsonResponse; 25 | } 26 | 27 | public HubSpotException(string message, Exception innerException) : base(message, innerException) 28 | { 29 | } 30 | 31 | public HubSpotException(string message, string jsonResponse, HttpResponseMessage response) : this(message, jsonResponse) 32 | { 33 | this.Response = response; 34 | } 35 | 36 | public override String Message 37 | { 38 | get 39 | { 40 | return base.Message + $", JSONResponse={RawJsonResponse??"Empty"}"; 41 | } 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/LineItem/Dto/LineItemHubSpotEntity.cs: -------------------------------------------------------------------------------- 1 | using Skarp.HubSpotClient.LineItem.Interfaces; 2 | using System.Runtime.Serialization; 3 | 4 | namespace Skarp.HubSpotClient.LineItem.Dto 5 | { 6 | [DataContract] 7 | public class LineItemHubSpotEntity : ILineItemHubSpotEntity 8 | { 9 | [DataMember(Name = "objectId")] 10 | [IgnoreDataMember] 11 | public long? Id { get; set; } 12 | [DataMember(Name = "hs_product_id")] 13 | public string ProductId { get; set; } 14 | [DataMember(Name = "quantity")] 15 | public int Quantity { get; set; } 16 | [DataMember(Name = "name")] 17 | public string Name { get; set; } 18 | [DataMember(Name = "price")] 19 | public decimal Price { get; set; } 20 | 21 | public string RouteBasePath => "/crm-objects/v1/objects"; 22 | 23 | public bool IsNameValue => true; 24 | 25 | public virtual void FromHubSpotDataEntity(dynamic hubspotData) 26 | { 27 | } 28 | 29 | public virtual void ToHubSpotDataEntity(ref dynamic dataEntity) 30 | { 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/LineItem/Dto/LineItemListHubSpotEntity.cs: -------------------------------------------------------------------------------- 1 | using Skarp.HubSpotClient.LineItem.Interfaces; 2 | using System.Collections.Generic; 3 | using System.Runtime.Serialization; 4 | 5 | namespace Skarp.HubSpotClient.LineItem.Dto 6 | { 7 | [DataContract] 8 | public class LineItemListHubSpotEntity : ILineItemListHubSpotEntity where T : ILineItemHubSpotEntity 9 | { 10 | /// 11 | /// 12 | /// Gets or sets the line items. 13 | /// 14 | /// 15 | /// The line items. 16 | /// 17 | [DataMember(Name = "objects")] 18 | public IList LineItems { get; set; } = new List(); 19 | 20 | /// 21 | /// 22 | /// Gets or sets a value indicating whether more results are available. 23 | /// 24 | /// 25 | /// true if [more results available]; otherwise, false. 26 | /// 27 | /// 28 | /// This is a mapping of the "hasMore" prop in the JSON return data from HubSpot 29 | /// 30 | [DataMember(Name = "hasMore")] 31 | public bool MoreResultsAvailable { get; set; } 32 | 33 | /// 34 | /// 35 | /// Gets or sets the continuation offset. 36 | /// 37 | /// 38 | /// The continuation offset. 39 | /// 40 | /// 41 | /// This is a mapping of the "offset" prop in the JSON reeturn data from HubSpot 42 | /// 43 | [DataMember(Name = "offset")] 44 | public long ContinuationOffset { get; set; } 45 | 46 | public string RouteBasePath => "/crm-objects/v1/objects"; 47 | 48 | public bool IsNameValue => false; 49 | 50 | public virtual void ToHubSpotDataEntity(ref dynamic converted) 51 | { 52 | 53 | } 54 | 55 | public virtual void FromHubSpotDataEntity(dynamic hubspotData) 56 | { 57 | 58 | } 59 | } 60 | 61 | } 62 | -------------------------------------------------------------------------------- /src/LineItem/Interfaces/IHubSpotLineItemClient.cs: -------------------------------------------------------------------------------- 1 | using Skarp.HubSpotClient.Core.Interfaces; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Threading.Tasks; 5 | 6 | namespace Skarp.HubSpotClient.LineItem.Interfaces 7 | { 8 | public interface IHubSpotLineItemClient 9 | { 10 | /// 11 | /// Creates the line item entity asynchronously. 12 | /// 13 | /// The entity. 14 | /// 15 | /// 16 | Task CreateAsync(ILineItemHubSpotEntity entity) where T : IHubSpotEntity, new(); 17 | /// 18 | /// Creates as group of line items entities asynchronously. 19 | /// 20 | /// The entities. 21 | /// 22 | /// 23 | Task> CreateBatchAsync(IEnumerable entity) where T : IHubSpotEntity, new(); 24 | /// 25 | /// Delete a line item from hubspot 26 | /// 27 | /// 28 | /// 29 | Task DeleteAsync(long lineItemId); 30 | /// 31 | /// Deletes multiple line items from hubspot 32 | /// 33 | /// 34 | /// 35 | Task DeleteBatchAsync(ListOfLineItemIds lineItemIds); 36 | /// 37 | /// Return a single line item by id from hubspot 38 | /// 39 | /// 40 | /// 41 | /// 42 | Task GetByIdAsync(long lineItemId, LineItemGetRequestOptions opts = null) where T : IHubSpotEntity, new(); 43 | /// 44 | /// Lists all line items 45 | /// 46 | /// 47 | /// 48 | Task ListAsync(LineItemListRequestOptions opts = null) where T : IHubSpotEntity, new(); 49 | /// 50 | /// Read a batch of line items from hubspot 51 | /// 52 | /// 53 | /// 54 | /// 55 | Task> ReadBatchAsync(ListOfLineItemIds lineItemIds, LineItemGetRequestOptions opts = null) where T : IHubSpotEntity, new(); 56 | /// 57 | /// Update an existing line item in hubspot 58 | /// 59 | /// 60 | /// 61 | /// 62 | Task UpdateAsync(ILineItemHubSpotEntity entity) where T : IHubSpotEntity, new(); 63 | /// 64 | /// Update multiple existing line items in hubspot 65 | /// 66 | /// 67 | /// 68 | /// 69 | Task> UpdateBatchAsync(IEnumerable entities) where T : IHubSpotEntity, new(); 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /src/LineItem/Interfaces/ILineItemHubSpotEntity.cs: -------------------------------------------------------------------------------- 1 | using Skarp.HubSpotClient.Core.Interfaces; 2 | 3 | namespace Skarp.HubSpotClient.LineItem.Interfaces 4 | { 5 | public interface ILineItemHubSpotEntity : IHubSpotEntity 6 | { 7 | long? Id { get; set; } 8 | string ProductId { get; set; } 9 | int Quantity { get; set; } 10 | string Name { get; set; } 11 | decimal Price { get; set; } 12 | string RouteBasePath { get; } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/LineItem/Interfaces/ILineItemListHubSpotEntity.cs: -------------------------------------------------------------------------------- 1 | using Skarp.HubSpotClient.Core.Interfaces; 2 | using System.Collections.Generic; 3 | 4 | namespace Skarp.HubSpotClient.LineItem.Interfaces 5 | { 6 | public interface ILineItemListHubSpotEntity : IHubSpotEntity where T : ILineItemHubSpotEntity 7 | { 8 | /// 9 | /// Gets or sets the line items. 10 | /// 11 | /// 12 | /// The line items. 13 | /// 14 | IList LineItems { get; set; } 15 | 16 | /// 17 | /// Gets or sets a value indicating whether more results are available. 18 | /// 19 | /// 20 | /// This is a mapping of the "hasMore" prop in the JSON return data from HubSpot 21 | /// 22 | /// 23 | /// true if [more results available]; otherwise, false. 24 | /// 25 | bool MoreResultsAvailable { get; set; } 26 | 27 | /// 28 | /// Gets or sets the continuation offset. 29 | /// 30 | /// 31 | /// This is a mapping of the "offset" prop in the JSON return data from HubSpot 32 | /// 33 | /// 34 | /// The continuation offset. 35 | /// 36 | long ContinuationOffset { get; set; } 37 | 38 | string RouteBasePath { get; } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/LineItem/Interfaces/LineItemListRequestOptions.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace Skarp.HubSpotClient.LineItem 4 | { 5 | public class LineItemListRequestOptions 6 | { 7 | /// 8 | /// Get or set the continuation offset when calling list many times to enumerate all your line items. 9 | /// The API will return up to 100 results per page. 10 | /// 11 | /// 12 | /// The return DTO from List contains the current "offset" that you can inject into your next list call 13 | /// to continue the listing process 14 | /// 15 | public long? Offset { get; set; } = null; 16 | public List PropertiesToInclude { get; set; } = new List(); 17 | } 18 | } -------------------------------------------------------------------------------- /src/LineItem/Interfaces/LineItemRequestOptions.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace Skarp.HubSpotClient.LineItem 4 | { 5 | public class LineItemGetRequestOptions 6 | { 7 | public List PropertiesToInclude { get; set; } = new List(); 8 | public List PropertiesWithHistoryToInclude { get; set; } = new List(); 9 | public bool IncludeDeletes { get; set; } 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/LineItem/Interfaces/ListOfLineItemIds.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Runtime.Serialization; 3 | 4 | namespace Skarp.HubSpotClient.LineItem.Interfaces 5 | { 6 | public class ListOfLineItemIds 7 | { 8 | [DataMember(Name = "ids")] 9 | public IList Ids { get; set; } = new List(); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/ListOfContacts/Dto/ContactListFilter.cs: -------------------------------------------------------------------------------- 1 | using Skarp.HubSpotClient.ListOfContacts.Interfaces; 2 | using System.Runtime.Serialization; 3 | 4 | namespace Skarp.HubSpotClient.ListOfContacts.Dto 5 | { 6 | 7 | [DataContract(Name = "filter")] 8 | public class ContactListFilter : IContactListFilter 9 | { 10 | [DataMember(Name = "type")] 11 | public string Type { get; set; } 12 | [DataMember(Name = "property")] 13 | public string Property { get; set; } 14 | [DataMember(Name = "value")] 15 | public string Value { get; set; } 16 | [DataMember(Name = "operator")] 17 | public string op { get; set; } 18 | } 19 | 20 | } 21 | -------------------------------------------------------------------------------- /src/ListOfContacts/Dto/ContactListMetaData.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.Serialization; 2 | 3 | namespace Skarp.HubSpotClient.ListOfContacts.Dto 4 | { 5 | [DataContract(Name = "MetaData")] 6 | public class ContactListMetaData 7 | { 8 | [DataMember(Name = "processing")] 9 | public string Processing { get; set; } 10 | [DataMember(Name = "size")] 11 | public int Size { get; set; } 12 | [DataMember(Name = "error")] 13 | public string Error { get; set; } 14 | [DataMember(Name = "lastProcessingStateChangeAt")] 15 | public long LastProcessingStateChangeAtTimeStamp { get; set; } 16 | [DataMember(Name = "lastSizeChangeAt")] 17 | public long LastSizeChangeAtTimeStamp { get; set; } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/ListOfContacts/Dto/CreateContactListRequestHubSpotEntity.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | using Skarp.HubSpotClient.Core.Interfaces; 3 | using Skarp.HubSpotClient.ListOfContacts.Interfaces; 4 | using System; 5 | using System.Collections.Generic; 6 | using System.Runtime.Serialization; 7 | using System.Text; 8 | 9 | namespace Skarp.HubSpotClient.ListOfContacts.Dto 10 | { 11 | [DataContract] 12 | public class CreateContactListRequestHubSpotEntity : ICreateContactListRequestHubSpotEntity 13 | { 14 | [DataMember(Name = "name")] 15 | public string Name { get; set; } 16 | [DataMember(Name = "dynamic")] 17 | public bool? Dynamic { get; set; } 18 | [DataMember(Name = "portalId")] 19 | public int? PortalId { get; set; } 20 | [DataMember(Name = "filters")] 21 | public List> Filters { get; set; } 22 | 23 | public int offset { get; set; } 24 | 25 | [DataMember(Name = "has-more")] 26 | public bool HasMore { get; set; } 27 | 28 | public bool IsNameValue => false; 29 | 30 | public virtual void ToHubSpotDataEntity(ref dynamic dataEntity) 31 | { 32 | 33 | } 34 | 35 | public virtual void FromHubSpotDataEntity(dynamic hubspotData) 36 | { 37 | 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/ListOfContacts/Dto/CreateContactListResponseHubSpotEntity.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | using Skarp.HubSpotClient.Core.Interfaces; 3 | using Skarp.HubSpotClient.ListOfContacts.Interfaces; 4 | using System; 5 | using System.Collections.Generic; 6 | using System.Runtime.Serialization; 7 | using System.Text; 8 | 9 | namespace Skarp.HubSpotClient.ListOfContacts.Dto 10 | { 11 | [DataContract] 12 | public class CreateContactListResponseHubSpotEntity: IHubSpotEntity 13 | { 14 | [DataMember(Name = "name")] 15 | public string Name { get; set; } 16 | [DataMember(Name = "internalListId")] 17 | public int InternalListId { get; set; } 18 | [DataMember(Name = "listId")] 19 | public int ListId { get; set; } 20 | [DataMember(Name = "deleted")] 21 | public bool Deleted { get; set; } 22 | [DataMember(Name = "dynamic")] 23 | public bool Dynamic { get; set; } 24 | [DataMember(Name = "portalId")] 25 | public int PortalId { get; set; } 26 | [DataMember(Name = "createdAt")] 27 | public string CreatedAtTimeStamp { get; set; } 28 | [DataMember(Name = "updatedAt")] 29 | public string UpdatedAtTimeStamp { get; set; } 30 | [DataMember(Name = "metaData")] 31 | public ContactListMetaData MetaData { get; set; } 32 | [DataMember(Name = "filters")] 33 | public List> Filters { get; set; } 34 | [DataMember(Name = "listType")] 35 | public string ListType { get; set; } 36 | [DataMember(Name = "archived")] 37 | public bool Archived { get; set; } 38 | 39 | public int offset { get; set; } 40 | 41 | [DataMember(Name = "has-more")] 42 | public bool HasMore { get; set; } 43 | 44 | public bool IsNameValue => false; 45 | 46 | public virtual void ToHubSpotDataEntity(ref dynamic dataEntity) 47 | { 48 | 49 | } 50 | 51 | public virtual void FromHubSpotDataEntity(dynamic hubspotData) 52 | { 53 | 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/ListOfContacts/Dto/HubSpotListOfContactsEntity.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Runtime.Serialization; 3 | using Skarp.HubSpotClient.Contact.Interfaces; 4 | using Skarp.HubSpotClient.ListOfContacts.Interfaces; 5 | 6 | namespace Skarp.HubSpotClient.ListOfContacts.Dto 7 | { 8 | [DataContract] 9 | public class HubSpotListOfContactsEntity : IHubSpotListOfContactsEntity 10 | { 11 | 12 | public string RouteBasePath => "/contacts/v1"; 13 | 14 | public bool IsNameValue => false; 15 | 16 | [DataMember(Name = "vids")] 17 | public IList Vids { get; set; } = new List(); 18 | 19 | public virtual void ToHubSpotDataEntity(ref dynamic converted) 20 | { 21 | 22 | } 23 | 24 | public virtual void FromHubSpotDataEntity(dynamic hubspotData) 25 | { 26 | 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/ListOfContacts/Dto/ListOfContactListsHubSpotEntity.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | using Skarp.HubSpotClient.Core.Interfaces; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Runtime.Serialization; 6 | using System.Text; 7 | 8 | namespace Skarp.HubSpotClient.ListOfContacts.Dto 9 | { 10 | public class ListOfContactListsHubSpotEntity: IHubSpotEntity 11 | { 12 | [DataContract(Name="MetaData")] 13 | public class ContactListsMetaData 14 | { 15 | [DataMember(Name="processing")] 16 | public string Processing { get; set; } 17 | [DataMember(Name="size")] 18 | public int Size { get; set; } 19 | [DataMember(Name="error")] 20 | public string Error { get; set; } 21 | [DataMember(Name="lastProcessingStateChangeAt")] 22 | public long LastProcessingStateChangeAtTimeStamp { get; set; } 23 | [DataMember(Name="lastSizeChangeAt")] 24 | public long LastSizeChangeAtTimeStamp { get; set; } 25 | } 26 | 27 | [DataContract(Name="List")] 28 | public class ContactListsItem 29 | { 30 | [DataMember(Name="dynamic")] 31 | public bool Dynamic { get; set; } 32 | [DataMember(Name="metaData")] 33 | public ContactListsMetaData MetaData { get; set; } 34 | [DataMember(Name="name")] 35 | public string Name { get; set; } 36 | [DataMember(Name="filters")] 37 | public List> Filters { get; set; } 38 | [DataMember(Name="portalId")] 39 | public int PortalId { get; set; } 40 | [DataMember(Name="createdAt")] 41 | public long CreatedAtTimeStamp { get; set; } 42 | [DataMember(Name="listId")] 43 | public int ListId { get; set; } 44 | [DataMember(Name="updatedAt")] 45 | public long UpdatedAtTimeStamp { get; set; } 46 | [DataMember(Name="listType")] 47 | public string ListType { get; set; } 48 | [DataMember(Name="internalListId")] 49 | public int InternalListId { get; set; } 50 | [DataMember(Name="deleteable")] 51 | public bool Deleteable { get; set; } 52 | } 53 | 54 | [DataContract(Name="filter")] 55 | public class ContactListsFilter 56 | { 57 | [DataMember(Name="filterFamily")] 58 | public string FilterFamily { get; set; } 59 | [DataMember(Name="withinTimeMode")] 60 | public string WithinTimeMode { get; set; } 61 | [DataMember(Name="checkPastVersions")] 62 | public bool CheckPastVersions { get; set; } 63 | [DataMember(Name="type")] 64 | public string Type { get; set; } 65 | [DataMember(Name="property")] 66 | public string Property { get; set; } 67 | [DataMember(Name="value")] 68 | public string Value { get; set; } 69 | [DataMember(Name = "operator")] 70 | public string op { get; set; } 71 | } 72 | 73 | 74 | public List lists { get; set; } 75 | public int offset { get; set; } 76 | 77 | [DataMember(Name = "has-more")] 78 | public bool HasMore { get; set; } 79 | 80 | public bool IsNameValue => false; 81 | 82 | public virtual void ToHubSpotDataEntity(ref dynamic dataEntity) 83 | { 84 | 85 | } 86 | 87 | public virtual void FromHubSpotDataEntity(dynamic hubspotData) 88 | { 89 | 90 | } 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /src/ListOfContacts/Dto/ListOfContactsHubSpotEntity.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Runtime.Serialization; 3 | using Skarp.HubSpotClient.Contact.Interfaces; 4 | using Skarp.HubSpotClient.ListOfContacts.Interfaces; 5 | 6 | namespace Skarp.HubSpotClient.ListOfContacts.Dto 7 | { 8 | [DataContract] 9 | public class ListOfContactsHubSpotEntity : IListOfContactsHubSpotEntity where T : IContactHubSpotEntity 10 | { 11 | /// 12 | /// 13 | /// Gets or sets the contacts. 14 | /// 15 | /// 16 | /// The contacts. 17 | /// 18 | [DataMember(Name = "contacts")] 19 | public IList Contacts { get; set; } = new List(); 20 | 21 | /// 22 | /// 23 | /// Gets or sets a value indicating whether more results are available. 24 | /// 25 | /// 26 | /// true if [more results available]; otherwise, false. 27 | /// 28 | /// 29 | /// This is a mapping of the "has-more" prop in the JSON return data from HubSpot 30 | /// 31 | [DataMember(Name = "has-more")] 32 | public bool MoreResultsAvailable { get; set; } 33 | 34 | /// 35 | /// 36 | /// Gets or sets the continuation offset. 37 | /// 38 | /// 39 | /// The continuation offset. 40 | /// 41 | /// 42 | /// This is a mapping of the "vid-offset" prop in the JSON reeturn data from HubSpot 43 | /// 44 | [DataMember(Name = "vid-offset")] 45 | public long ContinuationOffset { get; set; } 46 | 47 | public string RouteBasePath => "/contacts/v1"; 48 | 49 | public bool IsNameValue => false; 50 | public virtual void ToHubSpotDataEntity(ref dynamic converted) 51 | { 52 | 53 | } 54 | 55 | public virtual void FromHubSpotDataEntity(dynamic hubspotData) 56 | { 57 | 58 | } 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/ListOfContacts/Interfaces/IContactListFilter.cs: -------------------------------------------------------------------------------- 1 | namespace Skarp.HubSpotClient.ListOfContacts.Interfaces 2 | { 3 | public interface IContactListFilter 4 | { 5 | string op { get; set; } 6 | string Property { get; set; } 7 | string Type { get; set; } 8 | string Value { get; set; } 9 | } 10 | } -------------------------------------------------------------------------------- /src/ListOfContacts/Interfaces/ICreateContactListRequestHubSpotEntity.cs: -------------------------------------------------------------------------------- 1 | using Skarp.HubSpotClient.Core.Interfaces; 2 | using System.Collections.Generic; 3 | 4 | namespace Skarp.HubSpotClient.ListOfContacts.Interfaces 5 | { 6 | public interface ICreateContactListRequestHubSpotEntity : IHubSpotEntity 7 | { 8 | bool? Dynamic { get; set; } 9 | List> Filters { get; set; } 10 | bool HasMore { get; set; } 11 | string Name { get; set; } 12 | int offset { get; set; } 13 | int? PortalId { get; set; } 14 | 15 | } 16 | } -------------------------------------------------------------------------------- /src/ListOfContacts/Interfaces/IHubSpotListOfContactsClient.cs: -------------------------------------------------------------------------------- 1 | using Skarp.HubSpotClient.ListOfContacts.Dto; 2 | using System.Threading.Tasks; 3 | 4 | namespace Skarp.HubSpotClient.ListOfContacts.Interfaces 5 | { 6 | public interface IHubSpotListOfContactsClient 7 | { 8 | /// 9 | /// Return a list of contacts for a contact list by id from hubspot 10 | /// 11 | /// 12 | /// 13 | Task GetListByIdAsync(long listId, ListOfContactsRequestOptions opts = null); 14 | /// 15 | /// Add list of contacts based on list id 16 | /// 17 | /// 18 | /// 19 | Task AddBatchAsync(HubSpotListOfContactsEntity contacts, long listId); 20 | /// 21 | /// Remove list of contacts based on list id 22 | /// 23 | /// 24 | /// 25 | Task RemoveBatchAsync(HubSpotListOfContactsEntity contacts, long listId); 26 | } 27 | } -------------------------------------------------------------------------------- /src/ListOfContacts/Interfaces/IHubSpotListOfContactsEntity.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using Skarp.HubSpotClient.Contact.Interfaces; 3 | using Skarp.HubSpotClient.Core.Interfaces; 4 | 5 | namespace Skarp.HubSpotClient.ListOfContacts.Interfaces 6 | { 7 | public interface IHubSpotListOfContactsEntity 8 | { 9 | /// 10 | /// Gets or sets the contact vids. 11 | /// 12 | /// 13 | /// The contact vids. 14 | /// 15 | IList Vids { get; set; } 16 | } 17 | } -------------------------------------------------------------------------------- /src/ListOfContacts/Interfaces/IListOfContactsHubSpotEntity.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using Skarp.HubSpotClient.Contact.Interfaces; 3 | using Skarp.HubSpotClient.Core.Interfaces; 4 | 5 | namespace Skarp.HubSpotClient.ListOfContacts.Interfaces 6 | { 7 | public interface IListOfContactsHubSpotEntity : IHubSpotEntity where T : IContactHubSpotEntity 8 | { 9 | /// 10 | /// Gets or sets the contacts. 11 | /// 12 | /// 13 | /// The contacts. 14 | /// 15 | IList Contacts { get; set; } 16 | 17 | /// 18 | /// Gets or sets a value indicating whether more results are available. 19 | /// 20 | /// 21 | /// This is a mapping of the "has-more" prop in the JSON return data from HubSpot 22 | /// 23 | /// 24 | /// true if [more results available]; otherwise, false. 25 | /// 26 | bool MoreResultsAvailable { get; set; } 27 | 28 | /// 29 | /// Gets or sets the continuation offset. 30 | /// 31 | /// 32 | /// This is a mapping of the "vid-offset" prop in the JSON reeturn data from HubSpot 33 | /// 34 | /// 35 | /// The continuation offset. 36 | /// 37 | long ContinuationOffset { get; set; } 38 | 39 | string RouteBasePath { get; } 40 | } 41 | } -------------------------------------------------------------------------------- /src/ListOfContacts/ListOfContactListsRequestOptions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Skarp.HubSpotClient.ListOfContacts 4 | { 5 | public class ListOfContactListsRequestOptions 6 | { 7 | private int _numberOfContactListsToReturn = 100; 8 | 9 | /// 10 | /// Gets or sets the number of contact lists to return. 11 | /// 12 | /// 13 | /// Defaults to 20 which is also the hubspot api default. Max value is 100 14 | /// 15 | /// 16 | /// The number of contacts to return. 17 | /// 18 | public int NumberOfContactListsToReturn 19 | { 20 | get => _numberOfContactListsToReturn; 21 | set 22 | { 23 | if (value < 1 || value > 250) 24 | { 25 | throw new ArgumentException( 26 | $"Number of contacts to return must be a positive ingeteger greater than 0 and less than 251 - you provided {value}"); 27 | } 28 | _numberOfContactListsToReturn = value; 29 | } 30 | } 31 | 32 | /// 33 | /// Get or set the continuation offset when calling list many times to enumerate all your contact lists 34 | /// 35 | /// 36 | /// The return DTO from List contains the current "offset" that you can inject into your next list call 37 | /// to continue the listing process 38 | /// 39 | public long? ContactListOffset { get; set; } = null; 40 | } 41 | } -------------------------------------------------------------------------------- /src/ListOfContacts/ListOfContactsRequestOptions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace Skarp.HubSpotClient.ListOfContacts 6 | { 7 | public class ListOfContactsRequestOptions 8 | { 9 | private int _numberOfContactsToReturn = 100; 10 | 11 | /// 12 | /// Gets or sets the number of contacts to return. 13 | /// 14 | /// 15 | /// Defaults to 20 which is also the hubspot api default. Max value is 100 16 | /// 17 | /// 18 | /// The number of contacts to return. 19 | /// 20 | public int NumberOfContactsToReturn 21 | { 22 | get => _numberOfContactsToReturn; 23 | set 24 | { 25 | if (value < 1 || value > 250) 26 | { 27 | throw new ArgumentException( 28 | $"Number of contacts to return must be a positive ingeteger greater than 0 and less than 251 - you provided {value}"); 29 | } 30 | _numberOfContactsToReturn = value; 31 | } 32 | } 33 | 34 | /// 35 | /// Get or set the continuation offset when calling list many times to enumerate all your contacts 36 | /// 37 | /// 38 | /// The return DTO from List contains the current "offset" that you can inject into your next list call 39 | /// to continue the listing process 40 | /// 41 | public long? ContactOffset { get; set; } = null; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/Owner/Dto/OwnerHubSpotEntity.cs: -------------------------------------------------------------------------------- 1 | using Skarp.HubSpotClient.Owner.Interfaces; 2 | using System.Runtime.Serialization; 3 | 4 | namespace Skarp.HubSpotClient.Owner.Dto 5 | { 6 | [DataContract] 7 | public class OwnerHubSpotEntity : IOwnerHubSpotEntity 8 | { 9 | [DataMember(Name = "ownerId")] 10 | public long Id { get; set; } 11 | [DataMember(Name = "portalId")] 12 | public long PortalId { get; set; } 13 | [DataMember(Name = "firstName")] 14 | public string FirstName { get; set; } 15 | [DataMember(Name = "lastName")] 16 | public string LastName { get; set; } 17 | [DataMember(Name = "email")] 18 | public string Email { get; set; } 19 | 20 | public string RouteBasePath => "/owners/v2"; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/Owner/Interfaces/IHubSpotOwnerClient.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Threading.Tasks; 3 | 4 | namespace Skarp.HubSpotClient.Owner.Interfaces 5 | { 6 | public interface IHubSpotOwnerClient 7 | { 8 | /// 9 | /// Return a single Owner by id from hubspot 10 | /// 11 | /// 12 | /// 13 | /// 14 | Task GetByIdAsync(long ownerId) where T : IOwnerHubSpotEntity, new(); 15 | /// 16 | /// Return a single Owner by id from hubspot 17 | /// 18 | /// 19 | /// 20 | /// 21 | Task GetByIdAsync(string ownerId) where T : IOwnerHubSpotEntity, new(); 22 | /// 23 | /// List Owners 24 | /// 25 | /// Request options - use for filtering 26 | /// 27 | /// 28 | Task> ListAsync(OwnerListRequestOptions opts = null) where T : IOwnerHubSpotEntity, new(); 29 | } 30 | } -------------------------------------------------------------------------------- /src/Owner/Interfaces/IOwnerHubSpotEntity.cs: -------------------------------------------------------------------------------- 1 | namespace Skarp.HubSpotClient.Owner.Interfaces 2 | { 3 | // Not using IHubSpotEntity because the api does not map to and from with property values. Owner is a simple object structure. 4 | public interface IOwnerHubSpotEntity 5 | { 6 | long Id { get; set; } 7 | long PortalId { get; set; } 8 | string FirstName { get; set; } 9 | string LastName { get; set; } 10 | string Email { get; set; } 11 | string RouteBasePath { get; } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/Owner/OwnerListRequestOptions.cs: -------------------------------------------------------------------------------- 1 | namespace Skarp.HubSpotClient.Owner 2 | { 3 | public class OwnerListRequestOptions 4 | { 5 | public bool IncludeInactive { get; set; } 6 | 7 | public string Email { get; set; } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.CompilerServices; 2 | 3 | [assembly: InternalsVisibleTo("Skarp.HubSpotClient.FunctionalTest")] 4 | [assembly: InternalsVisibleTo("Skarp.HubSpotClient.UnitTest")] -------------------------------------------------------------------------------- /src/hubspot-client.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | netstandard2.0;net461;net5.0;net6.0 4 | 0.22.0 5 | Skarp.HubSpotClient 6 | Skarp.HubSpotClient 7 | HubSpotClient 8 | nover 9 | A dotnet (core) HubSpot rest api client with support for custom property mapping 10 | hubspot;hubspot client; 11 | https://github.com/skarpdev/dotnetcore-hubspot-client/ 12 | https://raw.githubusercontent.com/skarpdev/dotnetcore-hubspot-client/master/LICENSE 13 | false 14 | git 15 | https://github.com/skarpdev/dotnetcore-hubspot-client/ 16 | HubSpotClient 17 | SKARP ApS 18 | 19 | 20 | true 21 | 22 | 23 | true 24 | 25 | 26 | embedded 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | <_Parameter1>$(AssemblyName).UnitTest 41 | 42 | 43 | 44 | 45 | true 46 | 47 | -------------------------------------------------------------------------------- /test/functional/Deal/HubSpotDealClientFunctionalTest.cs: -------------------------------------------------------------------------------- 1 | using System.Threading.Tasks; 2 | using Microsoft.Extensions.Logging; 3 | using RapidCore.Network; 4 | using Skarp.HubSpotClient.Deal; 5 | using Skarp.HubSpotClient.Deal.Dto; 6 | using Skarp.HubSpotClient.Core.Requests; 7 | using Xunit; 8 | using Xunit.Abstractions; 9 | using Skarp.HubSpotClient.FunctionalTests.Mocks.Deal; 10 | 11 | namespace Skarp.HubSpotClient.FunctionalTests.Deal 12 | { 13 | public class HubSpotDealClientFunctionalTest : FunctionalTestBase 14 | { 15 | private readonly HubSpotDealClient _client; 16 | 17 | public HubSpotDealClientFunctionalTest(ITestOutputHelper output) 18 | : base(output) 19 | { 20 | var mockHttpClient = new MockRapidHttpClient() 21 | .AddTestCase(new CreateDealMockTestCase()) 22 | .AddTestCase(new GetDealMockTestCase()) 23 | .AddTestCase(new GetDealByIdNotFoundMockTestCase()) 24 | .AddTestCase(new UpdateDealMockTestCase()) 25 | .AddTestCase(new DeleteDealMockTestCase()); 26 | 27 | _client = new HubSpotDealClient( 28 | mockHttpClient, 29 | Logger, 30 | new RequestSerializer(new RequestDataConverter(LoggerFactory.CreateLogger())), 31 | "https://api.hubapi.com/", 32 | "HapiKeyFisk" 33 | ); 34 | } 35 | 36 | [Fact] 37 | public async Task DealClient_can_create_Deals() 38 | { 39 | var data = await _client.CreateAsync(new DealHubSpotEntity 40 | { 41 | Name = "A new deal", 42 | Pipeline = "default", 43 | Amount = 60000, 44 | DealType = "newbusiness" 45 | }); 46 | 47 | Assert.NotNull(data); 48 | 49 | // Should have replied with mocked data, so it does not really correspond to our input data, but it proves the "flow" 50 | Assert.Equal(151088, data.Id); 51 | } 52 | 53 | [Fact] 54 | public async Task DealClient_can_get_Deal() 55 | { 56 | const int dealId = 151088; 57 | var data = await _client.GetByIdAsync(dealId); 58 | 59 | Assert.NotNull(data); 60 | Assert.Equal("This is a Deal", data.Name); 61 | Assert.Equal(560, data.Amount); 62 | Assert.Equal(dealId, data.Id); 63 | } 64 | 65 | 66 | [Fact] 67 | public async Task DealClient_returns_null_when_Deal_not_found() 68 | { 69 | const int dealId = 158; 70 | var data = await _client.GetByIdAsync(dealId); 71 | 72 | Assert.Null(data); 73 | } 74 | 75 | [Fact] 76 | public async Task DealClient_update_Deal_works() 77 | { 78 | var data = await _client.UpdateAsync(new DealHubSpotEntity 79 | { 80 | Id = 151088, 81 | Name = "This is an updated deal", 82 | Amount = 560 83 | } 84 | ); 85 | 86 | Assert.NotNull(data); 87 | 88 | // Should have replied with mocked data, so it does not really correspond to our input data, but it proves the "flow" 89 | Assert.Equal(560, data.Amount); 90 | Assert.Equal(151088, data.Id); 91 | } 92 | 93 | [Fact] 94 | public async Task DealClient_delete_Deal_works() 95 | { 96 | await _client.DeleteAsync(151088); 97 | } 98 | } 99 | } -------------------------------------------------------------------------------- /test/functional/FunctionalTestBase.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | using Microsoft.Extensions.Logging; 5 | using RapidCore.Xunit.Logging; 6 | using Xunit.Abstractions; 7 | 8 | namespace Skarp.HubSpotClient.FunctionalTests 9 | { 10 | public abstract class FunctionalTestBase 11 | { 12 | protected readonly ITestOutputHelper Output; 13 | protected readonly LoggerFactory LoggerFactory; 14 | protected readonly ILogger Logger; 15 | 16 | protected FunctionalTestBase(ITestOutputHelper output) 17 | { 18 | Output = output; 19 | LoggerFactory = new LoggerFactory(); 20 | LoggerFactory.AddXunitOutput(output); 21 | 22 | Logger = LoggerFactory.CreateLogger(); 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /test/functional/Mocks/Association/CreateAssociationMockTestCase.cs: -------------------------------------------------------------------------------- 1 | using RapidCore.Network; 2 | using Skarp.HubSpotClient.Core; 3 | using System.Net; 4 | using System.Net.Http; 5 | using System.Threading.Tasks; 6 | 7 | namespace Skarp.HubSpotClient.FunctionalTests.Mocks.Association 8 | { 9 | public class CreateAssociationMockTestCase : IMockRapidHttpClientTestCase 10 | { 11 | public bool IsMatch(HttpRequestMessage request) 12 | { 13 | return request.RequestUri.AbsolutePath.Contains("/crm-associations/v1/associations") && request.Method == HttpMethod.Put; 14 | } 15 | public Task GetResponseAsync(HttpRequestMessage request) 16 | { 17 | var response = new HttpResponseMessage(HttpStatusCode.NoContent); 18 | 19 | response.RequestMessage = request; 20 | 21 | return Task.FromResult(response); 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /test/functional/Mocks/Association/CreateBatchAssociationMockTestCase.cs: -------------------------------------------------------------------------------- 1 | using RapidCore.Network; 2 | using Skarp.HubSpotClient.Core; 3 | using System.Net; 4 | using System.Net.Http; 5 | using System.Threading.Tasks; 6 | 7 | namespace Skarp.HubSpotClient.FunctionalTests.Mocks.Association 8 | { 9 | public class CreateBatchAssociationMockTestCase : IMockRapidHttpClientTestCase 10 | { 11 | public bool IsMatch(HttpRequestMessage request) 12 | { 13 | return request.RequestUri.AbsolutePath.Contains("/crm-associations/v1/associations/create-batch") && request.Method == HttpMethod.Put; 14 | } 15 | public Task GetResponseAsync(HttpRequestMessage request) 16 | { 17 | var response = new HttpResponseMessage(HttpStatusCode.NoContent); 18 | 19 | response.RequestMessage = request; 20 | 21 | return Task.FromResult(response); 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /test/functional/Mocks/Association/CreateBatchAssociationMockTestFailCase.cs: -------------------------------------------------------------------------------- 1 | using RapidCore.Network; 2 | using Skarp.HubSpotClient.Core; 3 | using System.Net; 4 | using System.Net.Http; 5 | using System.Threading.Tasks; 6 | 7 | namespace Skarp.HubSpotClient.FunctionalTests.Mocks.Association 8 | { 9 | public class CreateBatchAssociationMockFailTestCase : IMockRapidHttpClientTestCase 10 | { 11 | public bool IsMatch(HttpRequestMessage request) 12 | { 13 | return request.RequestUri.AbsolutePath.Contains("/crm-associations/v1/associations/create-batch") && request.Method == HttpMethod.Put; 14 | } 15 | public Task GetResponseAsync(HttpRequestMessage request) 16 | { 17 | var response = new HttpResponseMessage(HttpStatusCode.BadRequest); 18 | 19 | const string jsonResponse = "{" + 20 | "\"status\": \"error\"," + 21 | "\"message\": \"One or more associations are invalid\"," + 22 | "\"errors\": [" + 23 | "\"CONTACT=1 is not valid\"" + 24 | "]" + 25 | "}"; 26 | 27 | response.Content = new JsonContent(jsonResponse); 28 | response.RequestMessage = request; 29 | 30 | return Task.FromResult(response); 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /test/functional/Mocks/Association/DeleteAssociationMockTestCase.cs: -------------------------------------------------------------------------------- 1 | using RapidCore.Network; 2 | using Skarp.HubSpotClient.Core; 3 | using System.Net; 4 | using System.Net.Http; 5 | using System.Threading.Tasks; 6 | 7 | namespace Skarp.HubSpotClient.FunctionalTests.Mocks.Association 8 | { 9 | public class DeleteAssociationMockTestCase : IMockRapidHttpClientTestCase 10 | { 11 | public bool IsMatch(HttpRequestMessage request) 12 | { 13 | return request.RequestUri.AbsolutePath.Contains("/crm-associations/v1/associations/delete") && request.Method == HttpMethod.Put; 14 | } 15 | public Task GetResponseAsync(HttpRequestMessage request) 16 | { 17 | var response = new HttpResponseMessage(HttpStatusCode.NoContent); 18 | 19 | response.RequestMessage = request; 20 | 21 | return Task.FromResult(response); 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /test/functional/Mocks/Association/DeleteBatchAssociationMockTestCase.cs: -------------------------------------------------------------------------------- 1 | using RapidCore.Network; 2 | using Skarp.HubSpotClient.Core; 3 | using System.Net; 4 | using System.Net.Http; 5 | using System.Threading.Tasks; 6 | 7 | namespace Skarp.HubSpotClient.FunctionalTests.Mocks.Association 8 | { 9 | public class DeleteBatchAssociationMockTestCase : IMockRapidHttpClientTestCase 10 | { 11 | public bool IsMatch(HttpRequestMessage request) 12 | { 13 | return request.RequestUri.AbsolutePath.Contains("/crm-associations/v1/associations/create-batch") && request.Method == HttpMethod.Put; 14 | } 15 | public Task GetResponseAsync(HttpRequestMessage request) 16 | { 17 | var response = new HttpResponseMessage(HttpStatusCode.NoContent); 18 | 19 | response.RequestMessage = request; 20 | 21 | return Task.FromResult(response); 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /test/functional/Mocks/Association/ListAssociationMockTestCase.cs: -------------------------------------------------------------------------------- 1 | using System.Net; 2 | using System.Net.Http; 3 | using System.Threading.Tasks; 4 | using RapidCore.Network; 5 | using Skarp.HubSpotClient.Core; 6 | 7 | namespace Skarp.HubSpotClient.FunctionalTests.Mocks.Association 8 | { 9 | public class ListAssociationMockTestCase : IMockRapidHttpClientTestCase 10 | { 11 | public bool IsMatch(HttpRequestMessage request) 12 | { 13 | return request.RequestUri.AbsolutePath.Contains("/crm-associations/v1/associations/10444744/HUBSPOT_DEFINED/2") && request.Method == HttpMethod.Get; 14 | } 15 | 16 | public Task GetResponseAsync(HttpRequestMessage request) 17 | { 18 | var response = new HttpResponseMessage(HttpStatusCode.OK); 19 | 20 | const string jsonResponse = 21 | "{\"results\":[" + 22 | "259674," + 23 | "259727" + 24 | "],\"hasMore\":true,\"offset\":259727}"; 25 | response.Content = new JsonContent(jsonResponse); 26 | response.RequestMessage = request; 27 | 28 | return Task.FromResult(response); 29 | } 30 | } 31 | } -------------------------------------------------------------------------------- /test/functional/Mocks/Company/CreateCompanyMockTestCase.cs: -------------------------------------------------------------------------------- 1 | using System.Net; 2 | using System.Net.Http; 3 | using System.Threading.Tasks; 4 | using RapidCore.Network; 5 | using Skarp.HubSpotClient.Core; 6 | 7 | namespace Skarp.HubSpotClient.FunctionalTests.Mocks.Company 8 | { 9 | public class CreateCompanyMockTestCase : IMockRapidHttpClientTestCase 10 | { 11 | public bool IsMatch(HttpRequestMessage request) 12 | { 13 | return request.RequestUri.AbsolutePath.EndsWith("/companies/v2/companies"); 14 | } 15 | 16 | public Task GetResponseAsync(HttpRequestMessage request) 17 | { 18 | var response = new HttpResponseMessage(HttpStatusCode.OK); 19 | 20 | const string jsonResponse = "{'portalId': 62515,'companyId': 10444744,'isDeleted': false,'properties': {'description': {'value': 'A full description','timestamp': 1403218621658,'source': 'API','sourceId': null,'versions': [{'name': 'description','value': 'A full description','timestamp': 1403218621658,'source': 'API', 'sourceVid': []}]},'name': {'value': 'A new company','timestamp': 1403217668394,'source': 'API','sourceId': null,'versions': [{'name': 'name','value': 'A new company','timestamp': 1403217668394,'source': 'API','sourceVid': []}]},'createdate': {'value': '1403217668394','timestamp': 1403217668394,'source': 'API','sourceId': null,'versions': [{'name': 'createdate','value': '1403217668394','timestamp': 1403217668394,'source': 'API','sourceVid': []}]}}}"; 21 | response.Content = new JsonContent(jsonResponse); 22 | response.RequestMessage = request; 23 | 24 | return Task.FromResult(response); 25 | } 26 | } 27 | } -------------------------------------------------------------------------------- /test/functional/Mocks/Company/DeleteCompanyMockTestCase.cs: -------------------------------------------------------------------------------- 1 | using System.Net; 2 | using System.Net.Http; 3 | using System.Threading.Tasks; 4 | using RapidCore.Network; 5 | using Skarp.HubSpotClient.Core; 6 | 7 | namespace Skarp.HubSpotClient.FunctionalTests.Mocks.Company 8 | { 9 | public class DeleteCompanyMockTestCase : IMockRapidHttpClientTestCase 10 | { 11 | public bool IsMatch(HttpRequestMessage request) 12 | { 13 | return request.RequestUri.AbsolutePath.Contains("/companies/v2/companies/10444744") && request.Method == HttpMethod.Delete; 14 | } 15 | 16 | public Task GetResponseAsync(HttpRequestMessage request) 17 | { 18 | const string jsonResponse = ""; 19 | 20 | var response = new HttpResponseMessage(HttpStatusCode.OK) 21 | { 22 | Content = new JsonContent(jsonResponse), 23 | StatusCode = HttpStatusCode.NoContent, 24 | RequestMessage = request 25 | }; 26 | 27 | return Task.FromResult(response); 28 | } 29 | } 30 | } -------------------------------------------------------------------------------- /test/functional/Mocks/Company/GetCompanyByIdNotFoundMockTestCase.cs: -------------------------------------------------------------------------------- 1 | using System.Net; 2 | using System.Net.Http; 3 | using System.Threading.Tasks; 4 | using RapidCore.Network; 5 | using Skarp.HubSpotClient.Core; 6 | 7 | namespace Skarp.HubSpotClient.FunctionalTests.Mocks.Company 8 | { 9 | public class GetCompanyByIdNotFoundMockTestCase : IMockRapidHttpClientTestCase 10 | { 11 | public bool IsMatch(HttpRequestMessage request) 12 | { 13 | return request.RequestUri.AbsolutePath.Contains("/companies/v2/companies/158") && request.Method == HttpMethod.Get; 14 | } 15 | 16 | public Task GetResponseAsync(HttpRequestMessage request) 17 | { 18 | var response = new HttpResponseMessage(HttpStatusCode.OK); 19 | 20 | const string jsonResponse = "{'status':'error','message':'resource not found','correlationId':'addfe990 - 865c - 4dca - ae27 - 7f718bd0881e','requestId':'8516ca3e2e533437cf760c0fc3546dfe'}"; 21 | response.Content = new JsonContent(jsonResponse); 22 | response.StatusCode = HttpStatusCode.NotFound; 23 | response.RequestMessage = request; 24 | 25 | return Task.FromResult(response); 26 | } 27 | } 28 | } -------------------------------------------------------------------------------- /test/functional/Mocks/Company/GetCompanyMockTestCase.cs: -------------------------------------------------------------------------------- 1 | using System.Net; 2 | using System.Net.Http; 3 | using System.Threading.Tasks; 4 | using RapidCore.Network; 5 | using Skarp.HubSpotClient.Core; 6 | 7 | namespace Skarp.HubSpotClient.FunctionalTests.Mocks.Company 8 | { 9 | public class GetCompanyMockTestCase : IMockRapidHttpClientTestCase 10 | { 11 | public bool IsMatch(HttpRequestMessage request) 12 | { 13 | return request.RequestUri.AbsolutePath.Contains("/companies/v2/companies/10444744") && request.Method == HttpMethod.Get; 14 | } 15 | 16 | public Task GetResponseAsync(HttpRequestMessage request) 17 | { 18 | var response = new HttpResponseMessage(HttpStatusCode.OK); 19 | 20 | const string jsonResponse = "{'portalId': 62515,'companyId': 10444744,'isDeleted': false,'properties': {'description': {'value': 'A far better description than before', 'timestamp': 1403218621658,'source': 'API','sourceId': null,'versions': [{'name': 'description','value': 'A far better description than before','timestamp': 1403218621658,'source': 'API','sourceVid': []}]},'name': {'value': 'A company name','timestamp': 1403217668394,'source': 'API','sourceId': null,'versions': [{'name': 'name','value': 'A company name','timestamp': 1403217668394,'source': 'API','sourceVid': []}]},'createdate': {'value': '1403217668394','timestamp': 1403217668394,'source': 'API','sourceId': null,'versions': [{'name': 'createdate','value': '1403217668394','timestamp': 1403217668394,'source': 'API','sourceVid': []}]}}}"; 21 | response.Content = new JsonContent(jsonResponse); 22 | response.RequestMessage = request; 23 | 24 | return Task.FromResult(response); 25 | } 26 | } 27 | } -------------------------------------------------------------------------------- /test/functional/Mocks/Company/ListCompanyMockTestCase.cs: -------------------------------------------------------------------------------- 1 | using System.Net; 2 | using System.Net.Http; 3 | using System.Threading.Tasks; 4 | using RapidCore.Network; 5 | using Skarp.HubSpotClient.Core; 6 | 7 | namespace Skarp.HubSpotClient.FunctionalTests.Mocks.Company 8 | { 9 | public class ListCompanyMockTestCase : IMockRapidHttpClientTestCase 10 | { 11 | public bool IsMatch(HttpRequestMessage request) 12 | { 13 | return request.RequestUri.AbsolutePath.Contains("/companies/v2/companies/paged"); 14 | } 15 | 16 | public Task GetResponseAsync(HttpRequestMessage request) 17 | { 18 | var response = new HttpResponseMessage(HttpStatusCode.OK); 19 | 20 | const string jsonResponse = 21 | "{\"companies\":[" + 22 | "{'portalId': 62515,'companyId': 10444745,'isDeleted': false,'properties': {'description': {'value': 'A far better description than before', 'timestamp': 1403218621658,'source': 'API','sourceId': null,'versions': [{'name': 'description','value': 'A far better description than before','timestamp': 1403218621658,'source': 'API','sourceVid': []}]},'name': {'value': 'A company name','timestamp': 1403217668394,'source': 'API','sourceId': null,'versions': [{'name': 'name','value': 'A company name','timestamp': 1403217668394,'source': 'API','sourceVid': []}]},'createdate': {'value': '1403217668394','timestamp': 1403217668394,'source': 'API','sourceId': null,'versions': [{'name': 'createdate','value': '1403217668394','timestamp': 1403217668394,'source': 'API','sourceVid': []}]}}}, " + 23 | "{'portalId': 62515,'companyId': 10444746,'isDeleted': false,'properties': {'description': {'value': 'B far better description than before', 'timestamp': 1403218621659,'source': 'API','sourceId': null,'versions': [{'name': 'description','value': 'B far better description than before','timestamp': 1403218621658,'source': 'API','sourceVid': []}]},'name': {'value': 'B company name','timestamp': 1403217668394,'source': 'API','sourceId': null,'versions': [{'name': 'name','value': 'B company name','timestamp': 1403217668394,'source': 'API','sourceVid': []}]},'createdate': {'value': '1403217668394','timestamp': 1403217668394,'source': 'API','sourceId': null,'versions': [{'name': 'createdate','value': '1403217668394','timestamp': 1403217668394,'source': 'API','sourceVid': []}]}}}" + 24 | "],\"has-more\":true,\"offset\":10444746}"; 25 | 26 | 27 | response.Content = new JsonContent(jsonResponse); 28 | response.RequestMessage = request; 29 | 30 | return Task.FromResult(response); 31 | } 32 | } 33 | } -------------------------------------------------------------------------------- /test/functional/Mocks/Company/SearchByDomainMockTestCase.cs: -------------------------------------------------------------------------------- 1 | using System.Net; 2 | using System.Net.Http; 3 | using System.Threading.Tasks; 4 | using Newtonsoft.Json; 5 | using RapidCore.Network; 6 | using RapidCore.Threading; 7 | using Skarp.HubSpotClient.Core; 8 | 9 | namespace Skarp.HubSpotClient.FunctionalTests.Mocks.Company 10 | { 11 | public class SearchByDomainMockTestCase : IMockRapidHttpClientTestCase 12 | { 13 | public bool IsMatch(HttpRequestMessage request) 14 | { 15 | var requestData = request.Content.ReadAsStringAsync().AwaitSync(); 16 | return request.RequestUri.AbsolutePath.EndsWith("/companies/v2/domains/miaki.io/companies"); 17 | } 18 | 19 | public Task GetResponseAsync(HttpRequestMessage request) 20 | { 21 | var response = new HttpResponseMessage(HttpStatusCode.OK); 22 | 23 | const string jsonResponse = 24 | "{\"results\":[{\"portalId\":62515,\"companyId\":184896670,\"isDeleted\":false,\"properties\":{\"hs_lastmodifieddate\":{\"value\":\"1502872954691\",\"timestamp\":1502872954691,\"source\":\"CALCULATED\",\"sourceId\":null,\"versions\":[{\"name\":\"hs_lastmodifieddate\",\"value\":\"1502872954691\",\"timestamp\":1502872954691,\"source\":\"CALCULATED\",\"sourceVid\":[]}]},\"domain\":{\"value\":\"hubspot.com\",\"timestamp\":1457708103847,\"source\":\"COMPANIES\",\"sourceId\":null,\"versions\":[{\"name\":\"domain\",\"value\":\"hubspot.com\",\"timestamp\":1457708103847,\"source\":\"COMPANIES\",\"sourceVid\":[]}]},\"name\":{\"value\":\"Hubspot, Inc.\",\"timestamp\":1457708103906,\"source\":\"BIDEN\",\"sourceId\":\"name\",\"versions\":[{\"name\":\"name\",\"value\":\"Hubspot, Inc.\",\"timestamp\":1457708103906,\"sourceId\":\"name\",\"source\":\"BIDEN\",\"sourceVid\":[]}]},\"createdate\":{\"value\":\"1457708103847\",\"timestamp\":1457708103847,\"source\":\"API\",\"sourceId\":null,\"versions\":[{\"name\":\"createdate\",\"value\":\"1457708103847\",\"timestamp\":1457708103847,\"source\":\"API\",\"sourceVid\":[]}]}},\"additionalDomains\":[],\"stateChanges\":[],\"mergeAudits\":[]},{\"portalId\":62515,\"companyId\":418736767,\"isDeleted\":false,\"properties\":{\"hs_lastmodifieddate\":{\"value\":\"1498644245669\",\"timestamp\":1498644245669,\"source\":\"CALCULATED\",\"sourceId\":null,\"versions\":[{\"name\":\"hs_lastmodifieddate\",\"value\":\"1498644245669\",\"timestamp\":1498644245669,\"source\":\"CALCULATED\",\"sourceVid\":[]}]},\"domain\":{\"value\":\"hubspot.com\",\"timestamp\":1490280388204,\"source\":\"API\",\"sourceId\":null,\"versions\":[{\"name\":\"domain\",\"value\":\"hubspot.com\",\"timestamp\":1490280388204,\"source\":\"API\",\"sourceVid\":[]}]},\"name\":{\"value\":\"qweqwe2323\",\"timestamp\":1490280388204,\"source\":\"API\",\"sourceId\":null,\"versions\":[{\"name\":\"name\",\"value\":\"qweqwe2323\",\"timestamp\":1490280388204,\"source\":\"API\",\"sourceVid\":[]}]},\"createdate\":{\"value\":\"1490280388204\",\"timestamp\":1490280388204,\"source\":\"API\",\"sourceId\":\"API\",\"versions\":[{\"name\":\"createdate\",\"value\":\"1490280388204\",\"timestamp\":1490280388204,\"sourceId\":\"API\",\"source\":\"API\",\"sourceVid\":[]}]}},\"additionalDomains\":[],\"stateChanges\":[],\"mergeAudits\":[]}],\"hasMore\":true,\"offset\":{\"companyId\":418736767,\"isPrimary\":true}}"; 25 | response.Content = new JsonContent(jsonResponse); 26 | response.RequestMessage = request; 27 | 28 | return Task.FromResult(response); 29 | } 30 | } 31 | } -------------------------------------------------------------------------------- /test/functional/Mocks/Company/UpdateCompanyMockTestCase.cs: -------------------------------------------------------------------------------- 1 | using System.Net; 2 | using System.Net.Http; 3 | using System.Threading.Tasks; 4 | using RapidCore.Network; 5 | using Skarp.HubSpotClient.Core; 6 | 7 | namespace Skarp.HubSpotClient.FunctionalTests.Mocks.Company 8 | { 9 | public class UpdateCompanyMockTestCase : IMockRapidHttpClientTestCase 10 | { 11 | public bool IsMatch(HttpRequestMessage request) 12 | { 13 | return request.RequestUri.AbsolutePath.Contains("/companies/v2/companies/10444744") && request.Method == HttpMethod.Put; 14 | } 15 | 16 | public Task GetResponseAsync(HttpRequestMessage request) 17 | { 18 | var response = new HttpResponseMessage(HttpStatusCode.OK); 19 | 20 | const string jsonResponse = "{'portalId': 62515,'companyId': 10444744,'isDeleted': false,'properties': {'description': {'value': 'This is an updated description', 'timestamp': 1403218621658,'source': 'API','sourceId': null,'versions': [{'name': 'description','value': 'This is an updated description','timestamp': 1403218621658,'source': 'API','sourceVid': []}]},'name': {'value': 'This is an updated company','timestamp': 1403217668394,'source': 'API','sourceId': null,'versions': [{'name': 'name','value': 'This is an updated company','timestamp': 1403217668394,'source': 'API','sourceVid': []}]},'createdate': {'value': '1403217668394','timestamp': 1403217668394,'source': 'API','sourceId': null,'versions': [{'name': 'createdate','value': '1403217668394','timestamp': 1403217668394,'source': 'API','sourceVid': []}]}}}"; 21 | response.Content = new JsonContent(jsonResponse); 22 | response.RequestMessage = request; 23 | 24 | return Task.FromResult(response); 25 | } 26 | } 27 | } -------------------------------------------------------------------------------- /test/functional/Mocks/Contact/CreateContactMockTestCase.cs: -------------------------------------------------------------------------------- 1 | using System.Net; 2 | using System.Net.Http; 3 | using System.Threading.Tasks; 4 | using RapidCore.Network; 5 | using Skarp.HubSpotClient.Core; 6 | 7 | namespace Skarp.HubSpotClient.FunctionalTests.Mocks.Contact 8 | { 9 | public class CreateContactMockTestCase : IMockRapidHttpClientTestCase 10 | { 11 | public bool IsMatch(HttpRequestMessage request) 12 | { 13 | return request.RequestUri.AbsolutePath.EndsWith("/contacts/v1/contact"); 14 | } 15 | 16 | public Task GetResponseAsync(HttpRequestMessage request) 17 | { 18 | var response = new HttpResponseMessage(HttpStatusCode.OK); 19 | 20 | const string jsonResponse = 21 | "{'identity-profiles':[{'identities': [{'timestamp': 1331075050646,'type':'EMAIL','value':'fumanchu@hubspot.com'},{'timestamp': 1331075050681,'type': 'LEAD_GUID','value': '22a26060-c9d7-44b0-9f07-aa40488cfa3a' } ], 'vid': 61574 }],'properties': { 'website': { 'value': 'http://hubspot.com', 'versions': [ { 'timestamp': 1331075050646, 'selected':false, 'source-label':\"None\", 'value': 'http: //hubspot.com', 'source-type': 'API', 'source-id':\"None\" } ] }, 'city': { 'value': 'Cambridge', 'versions': [ { 'timestamp': 1331075050646, 'selected':false, 'source-label':\"None\", 'value': 'Cambridge', 'source-type': 'API', 'source-id':\"None\" } ] }, 'firstname': { 'value': 'Adrian', 'versions': [ { 'timestamp': 1331075050646, 'selected':false, 'source-label':\"None\", 'value': 'Adrian', 'source-type': 'API', 'source-id':\"None\" } ] }, 'zip': { 'value': '02139', 'versions': [ { 'timestamp': 1331075050646, 'selected':false, 'source-label':\"None\", 'value': '02139', 'source-type': 'API', 'source-id':\"None\" } ] }, 'lastname': { 'value': 'Mott', 'versions': [ { 'timestamp': 1331075050646, 'selected':false, 'source-label':\"None\", 'value': 'Mott', 'source-type': 'API', 'source-id':\"None\" } ] }, 'company': { 'value': 'HubSpot', 'versions': [ { 'timestamp': 1331075050646, 'selected':false, 'source-label':\"None\", 'value': 'HubSpot', 'source-type': 'API', 'source-id':\"None\" } ] }, 'phone': { 'value': '555-122-2323', 'versions': [ { 'timestamp': 1331075050646, 'selected':false, 'source-label':\"None\", 'value': '555-122-2323', 'source-type': 'API', 'source-id':\"None\" } ] }, 'state': { 'value': 'MA', 'versions': [ { 'timestamp': 1331075050646, 'selected':false, 'source-label':\"None\", 'value': 'MA', 'source-type': 'API', 'source-id':\"None\" } ] }, 'address': { 'value': '25FirstStreet', 'versions': [ { 'timestamp': 1331075050646, 'selected':false, 'source-label':\"None\", 'value': '25FirstStreet', 'source-type': 'API', 'source-id':\"None\" } ] }, 'email': { 'value': 'fumanchu@hubspot.com', 'versions': [ { 'timestamp': 1331075050646, 'selected':false, 'source-label':\"None\", 'value': 'fumanchu@hubspot.com', 'source-type': 'API', 'source-id':\"None\"}]}},'form-submissions': [],'vid': 61574}"; 22 | 23 | response.Content = new JsonContent(jsonResponse); 24 | response.RequestMessage = request; 25 | 26 | return Task.FromResult(response); 27 | } 28 | } 29 | } -------------------------------------------------------------------------------- /test/functional/Mocks/Contact/CreateOrUpdateContactMockTestCase.cs: -------------------------------------------------------------------------------- 1 | using System.Net; 2 | using System.Net.Http; 3 | using System.Threading.Tasks; 4 | using RapidCore.Network; 5 | using Skarp.HubSpotClient.Core; 6 | 7 | namespace Skarp.HubSpotClient.FunctionalTests.Mocks.Contact 8 | { 9 | public class CreateOrUpdateContactMockTestCase : IMockRapidHttpClientTestCase 10 | { 11 | public bool IsMatch(HttpRequestMessage request) 12 | { 13 | return request.RequestUri.AbsolutePath.EndsWith("/contact/createOrUpdate/email/that%40email.com"); 14 | } 15 | 16 | public Task GetResponseAsync(HttpRequestMessage request) 17 | { 18 | var response = new HttpResponseMessage(HttpStatusCode.OK); 19 | 20 | const string jsonResponse = 21 | "{'identity-profiles':[{'identities': [{'timestamp': 1331075050646,'type':'EMAIL','value':'fumanchu@hubspot.com'},{'timestamp': 1331075050681,'type': 'LEAD_GUID','value': '22a26060-c9d7-44b0-9f07-aa40488cfa3a' } ], 'vid': 61574 }],'properties': { 'website': { 'value': 'http://hubspot.com', 'versions': [ { 'timestamp': 1331075050646, 'selected':false, 'source-label':\"None\", 'value': 'http: //hubspot.com', 'source-type': 'API', 'source-id':\"None\" } ] }, 'city': { 'value': 'Cambridge', 'versions': [ { 'timestamp': 1331075050646, 'selected':false, 'source-label':\"None\", 'value': 'Cambridge', 'source-type': 'API', 'source-id':\"None\" } ] }, 'firstname': { 'value': 'Adrian', 'versions': [ { 'timestamp': 1331075050646, 'selected':false, 'source-label':\"None\", 'value': 'Adrian', 'source-type': 'API', 'source-id':\"None\" } ] }, 'zip': { 'value': '02139', 'versions': [ { 'timestamp': 1331075050646, 'selected':false, 'source-label':\"None\", 'value': '02139', 'source-type': 'API', 'source-id':\"None\" } ] }, 'lastname': { 'value': 'Mott', 'versions': [ { 'timestamp': 1331075050646, 'selected':false, 'source-label':\"None\", 'value': 'Mott', 'source-type': 'API', 'source-id':\"None\" } ] }, 'company': { 'value': 'HubSpot', 'versions': [ { 'timestamp': 1331075050646, 'selected':false, 'source-label':\"None\", 'value': 'HubSpot', 'source-type': 'API', 'source-id':\"None\" } ] }, 'phone': { 'value': '555-122-2323', 'versions': [ { 'timestamp': 1331075050646, 'selected':false, 'source-label':\"None\", 'value': '555-122-2323', 'source-type': 'API', 'source-id':\"None\" } ] }, 'state': { 'value': 'MA', 'versions': [ { 'timestamp': 1331075050646, 'selected':false, 'source-label':\"None\", 'value': 'MA', 'source-type': 'API', 'source-id':\"None\" } ] }, 'address': { 'value': '25FirstStreet', 'versions': [ { 'timestamp': 1331075050646, 'selected':false, 'source-label':\"None\", 'value': '25FirstStreet', 'source-type': 'API', 'source-id':\"None\" } ] }, 'email': { 'value': 'fumanchu@hubspot.com', 'versions': [ { 'timestamp': 1331075050646, 'selected':false, 'source-label':\"None\", 'value': 'fumanchu@hubspot.com', 'source-type': 'API', 'source-id':\"None\"}]}},'form-submissions': [],'vid': 61574}"; 22 | 23 | response.Content = new JsonContent(jsonResponse); 24 | response.RequestMessage = request; 25 | 26 | return Task.FromResult(response); 27 | } 28 | } 29 | } -------------------------------------------------------------------------------- /test/functional/Mocks/Contact/DeleteContactMockTestCase.cs: -------------------------------------------------------------------------------- 1 | using System.Net; 2 | using System.Net.Http; 3 | using System.Threading.Tasks; 4 | using RapidCore.Network; 5 | using Skarp.HubSpotClient.Core; 6 | 7 | namespace Skarp.HubSpotClient.FunctionalTests.Mocks.Contact 8 | { 9 | public class DeleteContactMockTestCase : IMockRapidHttpClientTestCase 10 | { 11 | public bool IsMatch(HttpRequestMessage request) 12 | { 13 | return request.RequestUri.AbsolutePath.Contains("contacts/v1/contact/vid/61571") && request.Method == HttpMethod.Delete; 14 | } 15 | 16 | public Task GetResponseAsync(HttpRequestMessage request) 17 | { 18 | const string jsonResponse = "{\"vid\": 61571, \"deleted\": true,\"reason\": \"OK\"}"; 19 | 20 | var response = new HttpResponseMessage(HttpStatusCode.OK) 21 | { 22 | Content = new JsonContent(jsonResponse), 23 | StatusCode = HttpStatusCode.NoContent, 24 | RequestMessage = request 25 | }; 26 | 27 | return Task.FromResult(response); 28 | } 29 | } 30 | } -------------------------------------------------------------------------------- /test/functional/Mocks/Contact/GetContactByEmailNotFoundMockTestCase.cs: -------------------------------------------------------------------------------- 1 | using System.Net; 2 | using System.Net.Http; 3 | using System.Threading.Tasks; 4 | using RapidCore.Network; 5 | using Skarp.HubSpotClient.Core; 6 | 7 | namespace Skarp.HubSpotClient.FunctionalTests.Mocks.Contact 8 | { 9 | public class GetContactByEmailNotFoundMockTestCase : IMockRapidHttpClientTestCase 10 | { 11 | public bool IsMatch(HttpRequestMessage request) 12 | { 13 | return request.RequestUri.AbsolutePath.Contains("/contacts/v1/contact/email/not@here.com") && request.Method == HttpMethod.Get; 14 | } 15 | 16 | public Task GetResponseAsync(HttpRequestMessage request) 17 | { 18 | var response = new HttpResponseMessage(HttpStatusCode.OK); 19 | 20 | const string jsonResponse = 21 | "{\"status\":\"error\",\"message\":\"contact does not exist\",\"correlationId\":\"6acf1262-0456-48d8-b0f8-070a698e7d05\",\"requestId\":\"ded0ada067ad2b3ff547f46afd03b9a7\"}"; 22 | response.Content = new JsonContent(jsonResponse); 23 | response.StatusCode = HttpStatusCode.NotFound; 24 | response.RequestMessage = request; 25 | 26 | return Task.FromResult(response); 27 | } 28 | } 29 | } -------------------------------------------------------------------------------- /test/functional/Mocks/Contact/ListContactMockTestCase.cs: -------------------------------------------------------------------------------- 1 | using System.Net; 2 | using System.Net.Http; 3 | using System.Threading.Tasks; 4 | using RapidCore.Network; 5 | using Skarp.HubSpotClient.Core; 6 | 7 | namespace Skarp.HubSpotClient.FunctionalTests.Mocks.Contact 8 | { 9 | public class ListContactMockTestCase : IMockRapidHttpClientTestCase 10 | { 11 | public bool IsMatch(HttpRequestMessage request) 12 | { 13 | return request.RequestUri.AbsolutePath.Contains("/contacts/v1/lists/all/contacts/all"); 14 | } 15 | 16 | public Task GetResponseAsync(HttpRequestMessage request) 17 | { 18 | var response = new HttpResponseMessage(HttpStatusCode.OK); 19 | 20 | const string jsonResponse = 21 | "{\"contacts\":[{\"addedAt\":1390574181854,\"vid\":204727,\"canonical-vid\":204727,\"merged-vids\":[],\"portal-id\":62515,\"is-contact\":true,\"profile-token\":\"AO_T-mMusl38dq-ff-Lms9BvB5nWgFb7sFrDU98e-3CBdnB7G2qCt1pMEHC9zmqSfOkeq2on6Dz72P-iLoGjEXfLuWfvZRWBpkB-C9Enw6SZ-ZASg57snQun5f32ISDfLOiK7BYDL0l2\",\"profile-url\":\"https://app.hubspot.com/contacts/62515/lists/public/contact/_AO_T-mMusl38dq-ff-Lms9BvB5nWgFb7sFrDU98e-3CBdnB7G2qCt1pMEHC9zmqSfOkeq2on6Dz72P-iLoGjEXfLuWfvZRWBpkB-C9Enw6SZ-ZASg57snQun5f32ISDfLOiK7BYDL0l2/\",\"properties\":{\"firstname\":{\"value\":\"Bob\"},\"lastmodifieddate\":{\"value\":\"1483461406481\"},\"company\":{\"value\":\"\"},\"lastname\":{\"value\":\"Record\"}},\"form-submissions\":[],\"identity-profiles\":[{\"vid\":204727,\"saved-at-timestamp\":1476768116149,\"deleted-changed-timestamp\":0,\"identities\":[{\"type\":\"LEAD_GUID\",\"value\":\"f9d728f1-dff1-49b0-9caa-247dbdf5b8b7\",\"timestamp\":1390574181878},{\"type\":\"EMAIL\",\"value\":\"mgnew-email@hubspot.com\",\"timestamp\":1476768116137}]}],\"merge-audits\":[]},{\"addedAt\":1392643921079,\"vid\":207303,\"canonical-vid\":207303,\"merged-vids\":[],\"portal-id\":62515,\"is-contact\":true,\"profile-token\":\"AO_T-mPMwvuZG_QTNH28c_MbhSyNRuuTNw9I7zJAaMFjOqL9HKlH9uBteqHAiTRUWVAPTThuU-Fmy7IemUNUvdtYpLrsll6nw47qnu7ACiSHFR6qZP1tDVZFpxueESKiKUIIvRjGzt8P\",\"profile-url\":\"https://app.hubspot.com/contacts/62515/lists/public/contact/_AO_T-mPMwvuZG_QTNH28c_MbhSyNRuuTNw9I7zJAaMFjOqL9HKlH9uBteqHAiTRUWVAPTThuU-Fmy7IemUNUvdtYpLrsll6nw47qnu7ACiSHFR6qZP1tDVZFpxueESKiKUIIvRjGzt8P/\",\"properties\":{\"firstname\":{\"value\":\"Ff_FirstName_0\"},\"lastmodifieddate\":{\"value\":\"1479148429488\"},\"lastname\":{\"value\":\"Ff_LastName_0\"}},\"form-submissions\":[],\"identity-profiles\":[{\"vid\":207303,\"saved-at-timestamp\":1392643921090,\"deleted-changed-timestamp\":0,\"identities\":[{\"type\":\"EMAIL\",\"value\":\"email_0be34aebe5@abctest.com\",\"timestamp\":1392643921079},{\"type\":\"LEAD_GUID\",\"value\":\"058378c6-9513-43e1-a13a-43a98d47aa22\",\"timestamp\":1392643921082}]}],\"merge-audits\":[]}],\"has-more\":true,\"vid-offset\":207303}"; 22 | 23 | 24 | response.Content = new JsonContent(jsonResponse); 25 | response.RequestMessage = request; 26 | 27 | return Task.FromResult(response); 28 | } 29 | } 30 | } -------------------------------------------------------------------------------- /test/functional/Mocks/Contact/UpdateContactMockTestCase.cs: -------------------------------------------------------------------------------- 1 | using System.Net; 2 | using System.Net.Http; 3 | using System.Threading.Tasks; 4 | using RapidCore.Network; 5 | using Skarp.HubSpotClient.Core; 6 | 7 | namespace Skarp.HubSpotClient.FunctionalTests.Mocks.Contact 8 | { 9 | public class UpdateContactMockTestCase : IMockRapidHttpClientTestCase 10 | { 11 | public bool IsMatch(HttpRequestMessage request) 12 | { 13 | return request.RequestUri.AbsolutePath.Contains("contacts/v1/contact/vid/2340324/profile") && request.Method == HttpMethod.Post; 14 | } 15 | 16 | public Task GetResponseAsync(HttpRequestMessage request) 17 | { 18 | var response = new HttpResponseMessage(HttpStatusCode.OK) 19 | { 20 | Content = null, 21 | StatusCode = HttpStatusCode.NoContent, 22 | RequestMessage = request 23 | }; 24 | 25 | 26 | return Task.FromResult(response); 27 | } 28 | } 29 | } -------------------------------------------------------------------------------- /test/functional/Mocks/Deal/CreateDealMockTestCase.cs: -------------------------------------------------------------------------------- 1 | using System.Net; 2 | using System.Net.Http; 3 | using System.Threading.Tasks; 4 | using RapidCore.Network; 5 | using Skarp.HubSpotClient.Core; 6 | 7 | namespace Skarp.HubSpotClient.FunctionalTests.Mocks.Deal 8 | { 9 | public class CreateDealMockTestCase : IMockRapidHttpClientTestCase 10 | { 11 | public bool IsMatch(HttpRequestMessage request) 12 | { 13 | return request.RequestUri.AbsolutePath.EndsWith("/deals/v1/deal"); 14 | } 15 | 16 | public Task GetResponseAsync(HttpRequestMessage request) 17 | { 18 | var response = new HttpResponseMessage(HttpStatusCode.OK); 19 | 20 | const string jsonResponse = "{'portalId': 62515,'dealId': 151088,'isDeleted': false,'associations': {'associatedVids': [27136],'associatedCompanyIds': [8954037],'associatedDealIds': []},'properties': {'amount': {'value': '60000','timestamp': 1410381338943,'source': 'API','sourceId': null,'versions': [{'name': 'amount','value': '60000','timestamp': 1410381338943,'source': 'API', 'sourceVid': []}]},'dealstage': {'value': 'appointmentscheduled','timestamp': 1410381338943,'source': 'API','sourceId': null,'versions': [{'name': 'dealstage','value': 'appointmentscheduled','timestamp': 1410381338943,'source': 'API','sourceVid': []}]},'pipeline': {'value': 'default','timestamp': 1410381338943,'source': 'API', 'sourceId': null,'versions': [{'name': 'pipeline','value': 'default','timestamp': 1410381338943,'source': 'API','sourceVid': []}]},'closedate': {'value': '1409443200000','timestamp': 1410381338943,'source': 'API','sourceId': null,'versions': [{'name': 'closedate','value': '1409443200000','timestamp': 1410381338943,'source': 'API', 'sourceVid': []}]},'createdate': {'value': '1410381339020','timestamp': 1410381339020,'source': null,'sourceId': null,'versions': [{'name': 'createdate','value': '1410381339020','timestamp': 1410381339020,'sourceVid': []}]},'hubspot_owner_id': {'value': '24','timestamp': 1410381338943,'source': 'API','sourceId': null,'versions': [{'name': 'hubspot_owner_id','value': '24','timestamp': 1410381338943,'source': 'API', 'sourceVid': []}]},'hs_createdate': {'value': '1410381339020','timestamp': 1410381339020,'source': null,'sourceId': null,'versions': [{'name': 'hs_createdate','value': '1410381339020','timestamp': 1410381339020,'sourceVid': []}]},'dealtype': {'value': 'newbusiness','timestamp': 1410381338943,'source': 'API','sourceId': null,'versions': [{'name': 'dealtype','value': 'newbusiness','timestamp': 1410381338943,'source': 'API', 'sourceVid': []}]},'dealname': {'value': 'A new Deal','timestamp': 1410381338943,'source': 'API','sourceId': null,'versions': [{'name': 'dealname','value': 'A new Deal','timestamp': 1410381338943,'source': 'API','sourceVid': []}]}}}"; 21 | response.Content = new JsonContent(jsonResponse); 22 | response.RequestMessage = request; 23 | 24 | return Task.FromResult(response); 25 | } 26 | } 27 | } -------------------------------------------------------------------------------- /test/functional/Mocks/Deal/DeleteDealMockTestCase.cs: -------------------------------------------------------------------------------- 1 | using System.Net; 2 | using System.Net.Http; 3 | using System.Threading.Tasks; 4 | using RapidCore.Network; 5 | using Skarp.HubSpotClient.Core; 6 | 7 | namespace Skarp.HubSpotClient.FunctionalTests.Mocks.Deal 8 | { 9 | public class DeleteDealMockTestCase : IMockRapidHttpClientTestCase 10 | { 11 | public bool IsMatch(HttpRequestMessage request) 12 | { 13 | return request.RequestUri.AbsolutePath.Contains("deals/v1/deal/151088") && request.Method == HttpMethod.Delete; 14 | } 15 | 16 | public Task GetResponseAsync(HttpRequestMessage request) 17 | { 18 | const string jsonResponse = ""; 19 | 20 | var response = new HttpResponseMessage(HttpStatusCode.OK) 21 | { 22 | Content = new JsonContent(jsonResponse), 23 | StatusCode = HttpStatusCode.NoContent, 24 | RequestMessage = request 25 | }; 26 | 27 | return Task.FromResult(response); 28 | } 29 | } 30 | } -------------------------------------------------------------------------------- /test/functional/Mocks/Deal/GetDealByIdNotFoundMockTestCase.cs: -------------------------------------------------------------------------------- 1 | using System.Net; 2 | using System.Net.Http; 3 | using System.Threading.Tasks; 4 | using RapidCore.Network; 5 | using Skarp.HubSpotClient.Core; 6 | 7 | namespace Skarp.HubSpotClient.FunctionalTests.Mocks.Deal 8 | { 9 | public class GetDealByIdNotFoundMockTestCase : IMockRapidHttpClientTestCase 10 | { 11 | public bool IsMatch(HttpRequestMessage request) 12 | { 13 | return request.RequestUri.AbsolutePath.Contains("/deals/v1/deal/158") && request.Method == HttpMethod.Get; 14 | } 15 | 16 | public Task GetResponseAsync(HttpRequestMessage request) 17 | { 18 | var response = new HttpResponseMessage(HttpStatusCode.OK); 19 | 20 | const string jsonResponse = 21 | "{'status':'error','message':'Deal does not exist','correlationId':'44f0d1e5-d6d8-4bc5-9b1b-51e5064e206f','requestId':'e3efb55b4250d72680f290f22bdf423e'}"; 22 | response.Content = new JsonContent(jsonResponse); 23 | response.StatusCode = HttpStatusCode.NotFound; 24 | response.RequestMessage = request; 25 | 26 | return Task.FromResult(response); 27 | } 28 | } 29 | } -------------------------------------------------------------------------------- /test/functional/Mocks/Deal/GetDealMockTestCase.cs: -------------------------------------------------------------------------------- 1 | using System.Net; 2 | using System.Net.Http; 3 | using System.Threading.Tasks; 4 | using RapidCore.Network; 5 | using Skarp.HubSpotClient.Core; 6 | 7 | namespace Skarp.HubSpotClient.FunctionalTests.Mocks.Deal 8 | { 9 | public class GetDealMockTestCase : IMockRapidHttpClientTestCase 10 | { 11 | public bool IsMatch(HttpRequestMessage request) 12 | { 13 | return request.RequestUri.AbsolutePath.Contains("/deals/v1/deal/151088") && request.Method == HttpMethod.Get; 14 | } 15 | 16 | public Task GetResponseAsync(HttpRequestMessage request) 17 | { 18 | var response = new HttpResponseMessage(HttpStatusCode.OK); 19 | 20 | const string jsonResponse = "{'portalId': 62515,'dealId': 151088,'isDeleted': false,'associations': {'associatedVids': [27136],'associatedCompanyIds': [8954037],'associatedDealIds': []},'properties': {'amount': {'value': '560','timestamp': 1410381338943,'source': 'API','sourceId': null,'versions': [{'name': 'amount','value': '560','timestamp': 1410381338943,'source': 'API', 'sourceVid': []}]},'dealstage': {'value': 'appointmentscheduled','timestamp': 1410381338943,'source': 'API','sourceId': null,'versions': [{'name': 'dealstage','value': 'appointmentscheduled','timestamp': 1410381338943,'source': 'API','sourceVid': []}]},'pipeline': {'value': 'default','timestamp': 1410381338943,'source': 'API', 'sourceId': null,'versions': [{'name': 'pipeline','value': 'default','timestamp': 1410381338943,'source': 'API','sourceVid': []}]},'closedate': {'value': '1409443200000','timestamp': 1410381338943,'source': 'API','sourceId': null,'versions': [{'name': 'closedate','value': '1409443200000','timestamp': 1410381338943,'source': 'API', 'sourceVid': []}]},'createdate': {'value': '1410381339020','timestamp': 1410381339020,'source': null,'sourceId': null,'versions': [{'name': 'createdate','value': '1410381339020','timestamp': 1410381339020,'sourceVid': []}]},'hubspot_owner_id': {'value': '24','timestamp': 1410381338943,'source': 'API','sourceId': null,'versions': [{'name': 'hubspot_owner_id','value': '24','timestamp': 1410381338943,'source': 'API', 'sourceVid': []}]},'hs_createdate': {'value': '1410381339020','timestamp': 1410381339020,'source': null,'sourceId': null,'versions': [{'name': 'hs_createdate','value': '1410381339020','timestamp': 1410381339020,'sourceVid': []}]},'dealtype': {'value': 'newbusiness','timestamp': 1410381338943,'source': 'API','sourceId': null,'versions': [{'name': 'dealtype','value': 'newbusiness','timestamp': 1410381338943,'source': 'API', 'sourceVid': []}]},'dealname': {'value': 'This is a Deal','timestamp': 1410381338943,'source': 'API','sourceId': null,'versions': [{'name': 'dealname','value': 'This is a Deal','timestamp': 1410381338943,'source': 'API','sourceVid': []}]}}}"; 21 | 22 | response.Content = new JsonContent(jsonResponse); 23 | response.RequestMessage = request; 24 | 25 | return Task.FromResult(response); 26 | } 27 | } 28 | } -------------------------------------------------------------------------------- /test/functional/Mocks/Deal/UpdateDealMockTestCase.cs: -------------------------------------------------------------------------------- 1 | using System.Net; 2 | using System.Net.Http; 3 | using System.Threading.Tasks; 4 | using RapidCore.Network; 5 | using Skarp.HubSpotClient.Core; 6 | 7 | namespace Skarp.HubSpotClient.FunctionalTests.Mocks.Deal 8 | { 9 | public class UpdateDealMockTestCase : IMockRapidHttpClientTestCase 10 | { 11 | public bool IsMatch(HttpRequestMessage request) 12 | { 13 | return request.RequestUri.AbsolutePath.Contains("deals/v1/deal/151088") && request.Method == HttpMethod.Put; 14 | } 15 | 16 | public Task GetResponseAsync(HttpRequestMessage request) 17 | { 18 | var response = new HttpResponseMessage(HttpStatusCode.OK); 19 | 20 | const string jsonResponse = "{'portalId': 62515,'dealId': 151088,'isDeleted': false,'associations': null,'properties': {'amount': {'value': '560','timestamp': 1459873345256,'source': 'API','sourceId': null,'versions': [{'name': 'amount','value': '560','timestamp': 1459873345256,'source': 'API','sourceVid': []}]},'hs_lastmodifieddate': {'value': '1459873345260','timestamp': 1459873345260,'source': 'CALCULATED','sourceId': null,'versions': [{'name': 'hs_lastmodifieddate','value': '1459873345260','timestamp': 1459873345260,'source': 'CALCULATED','sourceVid': []}]}},'imports': []}"; 21 | response.Content = new JsonContent(jsonResponse); 22 | response.RequestMessage = request; 23 | 24 | return Task.FromResult(response); 25 | } 26 | } 27 | } -------------------------------------------------------------------------------- /test/functional/Mocks/LineItem/CreateBatchLineItemMockTestCase.cs: -------------------------------------------------------------------------------- 1 | using RapidCore.Network; 2 | using Skarp.HubSpotClient.Core; 3 | using System.Net; 4 | using System.Net.Http; 5 | using System.Threading.Tasks; 6 | 7 | namespace Skarp.HubSpotClient.FunctionalTests.Mocks.LineItem 8 | { 9 | public class CreateBatchLineItemMockTestCase: IMockRapidHttpClientTestCase 10 | { 11 | public bool IsMatch(HttpRequestMessage request) 12 | { 13 | return request.RequestUri.AbsolutePath.EndsWith("/crm-objects/v1/objects/line_items/batch-create") && request.Method == HttpMethod.Post; 14 | } 15 | 16 | public Task GetResponseAsync(HttpRequestMessage request) 17 | { 18 | var response = new HttpResponseMessage(HttpStatusCode.OK); 19 | 20 | const string jsonResponse = "[{'objectType':'LINE_ITEM','portalId':62515,'objectId':9845651,'properties':{'amount':{'value':'687.50','timestamp':0,'source':'CALCULATED','sourceId':'LineItemAmountCalculator'},'quantity':{'value':'25','timestamp':1525369755209,'source':'API','sourceId':null},'hs_lastmodifieddate':{'value':'0','timestamp':0,'source':'CALCULATED','sourceId':null},'price':{'value':'27.50','timestamp':1525299376761,'source':'API','sourceId':null},'name':{'value':'A custom name for the product for this line item.','timestamp':1525369755209,'source':'API','sourceId':null},'createdate':{'value':'0','timestamp':0,'source':'API','sourceId':null},'description':{'value':'A description of this product.','timestamp':1525299376761,'source':'API','sourceId':null},'hs_product_id':{'value':'1645342','timestamp':1525369755209,'source':'API','sourceId':null},'recurringbillingfrequency':{'value':'quarterly','timestamp':1525299376761,'source':'API','sourceId':null}},'version':0,'isDeleted':false},{'objectType':'LINE_ITEM','portalId':62515,'objectId':9867373,'properties':{'amount':{'value':'-275.00','timestamp':0,'source':'CALCULATED','sourceId':'LineItemAmountCalculator'},'quantity':{'value':'25','timestamp':1525369755209,'source':'API','sourceId':null},'hs_lastmodifieddate':{'value':'0','timestamp':0,'source':'CALCULATED','sourceId':null},'price':{'value':'9.00','timestamp':1525369755209,'source':'API','sourceId':null},'name':{'value':'Widgets, special discount price','timestamp':1525369755209,'source':'API','sourceId':null},'createdate':{'value':'0','timestamp':0,'source':'API','sourceId':null},'discount':{'value':'20','timestamp':1525292253568,'source':'API','sourceId':null},'description':{'value':'A description of yet another product.','timestamp':1525289943771,'source':'API','sourceId':null},'hs_product_id':{'value':'1645187','timestamp':1525369755209,'source':'API','sourceId':null},'recurringbillingfrequency':{'value':'annually','timestamp':1525289943771,'source':'API','sourceId':null}},'version':0,'isDeleted':false}]"; 21 | response.Content = new JsonContent(jsonResponse); 22 | response.RequestMessage = request; 23 | 24 | return Task.FromResult(response); 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /test/functional/Mocks/LineItem/CreateLineItemMockTestCase.cs: -------------------------------------------------------------------------------- 1 | using RapidCore.Network; 2 | using Skarp.HubSpotClient.Core; 3 | using System.Net; 4 | using System.Net.Http; 5 | using System.Threading.Tasks; 6 | 7 | namespace Skarp.HubSpotClient.FunctionalTests.Mocks.LineItem 8 | { 9 | public class CreateLineItemMockTestCase : IMockRapidHttpClientTestCase 10 | { 11 | public bool IsMatch(HttpRequestMessage request) 12 | { 13 | return request.RequestUri.AbsolutePath.EndsWith("/crm-objects/v1/objects/line_items") && request.Method == HttpMethod.Post; 14 | } 15 | 16 | public Task GetResponseAsync(HttpRequestMessage request) 17 | { 18 | var response = new HttpResponseMessage(HttpStatusCode.OK); 19 | 20 | const string jsonResponse = "{'objectType':'LINE_ITEM','portalId':62515,'objectId':9867220,'properties':{'amount':{'value':'475.00','timestamp':0,'source':'CALCULATED','sourceId':'LineItemAmountCalculator'},'quantity':{'value':'50','timestamp':1525368534412,'source':'API','sourceId':null},'hs_lastmodifieddate':{'value':'0','timestamp':0,'source':'CALCULATED','sourceId':null},'price':{'value':'9.50','timestamp':1525368534412,'source':'API','sourceId':null},'name':{'value':'A custom name for the product for this line item. Discounting 5% on bulk purchase.','timestamp':1525368534412,'source':'API','sourceId':null},'createdate':{'value':'0','timestamp':0,'source':'API','sourceId':null},'description':{'value':'This product has an updated description and price.','timestamp':1525287810508,'source':'API','sourceId':null},'hs_product_id':{'value':'1642736','timestamp':1525368534412,'source':'API','sourceId':null}},'version':0,'isDeleted':false}"; 21 | response.Content = new JsonContent(jsonResponse); 22 | response.RequestMessage = request; 23 | 24 | return Task.FromResult(response); 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /test/functional/Mocks/LineItem/DeleteBatchLineItemMockTestCase.cs: -------------------------------------------------------------------------------- 1 | using RapidCore.Network; 2 | using Skarp.HubSpotClient.Core; 3 | using System.Net; 4 | using System.Net.Http; 5 | using System.Threading.Tasks; 6 | 7 | namespace Skarp.HubSpotClient.FunctionalTests.Mocks.LineItem 8 | { 9 | public class DeleteBatchLineItemMockTestCase : IMockRapidHttpClientTestCase 10 | { 11 | public bool IsMatch(HttpRequestMessage request) 12 | { 13 | return request.RequestUri.AbsolutePath.EndsWith("/crm-objects/v1/objects/line_items/batch-delete") && request.Method == HttpMethod.Post; 14 | } 15 | 16 | public Task GetResponseAsync(HttpRequestMessage request) 17 | { 18 | var response = new HttpResponseMessage(HttpStatusCode.NoContent) 19 | { 20 | RequestMessage = request 21 | }; 22 | 23 | return Task.FromResult(response); 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /test/functional/Mocks/LineItem/DeleteLineItemMockTestCase.cs: -------------------------------------------------------------------------------- 1 | using RapidCore.Network; 2 | using System.Net; 3 | using System.Net.Http; 4 | using System.Threading.Tasks; 5 | 6 | namespace Skarp.HubSpotClient.FunctionalTests.Mocks.LineItem 7 | { 8 | public class DeleteLineItemMockTestCase : IMockRapidHttpClientTestCase 9 | { 10 | public bool IsMatch(HttpRequestMessage request) 11 | { 12 | return request.RequestUri.AbsolutePath.EndsWith("/crm-objects/v1/objects/line_items/9867220") && request.Method == HttpMethod.Delete; 13 | } 14 | 15 | public Task GetResponseAsync(HttpRequestMessage request) 16 | { 17 | var response = new HttpResponseMessage(HttpStatusCode.NoContent) 18 | { 19 | RequestMessage = request 20 | }; 21 | 22 | return Task.FromResult(response); 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /test/functional/Mocks/LineItem/GetLineItemMockTestCase.cs: -------------------------------------------------------------------------------- 1 | using RapidCore.Network; 2 | using Skarp.HubSpotClient.Core; 3 | using System.Net; 4 | using System.Net.Http; 5 | using System.Threading.Tasks; 6 | 7 | namespace Skarp.HubSpotClient.FunctionalTests.Mocks.LineItem 8 | { 9 | public class GetLineItemMockTestCase : IMockRapidHttpClientTestCase 10 | { 11 | public bool IsMatch(HttpRequestMessage request) 12 | { 13 | return request.RequestUri.AbsolutePath.EndsWith("/crm-objects/v1/objects/line_items/9867220") 14 | && request.RequestUri.Query.Contains("properties=my_custom_property") 15 | && request.RequestUri.Query.Contains("includeDeletes=true") 16 | && request.Method == HttpMethod.Get; 17 | } 18 | 19 | public Task GetResponseAsync(HttpRequestMessage request) 20 | { 21 | var response = new HttpResponseMessage(HttpStatusCode.OK); 22 | 23 | const string jsonResponse = "{'objectType':'LINE_ITEM','portalId':62515,'objectId':9867220,'properties':{'amount':{'value':'475.00','timestamp':0,'source':'CALCULATED','sourceId':'LineItemAmountCalculator'},'quantity':{'value':'50','timestamp':1525368534412,'source':'API','sourceId':null},'hs_lastmodifieddate':{'value':'0','timestamp':0,'source':'CALCULATED','sourceId':null},'price':{'value':'9.50','timestamp':1525368534412,'source':'API','sourceId':null},'name':{'value':'This is a LineItem','timestamp':1525368534412,'source':'API','sourceId':null},'createdate':{'value':'0','timestamp':0,'source':'API','sourceId':null},'description':{'value':'This product has an updated description and price.','timestamp':1525287810508,'source':'API','sourceId':null},'hs_product_id':{'value':'1642736','timestamp':1525368534412,'source':'API','sourceId':null}},'version':0,'isDeleted':false}"; 24 | response.Content = new JsonContent(jsonResponse); 25 | response.RequestMessage = request; 26 | 27 | return Task.FromResult(response); 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /test/functional/Mocks/LineItem/GetLineItemNotFoundMockTestCase.cs: -------------------------------------------------------------------------------- 1 | using System.Net; 2 | using System.Net.Http; 3 | using System.Threading.Tasks; 4 | using RapidCore.Network; 5 | using Skarp.HubSpotClient.Core; 6 | 7 | namespace Skarp.HubSpotClient.FunctionalTests.Mocks.LineItem 8 | { 9 | public class GetLineItemNotFoundMockTestCase : IMockRapidHttpClientTestCase 10 | { 11 | public bool IsMatch(HttpRequestMessage request) 12 | { 13 | return request.RequestUri.AbsolutePath.Contains("/crm-objects/v1/objects/line_items/158") && request.Method == HttpMethod.Get; 14 | } 15 | 16 | public Task GetResponseAsync(HttpRequestMessage request) 17 | { 18 | var response = new HttpResponseMessage(HttpStatusCode.OK); 19 | 20 | const string jsonResponse = 21 | "{'status':'error','message':'Line item does not exist','correlationId':'44f0d1e5-d6d8-4bc5-9b1b-51e5064e206f','requestId':'e3efb55b4250d72680f290f22bdf423e'}"; 22 | response.Content = new JsonContent(jsonResponse); 23 | response.StatusCode = HttpStatusCode.NotFound; 24 | response.RequestMessage = request; 25 | 26 | return Task.FromResult(response); 27 | } 28 | } 29 | } -------------------------------------------------------------------------------- /test/functional/Mocks/LineItem/ListLineItemMockTestCase.cs: -------------------------------------------------------------------------------- 1 | using RapidCore.Network; 2 | using Skarp.HubSpotClient.Core; 3 | using System.Net; 4 | using System.Net.Http; 5 | using System.Threading.Tasks; 6 | 7 | namespace Skarp.HubSpotClient.FunctionalTests.Mocks.LineItem 8 | { 9 | public class ListLineItemMockTestCase : IMockRapidHttpClientTestCase 10 | { 11 | public bool IsMatch(HttpRequestMessage request) 12 | { 13 | return request.RequestUri.AbsolutePath.EndsWith("/crm-objects/v1/objects/line_items/paged") 14 | && request.RequestUri.Query.Contains("properties=my_custom_property") 15 | && request.RequestUri.Query.Contains("offset=9867220") 16 | && request.Method == HttpMethod.Get; 17 | } 18 | 19 | public Task GetResponseAsync(HttpRequestMessage request) 20 | { 21 | var response = new HttpResponseMessage(HttpStatusCode.OK); 22 | 23 | const string jsonResponse = "{'objects':[{'objectType':'LINE_ITEM','portalId':62515,'objectId':9843068,'properties':{'hs_product_id':{'value':'1642736','timestamp':0,'source':null,'sourceId':null}},'version':2,'isDeleted':false},{'objectType':'LINE_ITEM','portalId':62515,'objectId':9867220,'properties':{'hs_product_id':{'value':'1645187','timestamp':0,'source':null,'sourceId':null}},'version':1,'isDeleted':false}],'hasMore':true,'offset':9867220}"; 24 | response.Content = new JsonContent(jsonResponse); 25 | response.RequestMessage = request; 26 | 27 | return Task.FromResult(response); 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /test/functional/Mocks/LineItem/ReadBatchLineItemMockTestCase.cs: -------------------------------------------------------------------------------- 1 | using RapidCore.Network; 2 | using Skarp.HubSpotClient.Core; 3 | using System.Net; 4 | using System.Net.Http; 5 | using System.Threading.Tasks; 6 | 7 | namespace Skarp.HubSpotClient.FunctionalTests.Mocks.LineItem 8 | { 9 | internal class ReadBatchLineItemMockTestCase : IMockRapidHttpClientTestCase 10 | { 11 | public bool IsMatch(HttpRequestMessage request) 12 | { 13 | return request.RequestUri.AbsolutePath.EndsWith("/crm-objects/v1/objects/line_items/batch-read") && request.Method == HttpMethod.Post; 14 | } 15 | 16 | public Task GetResponseAsync(HttpRequestMessage request) 17 | { 18 | var response = new HttpResponseMessage(HttpStatusCode.OK); 19 | 20 | const string jsonResponse = "{'9845651':{'objectType':'LINE_ITEM','portalId':62515,'objectId':9845651,'properties':{'hs_product_id':{'versions':[{'name':'hs_product_id','value':'1645342','sourceVid':[]}],'value':'1645342','timestamp':0,'source':null,'sourceId':null}},'version':1,'isDeleted':false},'9867373':{'objectType':'LINE_ITEM','portalId':62515,'objectId':9867373,'properties':{'hs_product_id':{'versions':[{'name':'hs_product_id','value':'1645187','sourceVid':[]}],'value':'1645187','timestamp':0,'source':null,'sourceId':null}},'version':1,'isDeleted':false}}"; 21 | response.Content = new JsonContent(jsonResponse); 22 | response.RequestMessage = request; 23 | 24 | return Task.FromResult(response); 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /test/functional/Mocks/LineItem/UpdateBatchLineItemMockTestCase.cs: -------------------------------------------------------------------------------- 1 | using RapidCore.Network; 2 | using Skarp.HubSpotClient.Core; 3 | using System.Net; 4 | using System.Net.Http; 5 | using System.Threading.Tasks; 6 | 7 | namespace Skarp.HubSpotClient.FunctionalTests.Mocks.LineItem 8 | { 9 | public class UpdateBatchLineItemMockTestCase : IMockRapidHttpClientTestCase 10 | { 11 | public bool IsMatch(HttpRequestMessage request) 12 | { 13 | return request.RequestUri.AbsolutePath.EndsWith("/crm-objects/v1/objects/line_items/batch-update") && request.Method == HttpMethod.Post; 14 | } 15 | 16 | public Task GetResponseAsync(HttpRequestMessage request) 17 | { 18 | var response = new HttpResponseMessage(HttpStatusCode.OK); 19 | 20 | const string jsonResponse = "[{'objectType':'LINE_ITEM','portalId':62515,'objectId':9845651,'properties':{'amount':{'value':'687.50','timestamp':0,'source':'CALCULATED','sourceId':'LineItemAmountCalculator'},'quantity':{'value':'25','timestamp':1525369755209,'source':'API','sourceId':null},'hs_lastmodifieddate':{'value':'0','timestamp':0,'source':'CALCULATED','sourceId':null},'price':{'value':'27.50','timestamp':1525299376761,'source':'API','sourceId':null},'name':{'value':'A custom name for the product for this line item.','timestamp':1525369755209,'source':'API','sourceId':null},'createdate':{'value':'0','timestamp':0,'source':'API','sourceId':null},'description':{'value':'A description of this product.','timestamp':1525299376761,'source':'API','sourceId':null},'hs_product_id':{'value':'1645342','timestamp':1525369755209,'source':'API','sourceId':null},'recurringbillingfrequency':{'value':'quarterly','timestamp':1525299376761,'source':'API','sourceId':null}},'version':0,'isDeleted':false},{'objectType':'LINE_ITEM','portalId':62515,'objectId':9867373,'properties':{'amount':{'value':'-275.00','timestamp':0,'source':'CALCULATED','sourceId':'LineItemAmountCalculator'},'quantity':{'value':'25','timestamp':1525369755209,'source':'API','sourceId':null},'hs_lastmodifieddate':{'value':'0','timestamp':0,'source':'CALCULATED','sourceId':null},'price':{'value':'9.00','timestamp':1525369755209,'source':'API','sourceId':null},'name':{'value':'Widgets, special discount price','timestamp':1525369755209,'source':'API','sourceId':null},'createdate':{'value':'0','timestamp':0,'source':'API','sourceId':null},'discount':{'value':'20','timestamp':1525292253568,'source':'API','sourceId':null},'description':{'value':'A description of yet another product.','timestamp':1525289943771,'source':'API','sourceId':null},'hs_product_id':{'value':'1645187','timestamp':1525369755209,'source':'API','sourceId':null},'recurringbillingfrequency':{'value':'annually','timestamp':1525289943771,'source':'API','sourceId':null}},'version':0,'isDeleted':false}]"; 21 | response.Content = new JsonContent(jsonResponse); 22 | response.RequestMessage = request; 23 | 24 | return Task.FromResult(response); 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /test/functional/Mocks/LineItem/UpdateLineItemMockTestCase.cs: -------------------------------------------------------------------------------- 1 | using RapidCore.Network; 2 | using Skarp.HubSpotClient.Core; 3 | using System.Net; 4 | using System.Net.Http; 5 | using System.Threading.Tasks; 6 | 7 | namespace Skarp.HubSpotClient.FunctionalTests.Mocks.LineItem 8 | { 9 | public class UpdateLineItemMockTestCase : IMockRapidHttpClientTestCase 10 | { 11 | public bool IsMatch(HttpRequestMessage request) 12 | { 13 | return request.RequestUri.AbsolutePath.Contains("/crm-objects/v1/objects/line_items/9867220") && request.Method == HttpMethod.Put; 14 | } 15 | 16 | public Task GetResponseAsync(HttpRequestMessage request) 17 | { 18 | var response = new HttpResponseMessage(HttpStatusCode.OK); 19 | 20 | const string jsonResponse = "{'objectType':'LINE_ITEM','portalId':62515,'objectId':9867220,'properties':{'amount':{'value':'475.00','timestamp':0,'source':'CALCULATED','sourceId':'LineItemAmountCalculator'},'quantity':{'value':'50','timestamp':1525368534412,'source':'API','sourceId':null},'hs_lastmodifieddate':{'value':'0','timestamp':0,'source':'CALCULATED','sourceId':null},'price':{'value':'9.50','timestamp':1525368534412,'source':'API','sourceId':null},'name':{'value':'This is a LineItem','timestamp':1525368534412,'source':'API','sourceId':null},'createdate':{'value':'0','timestamp':0,'source':'API','sourceId':null},'description':{'value':'This product has an updated description and price.','timestamp':1525287810508,'source':'API','sourceId':null},'hs_product_id':{'value':'1642736','timestamp':1525368534412,'source':'API','sourceId':null}},'version':0,'isDeleted':false}"; 21 | response.Content = new JsonContent(jsonResponse); 22 | response.RequestMessage = request; 23 | 24 | return Task.FromResult(response); 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /test/functional/Mocks/Owner/GetOwnerByIdNotFoundMockTestCase.cs: -------------------------------------------------------------------------------- 1 | using RapidCore.Network; 2 | using Skarp.HubSpotClient.Core; 3 | using System.Net; 4 | using System.Net.Http; 5 | using System.Threading.Tasks; 6 | 7 | namespace Skarp.HubSpotClient.FunctionalTests.Mocks.Owner 8 | { 9 | public class GetOwnerByIdNotFoundMockTestCase : IMockRapidHttpClientTestCase 10 | { 11 | public bool IsMatch(HttpRequestMessage request) 12 | { 13 | return request.RequestUri.AbsolutePath.Contains("/owners/v2/owners/158") && request.Method == HttpMethod.Get; 14 | } 15 | 16 | public Task GetResponseAsync(HttpRequestMessage request) 17 | { 18 | var response = new HttpResponseMessage(HttpStatusCode.OK); 19 | 20 | const string jsonResponse = "{'status':'error','message':'resource not found','correlationId':'addfe990 - 865c - 4dca - ae27 - 7f718bd0881e','requestId':'8516ca3e2e533437cf760c0fc3546dfe'}"; 21 | response.Content = new JsonContent(jsonResponse); 22 | response.StatusCode = HttpStatusCode.NotFound; 23 | response.RequestMessage = request; 24 | 25 | return Task.FromResult(response); 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /test/functional/Mocks/Owner/GetOwnerMockTestCase.cs: -------------------------------------------------------------------------------- 1 | using RapidCore.Network; 2 | using Skarp.HubSpotClient.Core; 3 | using System.Net; 4 | using System.Net.Http; 5 | using System.Threading.Tasks; 6 | 7 | namespace Skarp.HubSpotClient.FunctionalTests.Mocks.Owner 8 | { 9 | public class GetOwnerMockTestCase : IMockRapidHttpClientTestCase 10 | { 11 | public bool IsMatch(HttpRequestMessage request) 12 | { 13 | return request.RequestUri.AbsolutePath.Contains("/owners/v2/owners/64") && request.Method == HttpMethod.Get; 14 | } 15 | 16 | public Task GetResponseAsync(HttpRequestMessage request) 17 | { 18 | var response = new HttpResponseMessage(HttpStatusCode.OK); 19 | 20 | const string jsonResponse = "{ \"portalId\": 62515, \"ownerId\": 64, \"type\": \"PERSON\", \"firstName\": \"An owner first name\", \"lastName\": \"An owner last name\", \"email\": \"owner@company.com\", \"createdAt\": 1405605858624, \"updatedAt\": 1416928146449, \"remoteList\": [ { \"portalId\": 62515, \"ownerId\": 64, \"remoteId\": \"137304\", \"remoteType\": \"HUBSPOT\", \"active\": true } ] }"; 21 | response.Content = new JsonContent(jsonResponse); 22 | response.RequestMessage = request; 23 | 24 | return Task.FromResult(response); 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /test/functional/Mocks/Owner/ListOwnerMockTestCase.cs: -------------------------------------------------------------------------------- 1 | using RapidCore.Network; 2 | using Skarp.HubSpotClient.Core; 3 | using System.Net; 4 | using System.Net.Http; 5 | using System.Threading.Tasks; 6 | 7 | namespace Skarp.HubSpotClient.FunctionalTests.Mocks.Owner 8 | { 9 | public class ListOwnerMockTestCase : IMockRapidHttpClientTestCase 10 | { 11 | public bool IsMatch(HttpRequestMessage request) 12 | { 13 | return request.RequestUri.AbsolutePath.Contains("/owners/v2/owners") && request.Method == HttpMethod.Get; 14 | } 15 | 16 | public Task GetResponseAsync(HttpRequestMessage request) 17 | { 18 | var response = new HttpResponseMessage(HttpStatusCode.OK); 19 | 20 | const string jsonResponse = 21 | "[" + 22 | "{ \"portalId\": 62515, \"ownerId\": 64, \"type\": \"PERSON\", \"firstName\": \"Holly\", \"lastName\": \"Flax\", \"email\": \"holly@dundermifflin.com\", \"createdAt\": 1405605858624, \"updatedAt\": 1416928146449, \"remoteList\": [ { \"portalId\": 62515, \"ownerId\": 64, \"remoteId\": \"137304\", \"remoteType\": \"HUBSPOT\", \"active\": true } ] }, " + 23 | "{ \"portalId\": 62515, \"ownerId\": 65, \"type\": \"PERSON\", \"firstName\": \"Michael\", \"lastName\": \"Scott\", \"email\": \"michael@dundermifflin.com\", \"createdAt\": 1405605858732, \"updatedAt\": 1416928145437, \"remoteList\": [ { \"portalId\": 62515, \"ownerId\": 65, \"remoteId\": \"153112\", \"remoteType\": \"HUBSPOT\", \"active\": true } ] }, " + 24 | "{ \"portalId\": 62515, \"ownerId\": 66, \"type\": \"PERSON\", \"firstName\": \"Dwight\", \"lastName\": \"Schrute\", \"email\": \"dwight@dundermifflin.com\", \"createdAt\": 1405605858898, \"updatedAt\": 1416928146430, \"remoteList\": [ { \"portalId\" : 62515, \"ownerId\": 66, \"remoteId\": \"166656\", \"remoteType\": \"HUBSPOT\", \"active\": true } ] } " + 25 | "]"; 26 | 27 | response.Content = new JsonContent(jsonResponse); 28 | response.RequestMessage = request; 29 | 30 | return Task.FromResult(response); 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /test/functional/Owner/HubSpotOwnerClientFunctionalTest.cs: -------------------------------------------------------------------------------- 1 | using System.Threading.Tasks; 2 | using Microsoft.Extensions.Logging; 3 | using RapidCore.Network; 4 | using Skarp.HubSpotClient.Core.Requests; 5 | using Xunit; 6 | using Xunit.Abstractions; 7 | using Skarp.HubSpotClient.FunctionalTests.Mocks.Owner; 8 | using Skarp.HubSpotClient.Owner; 9 | using Skarp.HubSpotClient.Owner.Dto; 10 | using System.Linq; 11 | 12 | namespace Skarp.HubSpotClient.FunctionalTests.Owner 13 | { 14 | public class HubSpotOwnerClientFunctionalTest : FunctionalTestBase 15 | { 16 | private readonly HubSpotOwnerClient _client; 17 | 18 | public HubSpotOwnerClientFunctionalTest(ITestOutputHelper output) 19 | : base(output) 20 | { 21 | var mockHttpClient = new MockRapidHttpClient() 22 | .AddTestCase(new GetOwnerMockTestCase()) 23 | .AddTestCase(new GetOwnerByIdNotFoundMockTestCase()) 24 | .AddTestCase(new ListOwnerMockTestCase()); 25 | 26 | _client = new HubSpotOwnerClient( 27 | mockHttpClient, 28 | Logger, 29 | new RequestSerializer(new RequestDataConverter(LoggerFactory.CreateLogger())), 30 | "https://api.hubapi.com/", 31 | "HapiKeyFisk" 32 | ); 33 | } 34 | 35 | [Fact] 36 | public async Task OwnerClient_can_get_owner_by_id_long() 37 | { 38 | const int ownerId = 64; 39 | var data = await _client.GetByIdAsync(ownerId); 40 | 41 | Assert.NotNull(data); 42 | Assert.Equal("An owner first name", data.FirstName); 43 | Assert.Equal("An owner last name", data.LastName); 44 | Assert.Equal("owner@company.com", data.Email); 45 | Assert.Equal(ownerId, data.Id); 46 | } 47 | 48 | [Fact] 49 | public async Task OwnerClient_can_get_owner_by_id_string() 50 | { 51 | const string ownerId = "64"; 52 | var data = await _client.GetByIdAsync(ownerId); 53 | 54 | Assert.NotNull(data); 55 | Assert.Equal("An owner first name", data.FirstName); 56 | Assert.Equal("An owner last name", data.LastName); 57 | Assert.Equal("owner@company.com", data.Email); 58 | Assert.Equal(ownerId, data.Id.ToString()); 59 | } 60 | 61 | [Fact] 62 | public async Task OwnerClient_can_get_list_of_owners() 63 | { 64 | var data = await _client.ListAsync(); 65 | 66 | Assert.NotNull(data); 67 | Assert.True(data.Count() == 3, "data.Count() == 3"); 68 | Assert.False(data.Any(owner => string.IsNullOrEmpty(owner.FirstName)), "All owners should have data"); 69 | } 70 | 71 | [Fact] 72 | public async Task OwnerClient_returns_null_when_owner_not_found() 73 | { 74 | const int ownerId = 158; 75 | var data = await _client.GetByIdAsync(ownerId); 76 | 77 | Assert.Null(data); 78 | } 79 | 80 | [Fact] 81 | public async Task OwnerClient_list_by_email_works() 82 | { 83 | var options = new OwnerListRequestOptions 84 | { 85 | Email = "owner@company.com" 86 | }; 87 | 88 | var response = await _client.ListAsync(options); 89 | 90 | Assert.NotNull(response); 91 | Assert.NotEmpty(response); 92 | Assert.False(response.Any(owner => string.IsNullOrEmpty(owner.FirstName)), "All owners should have data"); 93 | } 94 | 95 | [Fact] 96 | public async Task OwnerClient_list_with_include_inactive_works() 97 | { 98 | var options = new OwnerListRequestOptions 99 | { 100 | IncludeInactive = true 101 | }; 102 | 103 | var response = await _client.ListAsync(options); 104 | 105 | Assert.NotNull(response); 106 | Assert.NotEmpty(response); 107 | Assert.False(response.Any(owner => string.IsNullOrEmpty(owner.FirstName)), "All owners should have data"); 108 | } 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /test/functional/functional.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | net6.0 4 | false 5 | Skarp.HubSpotClient.FunctionalTests 6 | Skarp.HubSpotClient.FunctionalTests 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | runtime; build; native; contentfiles; analyzers; buildtransitive 15 | all 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /test/integration/Company/HubSpotCompanyClientIntegrationTest.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Net.Http; 4 | using System.Threading.Tasks; 5 | using Microsoft.Extensions.Logging; 6 | using RapidCore.Network; 7 | using Skarp.HubSpotClient.Common.Dto.Properties; 8 | using Skarp.HubSpotClient.Company; 9 | using Skarp.HubSpotClient.Company.Dto; 10 | using Skarp.HubSpotClient.Core.Requests; 11 | using Xunit; 12 | using Xunit.Abstractions; 13 | 14 | namespace integration.Company 15 | { 16 | public class HubSpotCompanyClientIntegrationTest : IntegrationTestBase 17 | { 18 | private readonly HubSpotCompanyClient _client; 19 | private readonly string _apiKey; 20 | private readonly bool _isAppVeyorEnv; 21 | 22 | public HubSpotCompanyClientIntegrationTest(ITestOutputHelper output) : base(output) 23 | { 24 | _apiKey = Environment.GetEnvironmentVariable("HUBSPOT_API_KEY") ?? Environment.GetEnvironmentVariable("HUBSPOT_API_TOKEN") ?? "demo"; 25 | _isAppVeyorEnv = (Environment.GetEnvironmentVariable("APPVEYOR") ?? "false").Equals("true", StringComparison.InvariantCultureIgnoreCase); 26 | ; _client = new HubSpotCompanyClient( 27 | new RealRapidHttpClient(new HttpClient()), 28 | base.Logger, 29 | new RequestSerializer(new RequestDataConverter(LoggerFactory.CreateLogger())), 30 | "https://api.hubapi.com", 31 | _apiKey 32 | ); 33 | } 34 | 35 | [Fact] 36 | public async Task List() 37 | { 38 | if (_isAppVeyorEnv) 39 | { 40 | Output.WriteLine("Skipping test as we're in AppVeyor, demo account does return 3 results"); 41 | Assert.True(true); 42 | return; 43 | } 44 | 45 | var companies = 46 | await _client.ListAsync>(new CompanyListRequestOptions 47 | { 48 | PropertiesToInclude = new List 49 | { 50 | "name", 51 | "hubspot_owner_id" 52 | }, 53 | }); 54 | 55 | Assert.NotNull(companies); 56 | Assert.NotNull(companies.Companies); 57 | Assert.NotEmpty(companies.Companies); 58 | Assert.True(companies.Companies.Count > 1, "companies.Companies.Count > 1"); 59 | } 60 | 61 | [Fact] 62 | public async Task GetProperties() 63 | { 64 | if (_isAppVeyorEnv) 65 | { 66 | Output.WriteLine("Skipping test as we're in AppVeyor, demo account does return 137 results"); 67 | Assert.True(true); 68 | return; 69 | } 70 | 71 | var properties = await _client.GetPropertiesAsync>(); 72 | 73 | Assert.NotNull(properties); 74 | Assert.NotEmpty(properties); 75 | Assert.True(properties.Count > 1, "properties.Count > 1"); 76 | } 77 | } 78 | } -------------------------------------------------------------------------------- /test/integration/Contact/Dto/ContactHubSpotEntityExtended.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Runtime.Serialization; 3 | using Skarp.HubSpotClient.Contact.Dto; 4 | 5 | namespace integration.Contact.Dto 6 | { 7 | /// 8 | /// Extended HubSpot Contact Entity 9 | /// 10 | /// Used to test functionality of DateTime/DateTime?/DateTimeOffset/DateTimeOffset? 11 | [DataContract] 12 | public class ContactHubSpotEntityExtended : ContactHubSpotEntity 13 | { 14 | [DataMember(Name = "lastmodifieddate")] 15 | public DateTimeOffset? LastModified { get; set; } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /test/integration/Contact/HubSpotContactClientIntegrationTest.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Net.Http; 4 | using System.Runtime.Serialization; 5 | using System.Threading.Tasks; 6 | using integration.Contact.Dto; 7 | using Microsoft.Extensions.Logging; 8 | using RapidCore.Network; 9 | using Skarp.HubSpotClient.Contact; 10 | using Skarp.HubSpotClient.Contact.Dto; 11 | using Skarp.HubSpotClient.Core.Requests; 12 | using Xunit; 13 | using Xunit.Abstractions; 14 | 15 | namespace integration.Contact 16 | { 17 | public class HubSpotContactClientIntegrationTest : IntegrationTestBase 18 | { 19 | private readonly HubSpotContactClient _client; 20 | private readonly string _apiKey; 21 | private readonly bool _isAppVeyorEnv; 22 | 23 | public HubSpotContactClientIntegrationTest(ITestOutputHelper output) : base(output) 24 | { 25 | _apiKey = Environment.GetEnvironmentVariable("HUBSPOT_API_KEY") ?? Environment.GetEnvironmentVariable("HUBSPOT_API_TOKEN") ?? "demo"; 26 | _isAppVeyorEnv = (Environment.GetEnvironmentVariable("APPVEYOR") ?? "false").Equals("true", StringComparison.InvariantCultureIgnoreCase); 27 | ; _client = new HubSpotContactClient( 28 | new RealRapidHttpClient(new HttpClient()), 29 | base.Logger, 30 | new RequestSerializer(new RequestDataConverter(LoggerFactory.CreateLogger())), 31 | "https://api.hubapi.com", 32 | _apiKey 33 | ); 34 | } 35 | 36 | [Fact] 37 | public async Task Get_non_existing_contact_works() 38 | { 39 | var contact = await _client.GetByEmailAsync("iamnothere@skarp.dk"); 40 | Assert.Null(contact); 41 | } 42 | 43 | [Fact] 44 | public async Task Create_contact_and_get_works() 45 | { 46 | if (_apiKey.Equals("demo") && _isAppVeyorEnv) 47 | { 48 | Output.WriteLine("Skipping test as the API key is incorrectly set and we're in AppVeyor"); 49 | Assert.True(true); 50 | return; 51 | } 52 | 53 | var contact = new ContactHubSpotEntity 54 | { 55 | Address = "Som street 42", 56 | City = "Appleseed", 57 | Company = "Damage Inc.", 58 | Email = $"{Guid.NewGuid():N}@skarp.dk", 59 | FirstName = "Mr", 60 | Lastname = "Tester", 61 | Phone = "+45 12345678", 62 | State = "", 63 | ZipCode = "2300" 64 | }; 65 | var created = await _client.CreateAsync(contact); 66 | 67 | Assert.NotNull(created.Id); 68 | 69 | var retrieved = await _client.GetByIdAsync(created.Id.Value); 70 | 71 | Assert.NotNull(retrieved); 72 | Assert.Equal("2300", retrieved.ZipCode); 73 | } 74 | 75 | [Fact] 76 | public async Task List_contacts_works() 77 | { 78 | var contacts = 79 | await _client.ListAsync>(new ContactListRequestOptions 80 | { 81 | NumberOfContactsToReturn = 5, 82 | PropertiesToInclude = new List { "lastmodifieddate" } 83 | }); 84 | 85 | Assert.NotNull(contacts); 86 | Assert.NotNull(contacts.Contacts); 87 | Assert.NotEmpty(contacts.Contacts); 88 | Assert.True(contacts.Contacts.Count > 1, "contacts.Contacts.Count > 1"); 89 | } 90 | } 91 | } -------------------------------------------------------------------------------- /test/integration/IntegrationTestBase.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.Logging; 2 | using RapidCore.Xunit.Logging; 3 | using Xunit.Abstractions; 4 | 5 | namespace integration 6 | { 7 | public abstract class IntegrationTestBase 8 | { 9 | protected readonly ITestOutputHelper Output; 10 | protected readonly LoggerFactory LoggerFactory; 11 | protected readonly ILogger Logger; 12 | 13 | protected IntegrationTestBase(ITestOutputHelper output) 14 | { 15 | Output = output; 16 | LoggerFactory = new LoggerFactory(); 17 | LoggerFactory.AddXunitOutput(output); 18 | 19 | Logger = LoggerFactory.CreateLogger(); 20 | } 21 | } 22 | } -------------------------------------------------------------------------------- /test/integration/integration.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | net6.0 4 | false 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | runtime; build; native; contentfiles; analyzers; buildtransitive 13 | all 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /test/unit/Company/HubSpotCompanyClientTest.cs: -------------------------------------------------------------------------------- 1 | using System.Net; 2 | using System.Net.Http; 3 | using System.Threading.Tasks; 4 | using FakeItEasy; 5 | using RapidCore.Network; 6 | using Skarp.HubSpotClient.Core; 7 | using Skarp.HubSpotClient.Core.Interfaces; 8 | using Skarp.HubSpotClient.Core.Requests; 9 | using Xunit; 10 | using Xunit.Abstractions; 11 | using Skarp.HubSpotClient.Company; 12 | using Skarp.HubSpotClient.Company.Dto; 13 | 14 | namespace Skarp.HubSpotClient.UnitTest.Company 15 | { 16 | public class HubSpotCompanyClientTest : UnitTestBase 17 | { 18 | private readonly HubSpotCompanyClient _client; 19 | private IRapidHttpClient _mockHttpClient; 20 | private RequestSerializer _mockSerializer; 21 | 22 | public HubSpotCompanyClientTest(ITestOutputHelper output) : base(output) 23 | { 24 | _mockHttpClient = A.Fake(opts => opts.Strict()); 25 | 26 | A.CallTo(() => _mockHttpClient.SendAsync(A.Ignored)) 27 | .Returns(Task.FromResult(CreateNewEmptyOkResponse())); 28 | 29 | _mockSerializer = A.Fake(opts => opts.Strict()); 30 | A.CallTo(() => _mockSerializer.SerializeEntity(A.Ignored)) 31 | .Returns("{}"); 32 | 33 | A.CallTo(() => _mockSerializer.DeserializeEntity(A.Ignored)) 34 | .Returns(new CompanyHubSpotEntity()); 35 | 36 | A.CallTo(() => _mockSerializer.DeserializeListEntity>(A.Ignored)) 37 | .Returns(new CompanyListHubSpotEntity()); 38 | 39 | _client = new HubSpotCompanyClient( 40 | _mockHttpClient, 41 | Logger, 42 | _mockSerializer, 43 | "https://api.hubapi.com", 44 | "HapiKeyFisk" 45 | ); 46 | } 47 | 48 | private HttpResponseMessage CreateNewEmptyOkResponse() 49 | { 50 | var response = new HttpResponseMessage(HttpStatusCode.OK) 51 | { 52 | Content = new JsonContent("{}") 53 | }; 54 | return response; 55 | } 56 | 57 | [Theory] 58 | [InlineData(HubSpotAction.Create, "/companies/v2/companies")] 59 | [InlineData(HubSpotAction.Get, "/companies/v2/companies/:companyId:")] 60 | [InlineData(HubSpotAction.Update, "/companies/v2/companies/:companyId:")] 61 | [InlineData(HubSpotAction.Delete, "/companies/v2/companies/:companyId:")] 62 | [InlineData(HubSpotAction.List, "/companies/v2/companies/paged")] 63 | public void CompanyClient_path_resolver_works(HubSpotAction action, string expetedPath) 64 | { 65 | var resvoledPath = _client.PathResolver(new CompanyHubSpotEntity(), action); 66 | Assert.Equal(expetedPath, resvoledPath); 67 | } 68 | 69 | [Fact] 70 | public async Task CompanyClient_create_contact_work() 71 | { 72 | var response = await _client.CreateAsync(new CompanyHubSpotEntity 73 | { 74 | Name = "A new Company", 75 | Description = "A new description" 76 | }); 77 | 78 | A.CallTo(() => _mockHttpClient.SendAsync(A.Ignored)).MustHaveHappened(); 79 | A.CallTo(() => _mockSerializer.SerializeEntity(A.Ignored)).MustHaveHappened(); 80 | A.CallTo(() => _mockSerializer.DeserializeEntity("{}")).MustHaveHappened(); 81 | } 82 | 83 | [Fact] 84 | public async Task CompanyClient_list_companies_work() 85 | { 86 | var response = await _client.ListAsync>(); 87 | 88 | A.CallTo(() => _mockHttpClient.SendAsync(A.Ignored)).MustHaveHappened(); 89 | //A.CallTo(() => _mockSerializer.SerializeEntity(A.Ignored)).MustHaveHappened(); 90 | A.CallTo(() => _mockSerializer.DeserializeListEntity>("{}")).MustHaveHappened(); 91 | } 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /test/unit/Contact/HubSpotContactClientTest.cs: -------------------------------------------------------------------------------- 1 | using System.Net; 2 | using System.Net.Http; 3 | using System.Threading.Tasks; 4 | using FakeItEasy; 5 | using RapidCore.Network; 6 | using Skarp.HubSpotClient.Contact; 7 | using Skarp.HubSpotClient.Contact.Dto; 8 | using Skarp.HubSpotClient.Core; 9 | using Skarp.HubSpotClient.Core.Interfaces; 10 | using Skarp.HubSpotClient.Core.Requests; 11 | using Xunit; 12 | using Xunit.Abstractions; 13 | 14 | namespace Skarp.HubSpotClient.UnitTest.Contact 15 | { 16 | public class HubSpotContactClientTest : UnitTestBase 17 | { 18 | private readonly HubSpotContactClient _client; 19 | private IRapidHttpClient _mockHttpClient; 20 | private RequestSerializer _mockSerializer; 21 | 22 | public HubSpotContactClientTest(ITestOutputHelper output) : base(output) 23 | { 24 | _mockHttpClient = A.Fake(opts => opts.Strict()); 25 | 26 | A.CallTo(() => _mockHttpClient.SendAsync(A.Ignored)) 27 | .Returns(Task.FromResult(CreateNewEmptyOkResponse())); 28 | 29 | _mockSerializer = A.Fake(opts => opts.Strict()); 30 | A.CallTo(() => _mockSerializer.SerializeEntity(A.Ignored)) 31 | .Returns("{}"); 32 | 33 | A.CallTo(() => _mockSerializer.DeserializeEntity(A.Ignored)) 34 | .Returns(new ContactHubSpotEntity()); 35 | 36 | A.CallTo(() => _mockSerializer.DeserializeListEntity>(A.Ignored)) 37 | .Returns(new ContactListHubSpotEntity()); 38 | 39 | _client = new HubSpotContactClient( 40 | _mockHttpClient, 41 | Logger, 42 | _mockSerializer, 43 | "https://api.hubapi.com", 44 | "HapiKeyFisk" 45 | ); 46 | } 47 | 48 | private HttpResponseMessage CreateNewEmptyOkResponse() 49 | { 50 | var response = new HttpResponseMessage(HttpStatusCode.OK) 51 | { 52 | Content = new JsonContent("{}") 53 | }; 54 | return response; 55 | } 56 | 57 | [Theory] 58 | [InlineData(HubSpotAction.Create, "/contacts/v1/contact")] 59 | [InlineData(HubSpotAction.Get, "/contacts/v1/contact/vid/:contactId:/profile")] 60 | [InlineData(HubSpotAction.List, "/contacts/v1/lists/all/contacts/all")] 61 | [InlineData(HubSpotAction.Update, "/contacts/v1/contact/vid/:contactId:/profile")] 62 | [InlineData(HubSpotAction.Delete, "/contacts/v1/contact/vid/:contactId:")] 63 | public void ContactClient_path_resolver_works(HubSpotAction action, string expetedPath) 64 | { 65 | var resvoledPath = _client.PathResolver(new ContactHubSpotEntity(), action); 66 | Assert.Equal(expetedPath, resvoledPath); 67 | } 68 | 69 | [Fact] 70 | public async Task ContactClient_create_contact_work() 71 | { 72 | var response = await _client.CreateAsync(new ContactHubSpotEntity 73 | { 74 | FirstName = "Adrian", 75 | Lastname = "Baws", 76 | Email = "adrian@the-email.com" 77 | }); 78 | 79 | A.CallTo(() => _mockHttpClient.SendAsync(A.Ignored)).MustHaveHappened(); 80 | A.CallTo(() => _mockSerializer.SerializeEntity(A.Ignored)).MustHaveHappened(); 81 | A.CallTo(() => _mockSerializer.DeserializeEntity("{}")).MustHaveHappened(); 82 | } 83 | 84 | [Fact] 85 | public async Task ContactClient_list_contacts_work() 86 | { 87 | var response = await _client.ListAsync>(); 88 | 89 | A.CallTo(() => _mockHttpClient.SendAsync(A.Ignored)).MustHaveHappened(); 90 | //A.CallTo(() => _mockSerializer.SerializeEntity(A.Ignored)).MustHaveHappened(); 91 | A.CallTo(() => _mockSerializer.DeserializeListEntity>("{}")).MustHaveHappened(); 92 | } 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /test/unit/Contact/ListContactsRequestOptionsTest.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Skarp.HubSpotClient.Contact; 3 | using Xunit; 4 | 5 | namespace Skarp.HubSpotClient.UnitTest.Contact 6 | { 7 | public class ListContactsRequestOptionsTest 8 | { 9 | private ContactListRequestOptions _opts; 10 | 11 | public ListContactsRequestOptionsTest() 12 | { 13 | _opts = new ContactListRequestOptions(); 14 | } 15 | 16 | [Theory] 17 | [InlineData(0)] 18 | [InlineData(-1)] 19 | [InlineData(-9999)] 20 | [InlineData(int.MinValue)] 21 | [InlineData(101)] 22 | [InlineData(int.MaxValue)] 23 | public void ListContactRequestOptions_set_contacts_to_return_validates(int theValue) 24 | { 25 | var ex = Record.Exception(() =>_opts.NumberOfContactsToReturn = theValue); 26 | Assert.NotNull(ex); 27 | Assert.IsType(ex); 28 | } 29 | 30 | [Fact] 31 | public void ListContactRequestOptions_set_contacts_with_valid_value_does_not_throw() 32 | { 33 | // NO EXECPTION SHALL BE THROWN 34 | const int daValue = 50; 35 | _opts.NumberOfContactsToReturn = daValue; 36 | Assert.Equal(daValue, _opts.NumberOfContactsToReturn); 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /test/unit/Core/HubspotExceptionTest.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | using Xunit; 5 | 6 | namespace Skarp.HubSpotClient.UnitTest.Core 7 | { 8 | public class HubspotExceptionTest 9 | { 10 | [Fact] 11 | public void HubspotException_exception_with_nojson_nomessage_renders_correct_message() 12 | { 13 | try 14 | { 15 | throw new HubSpotException(); 16 | } 17 | catch (HubSpotException ex) 18 | { 19 | Assert.Equal("Exception of type 'Skarp.HubSpotClient.HubSpotException' was thrown., JSONResponse=Empty", ex.Message); 20 | } 21 | } 22 | 23 | [Fact] 24 | public void HubspotException_exception_with_nojson_message_renders_correct_message() 25 | { 26 | try 27 | { 28 | throw new HubSpotException("Test Message"); 29 | } 30 | catch (HubSpotException ex) 31 | { 32 | Assert.Equal("Test Message, JSONResponse=Empty", ex.Message); 33 | } 34 | } 35 | 36 | [Fact] 37 | public void HubspotException_exception_with_json_message_renders_correct_message() 38 | { 39 | try 40 | { 41 | throw new HubSpotException("Test Message" , "JSON Message"); 42 | } 43 | catch (HubSpotException ex) 44 | { 45 | Assert.Equal("Test Message, JSONResponse=JSON Message", ex.Message); 46 | } 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /test/unit/Deal/HubSpotDealClientTest.cs: -------------------------------------------------------------------------------- 1 | using System.Net; 2 | using System.Net.Http; 3 | using System.Threading.Tasks; 4 | using FakeItEasy; 5 | using RapidCore.Network; 6 | using Skarp.HubSpotClient.Core; 7 | using Skarp.HubSpotClient.Core.Interfaces; 8 | using Skarp.HubSpotClient.Core.Requests; 9 | using Skarp.HubSpotClient.Deal; 10 | using Skarp.HubSpotClient.Deal.Dto; 11 | using Xunit; 12 | using Xunit.Abstractions; 13 | 14 | namespace Skarp.HubSpotClient.UnitTest.Deal 15 | { 16 | public class HubSpotDealClientTest : UnitTestBase 17 | { 18 | private readonly HubSpotDealClient _client; 19 | private IRapidHttpClient _mockHttpClient; 20 | private RequestSerializer _mockSerializer; 21 | 22 | public HubSpotDealClientTest(ITestOutputHelper output) : base(output) 23 | { 24 | _mockHttpClient = A.Fake(opts => opts.Strict()); 25 | 26 | A.CallTo(() => _mockHttpClient.SendAsync(A.Ignored)) 27 | .Returns(Task.FromResult(CreateNewEmptyOkResponse())); 28 | 29 | _mockSerializer = A.Fake(opts => opts.Strict()); 30 | A.CallTo(() => _mockSerializer.SerializeEntity(A.Ignored)) 31 | .Returns("{}"); 32 | 33 | A.CallTo(() => _mockSerializer.DeserializeEntity(A.Ignored)) 34 | .Returns(new DealHubSpotEntity()); 35 | 36 | A.CallTo(() => _mockSerializer.DeserializeListEntity>(A.Ignored)) 37 | .Returns(new DealListHubSpotEntity()); 38 | 39 | _client = new HubSpotDealClient( 40 | _mockHttpClient, 41 | Logger, 42 | _mockSerializer, 43 | "https://api.hubapi.com", 44 | "HapiKeyFisk" 45 | ); 46 | } 47 | 48 | private HttpResponseMessage CreateNewEmptyOkResponse() 49 | { 50 | var response = new HttpResponseMessage(HttpStatusCode.OK) 51 | { 52 | Content = new JsonContent("{}") 53 | }; 54 | return response; 55 | } 56 | 57 | [Theory] 58 | [InlineData(HubSpotAction.Create, "/deals/v1/deal")] 59 | [InlineData(HubSpotAction.Get, "/deals/v1/deal/:dealId:")] 60 | [InlineData(HubSpotAction.Update, "/deals/v1/deal/:dealId:")] 61 | [InlineData(HubSpotAction.Delete, "/deals/v1/deal/:dealId:")] 62 | [InlineData(HubSpotAction.List, "/deals/v1/deal/paged")] 63 | public void DealClient_path_resolver_works(HubSpotAction action, string expetedPath) 64 | { 65 | var resvoledPath = _client.PathResolver(new DealHubSpotEntity(), action); 66 | Assert.Equal(expetedPath, resvoledPath); 67 | } 68 | 69 | [Fact] 70 | public async Task DealClient_create_contact_work() 71 | { 72 | var response = await _client.CreateAsync(new DealHubSpotEntity 73 | { 74 | Name = "A new deal", 75 | Pipeline = "default", 76 | Amount = 60000, 77 | DealType = "newbusiness" 78 | }); 79 | 80 | A.CallTo(() => _mockHttpClient.SendAsync(A.Ignored)).MustHaveHappened(); 81 | A.CallTo(() => _mockSerializer.SerializeEntity(A.Ignored)).MustHaveHappened(); 82 | A.CallTo(() => _mockSerializer.DeserializeEntity("{}")).MustHaveHappened(); 83 | } 84 | 85 | [Fact] 86 | public async Task DealClient_list_work() 87 | { 88 | var response = await _client.ListAsync>(); 89 | 90 | A.CallTo(() => _mockHttpClient.SendAsync(A.Ignored)).MustHaveHappened(); 91 | //A.CallTo(() => _mockSerializer.SerializeEntity(A.Ignored)).MustHaveHappened(); 92 | A.CallTo(() => _mockSerializer.DeserializeListEntity>("{}")).MustHaveHappened(); 93 | } 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /test/unit/LineItem/HubSpotLineItemClientTest.cs: -------------------------------------------------------------------------------- 1 | using FakeItEasy; 2 | using RapidCore.Network; 3 | using Skarp.HubSpotClient.Core; 4 | using Skarp.HubSpotClient.Core.Requests; 5 | using Skarp.HubSpotClient.LineItem; 6 | using Skarp.HubSpotClient.LineItem.Dto; 7 | using Skarp.HubSpotClient.LineItem.Interfaces; 8 | using System.Net; 9 | using System.Net.Http; 10 | using System.Threading.Tasks; 11 | using Xunit; 12 | using Xunit.Abstractions; 13 | 14 | namespace Skarp.HubSpotClient.UnitTest.LineItem 15 | { 16 | public class HubSpotLineItemClientTest : UnitTestBase 17 | { 18 | private readonly HubSpotLineItemClient _client; 19 | private IRapidHttpClient _mockHttpClient; 20 | private RequestSerializer _mockSerializer; 21 | 22 | public HubSpotLineItemClientTest(ITestOutputHelper output) : base(output) 23 | { 24 | _mockHttpClient = A.Fake(opts => opts.Strict()); 25 | 26 | A.CallTo(() => _mockHttpClient.SendAsync(A.Ignored)) 27 | .Returns(Task.FromResult(CreateNewEmptyOkResponse())); 28 | 29 | _mockSerializer = A.Fake(opts => opts.Strict()); 30 | A.CallTo(() => _mockSerializer.SerializeEntity(A.Ignored)) 31 | .Returns("{}"); 32 | 33 | A.CallTo(() => _mockSerializer.SerializeEntityToNameValueList(A.Ignored)) 34 | .Returns("[]"); 35 | 36 | A.CallTo(() => _mockSerializer.DeserializeEntity(A.Ignored)) 37 | .Returns(new LineItemHubSpotEntity()); 38 | 39 | _client = new HubSpotLineItemClient( 40 | _mockHttpClient, 41 | Logger, 42 | _mockSerializer, 43 | "https://api.hubapi.com", 44 | "HapiKeyFisk" 45 | ); 46 | } 47 | 48 | private HttpResponseMessage CreateNewEmptyOkResponse() 49 | { 50 | var response = new HttpResponseMessage(HttpStatusCode.OK) 51 | { 52 | Content = new JsonContent("{}") 53 | }; 54 | return response; 55 | } 56 | 57 | [Theory] 58 | [InlineData(HubSpotAction.Create, "/crm-objects/v1/objects/line_items")] 59 | [InlineData(HubSpotAction.CreateBatch, "/crm-objects/v1/objects/line_items/batch-create")] 60 | [InlineData(HubSpotAction.Get, "/crm-objects/v1/objects/line_items/:lineItemId:")] 61 | [InlineData(HubSpotAction.List, "/crm-objects/v1/objects/line_items/paged")] 62 | [InlineData(HubSpotAction.Update, "/crm-objects/v1/objects/line_items/:lineItemId:")] 63 | [InlineData(HubSpotAction.UpdateBatch, "/crm-objects/v1/objects/line_items/batch-update")] 64 | [InlineData(HubSpotAction.Delete, "/crm-objects/v1/objects/line_items/:lineItemId:")] 65 | [InlineData(HubSpotAction.DeleteBatch, "/crm-objects/v1/objects/line_items/batch-delete")] 66 | [InlineData(HubSpotAction.ReadBatch, "/crm-objects/v1/objects/line_items/batch-read")] 67 | public void LineItemClient_path_resolver_works(HubSpotAction action, string expectedPath) 68 | { 69 | var resvoledPath = _client.PathResolver(new LineItemHubSpotEntity(), action); 70 | Assert.Equal(expectedPath, resvoledPath); 71 | } 72 | 73 | [Fact] 74 | public async Task LineItemClient_create_lineitem_works() 75 | { 76 | var response = await _client.CreateAsync(new LineItemHubSpotEntity 77 | { 78 | Name = "A new deal", 79 | Price = 12.50M, 80 | ProductId = "12345", 81 | Quantity = 10, 82 | }); 83 | 84 | A.CallTo(() => _mockHttpClient.SendAsync(A.Ignored)).MustHaveHappened(); 85 | A.CallTo(() => _mockSerializer.SerializeEntityToNameValueList(A.Ignored)).MustHaveHappened(); 86 | A.CallTo(() => _mockSerializer.DeserializeEntity("{}")).MustHaveHappened(); 87 | } 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /test/unit/Owner/HubSpotOwnerClientTest.cs: -------------------------------------------------------------------------------- 1 | using FakeItEasy; 2 | using RapidCore.Network; 3 | using Skarp.HubSpotClient.Core; 4 | using Skarp.HubSpotClient.Core.Requests; 5 | using Skarp.HubSpotClient.Owner; 6 | using Skarp.HubSpotClient.Owner.Dto; 7 | using System.Collections.Generic; 8 | using System.Linq; 9 | using System.Net; 10 | using System.Net.Http; 11 | using System.Threading.Tasks; 12 | using Xunit; 13 | using Xunit.Abstractions; 14 | 15 | namespace Skarp.HubSpotClient.UnitTest.Owner 16 | { 17 | public class HubSpotOwnerClientTest : UnitTestBase 18 | { 19 | private readonly HubSpotOwnerClient _client; 20 | private readonly IRapidHttpClient _mockHttpClient; 21 | private readonly RequestSerializer _mockSerializer; 22 | 23 | public HubSpotOwnerClientTest(ITestOutputHelper output) : base(output) 24 | { 25 | _mockHttpClient = A.Fake(opts => opts.Strict()); 26 | 27 | A.CallTo(() => _mockHttpClient.SendAsync(A.Ignored)) 28 | .Returns(Task.FromResult(CreateNewEmptyOkResponse())); 29 | 30 | _mockSerializer = A.Fake(opts => opts.Strict()); 31 | A.CallTo(() => _mockSerializer.SerializeEntity(A.Ignored)) 32 | .Returns("{}"); 33 | 34 | A.CallTo(() => _mockSerializer.DeserializeGenericEntity(A.Ignored)) 35 | .Returns(new OwnerHubSpotEntity()); 36 | 37 | A.CallTo(() => _mockSerializer.DeserializeGenericEntity>(A.Ignored)) 38 | .Returns(Enumerable.Empty()); 39 | 40 | A.CallTo(() => _mockSerializer.SerializeEntities(A>.Ignored)) 41 | .Returns("{}"); 42 | 43 | _client = new HubSpotOwnerClient( 44 | _mockHttpClient, 45 | Logger, 46 | _mockSerializer, 47 | "https://api.hubapi.com", 48 | "HapiKeyFisk" 49 | ); 50 | } 51 | 52 | private HttpResponseMessage CreateNewEmptyOkResponse() 53 | { 54 | var response = new HttpResponseMessage(HttpStatusCode.OK) 55 | { 56 | Content = new JsonContent("{}") 57 | }; 58 | return response; 59 | } 60 | 61 | [Theory] 62 | [InlineData(HubSpotAction.List, "/owners/v2/owners")] 63 | [InlineData(HubSpotAction.Get, "/owners/v2/owners/:ownerId:")] 64 | public void OwnerClient_path_resolver_works(HubSpotAction action, string expectedPath) 65 | { 66 | var resvoledPath = _client.PathResolver(new OwnerHubSpotEntity(), action); 67 | Assert.Equal(expectedPath, resvoledPath); 68 | } 69 | 70 | [Fact] 71 | public async Task OwnerClient_get_owner_by_id_long_works() 72 | { 73 | var response = await _client.GetByIdAsync(64); 74 | 75 | A.CallTo(() => _mockHttpClient.SendAsync(A.Ignored)).MustHaveHappened(); 76 | A.CallTo(() => _mockSerializer.DeserializeGenericEntity("{}")).MustHaveHappened(); 77 | } 78 | 79 | [Fact] 80 | public async Task OwnerClient_get_owner_by_id_string_works() 81 | { 82 | var response = await _client.GetByIdAsync("64"); 83 | 84 | A.CallTo(() => _mockHttpClient.SendAsync(A.Ignored)).MustHaveHappened(); 85 | A.CallTo(() => _mockSerializer.DeserializeGenericEntity("{}")).MustHaveHappened(); 86 | } 87 | 88 | [Fact] 89 | public async Task OwnerClient_list_owners_works() 90 | { 91 | var response = await _client.ListAsync( 92 | new OwnerListRequestOptions 93 | { 94 | IncludeInactive = true, 95 | Email = "owner@company.com" 96 | }); 97 | 98 | A.CallTo(() => _mockHttpClient.SendAsync(A.Ignored)).MustHaveHappened(); 99 | A.CallTo(() => _mockSerializer.DeserializeGenericEntity>("{}")).MustHaveHappened(); 100 | } 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /test/unit/UnitTestBase.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.Logging; 2 | using RapidCore.Xunit.Logging; 3 | using Xunit.Abstractions; 4 | 5 | namespace Skarp.HubSpotClient.UnitTest 6 | { 7 | public abstract class UnitTestBase 8 | { 9 | protected readonly ITestOutputHelper Output; 10 | protected readonly LoggerFactory LoggerFactory; 11 | protected readonly ILogger Logger; 12 | 13 | protected UnitTestBase(ITestOutputHelper output) 14 | { 15 | Output = output; 16 | LoggerFactory = new LoggerFactory(); 17 | LoggerFactory.AddXunitOutput(output); 18 | 19 | Logger = LoggerFactory.CreateLogger(); 20 | } 21 | } 22 | } -------------------------------------------------------------------------------- /test/unit/unit.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | net6.0 4 | false 5 | Skarp.HubSpotClient.UnitTest 6 | Skarp.HubSpotClient.UnitTest 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | runtime; build; native; contentfiles; analyzers; buildtransitive 16 | all 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | --------------------------------------------------------------------------------