Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add API integrations for contact and deals #36

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
111 changes: 57 additions & 54 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,69 +1,72 @@
# General
SHELL := bash
.SHELLFLAGS := -eu -o pipefail -c
.DEFAULT_GOAL := help
# Use default shell BASH.
SHELL_PATH := /bin/bash
SHELL := /usr/bin/env bash

BIN := $(CURDIR)/.bin
TOOLS := $(CURDIR)/tools
PATH := $(abspath $(BIN)):$(PATH)
# ==============================================================================
# Define dependencies

UNAME_OS := $(shell uname -s)
UNAME_ARCH := $(shell uname -m)
NAME := go-hubspot
GOBIN := $$HOME/go/bin
GOVULNCHECK := $(GOBIN)/govulncheck
STATICCHECK := $(GOBIN)/staticcheck
TOOLS := tools

$(BIN):
mkdir -p $(BIN)
# ==============================================================================
# Defining all make targets

.PHONY: os
os: ## show os name
@echo "$(UNAME_OS)"
.DEFAULT_GOAL := all

.PHONY: help
help: ## print help
@grep -E '^[/a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-20s\033[0m %s\n", $$1, $$2}'
.PHONY: all
all: update fmt lint vulncheck tidy test

# Go
.PHONY: fmt
fmt:
@echo "-- Formatting Go files --"
gofmt -w -s . && \
gofmt -w -s legacy && \
goimports -local github.com/belong-inc/go-hubspot -w .

.PHONY: mod
mod: ## download Go modules
go mod download
.PHONY: generate
generate: ## generate go code (e.g. make generate OBJECT=Contact FILEPATH=contact.csv)
@cd $(TOOLS)/model_generator && go run model_gen.go $(OBJECT) $(FILEPATH)
$(MAKE) fmt

.PHONY: vendor
vendor: ## make go vendor
go mod vendor
.PHONY: lint
lint:
@echo "-- Lint check for Go files --"
go mod tidy
golangci-lint run
CGO_ENABLED=0 go vet ./...

.PHONY: test
test: ## run go test. If you need test options, pass them in like OPTIONS="-v"
go test ./... $(OPTIONS)
.PHONY: staticcheck
staticcheck:
$(STATICCHECK) -checks=all ./...

# Install golangci-lint
GOLANGCLI_LINT := $(BIN)/golangci-lint
GOLANGCLI_LINT_VERSION := v1.51.0
$(GOLANGCLI_LINT): | $(BIN) ## Install golangci-lint
@curl -sSfL "https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh" | sh -s -- -b $(BIN) $(GOLANGCLI_LINT_VERSION)
@chmod +x "$(BIN)/golangci-lint"
.PHONY: vulncheck
vulncheck:
$(GOVULNCHECK) ./...

.PHONY: lint
lint: | $(GOLANGCLI_LINT) ## run golangci-lint with config .golangcli.yml
$(BIN)/golangci-lint run --verbose --config=.golangci.yml ./...
.PHONY: update
update:
go get -u ./...

# Install gofumpt
# This setting is only available for Mac
GOFMPT := $(BIN)/gofumpt
GOFMPT_VERSION := v0.4.0
ifeq "$(UNAME_OS)" "Darwin"
GOFMPT_BIN=gofumpt_$(GOFMPT_VERSION)_darwin_amd64
endif
.PHONY: tidy
tidy:
@echo "-- Tidying Go modules --"
go mod tidy

$(GOFMPT): | $(BIN) ## Install gofumpt
@curl -sSfL "https://github.com/mvdan/gofumpt/releases/download/$(GOFMPT_VERSION)/$(GOFMPT_BIN)" \
-o "$(BIN)/gofumpt"
@chmod +x "$(BIN)/gofumpt"
.PHONY: clean
clean:
@echo " -- Cleaning Go files --"
@go clean -cache -testcache -modcache
@rm $(GO_DIR)/*.zip

.PHONY: fmt
fmt: | $(GOFMPT) ## format files via gofumpt and list impacted files
@$(BIN)/gofumpt -l -w . ./legacy
.PHONY: build
build:
@echo "-- Building binaries --"
go build -v ./...

.PHONY: generate
generate: ## generate go code (e.g. make generate OBJECT=Contact FILEPATH=contact.csv)
@cd $(TOOLS)/model_generator && go run model_gen.go $(OBJECT) $(FILEPATH)
$(MAKE) fmt
.PHONY:
test: build
@echo "-- Running tests --"
CGO_ENABLED=1 go test ./...
8 changes: 5 additions & 3 deletions auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,11 @@ func SetAPIKey(key string) AuthMethod {
}
}

func SetPrivateAppToken(token string) AuthMethod {
func SetPrivateAppToken(token, secret string) AuthMethod {
return func(c *Client) {
c.authenticator = &PrivateAppToken{
accessToken: token,
accessToken: token,
clientSecret: secret,
}
}
}
Expand Down Expand Up @@ -65,7 +66,8 @@ func (a *APIKey) SetAuthentication(r *http.Request) error {
}

type PrivateAppToken struct {
accessToken string
accessToken string
clientSecret string
}

func (p *PrivateAppToken) SetAuthentication(r *http.Request) error {
Expand Down
14 changes: 7 additions & 7 deletions company_model.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

15 changes: 8 additions & 7 deletions company_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,9 @@ import (
"reflect"
"testing"

"github.com/belong-inc/go-hubspot"
"github.com/google/go-cmp/cmp"

"github.com/belong-inc/go-hubspot"
)

func TestCompanyServiceOp_Create(t *testing.T) {
Expand Down Expand Up @@ -71,7 +72,7 @@ func TestCompanyServiceOp_Create(t *testing.T) {
client: hubspot.NewMockClient(&hubspot.MockConfig{
Status: http.StatusBadRequest,
Header: http.Header{},
Body: []byte(`{"message": "Invalid input (details will vary based on the error)","correlationId": "aeb5f871-7f07-4993-9211-075dc63e7cbf","category": "VALIDATION_ERROR","links": {"knowledge-base": "https://www.hubspot.com/products/service/knowledge-base"}}`),
Body: []byte(`{"message": "Invalid input (details will vary based on the error)","correlationID": "aeb5f871-7f07-4993-9211-075dc63e7cbf","category": "VALIDATION_ERROR","links": {"knowledge-base": "https://www.hubspot.com/products/service/knowledge-base"}}`),
}),
},
args: args{
Expand Down Expand Up @@ -166,7 +167,7 @@ func TestCompanyServiceOp_Update(t *testing.T) {
client: hubspot.NewMockClient(&hubspot.MockConfig{
Status: http.StatusBadRequest,
Header: http.Header{},
Body: []byte(`{"message": "Invalid input (details will vary based on the error)","correlationId": "aeb5f871-7f07-4993-9211-075dc63e7cbf","category": "VALIDATION_ERROR","links": {"knowledge-base": "https://www.hubspot.com/products/service/knowledge-base"}}`),
Body: []byte(`{"message": "Invalid input (details will vary based on the error)","correlationID": "aeb5f871-7f07-4993-9211-075dc63e7cbf","category": "VALIDATION_ERROR","links": {"knowledge-base": "https://www.hubspot.com/products/service/knowledge-base"}}`),
}),
},
args: args{
Expand Down Expand Up @@ -256,7 +257,7 @@ func TestCompanyServiceOp_Get(t *testing.T) {
Name: hubspot.NewString("Biglytics"),
Phone: hubspot.NewString("(877)929-0687"),
State: hubspot.NewString("Massachusetts"),
HsCreatedByUserId: hubspot.NewInt(0),
HsCreatedByUserID: hubspot.NewInt(0),
},
CustomName: hubspot.NewString("biglytics"),
CustomDate: &createdAt,
Expand Down Expand Up @@ -301,7 +302,7 @@ func TestCompanyServiceOp_Get(t *testing.T) {
Name: hubspot.NewString("Biglytics"),
Phone: hubspot.NewString("(877)929-0687"),
State: hubspot.NewString("Massachusetts"),
HsCreatedByUserId: hubspot.NewInt(0),
HsCreatedByUserID: hubspot.NewInt(0),
},
CustomName: hubspot.NewString("biglytics"),
CustomDate: &createdAt,
Expand All @@ -318,7 +319,7 @@ func TestCompanyServiceOp_Get(t *testing.T) {
client: hubspot.NewMockClient(&hubspot.MockConfig{
Status: http.StatusBadRequest,
Header: http.Header{},
Body: []byte(`{"message": "Invalid input (details will vary based on the error)","correlationId": "aeb5f871-7f07-4993-9211-075dc63e7cbf","category": "VALIDATION_ERROR","links": {"knowledge-base": "https://www.hubspot.com/products/service/knowledge-base"}}`),
Body: []byte(`{"message": "Invalid input (details will vary based on the error)","correlationID": "aeb5f871-7f07-4993-9211-075dc63e7cbf","category": "VALIDATION_ERROR","links": {"knowledge-base": "https://www.hubspot.com/products/service/knowledge-base"}}`),
}),
},
args: args{
Expand Down Expand Up @@ -386,7 +387,7 @@ func TestCompanyServiceOp_Delete(t *testing.T) {
client: hubspot.NewMockClient(&hubspot.MockConfig{
Status: http.StatusBadRequest,
Header: http.Header{},
Body: []byte(`{"message": "Invalid input (details will vary based on the error)","correlationId": "aeb5f871-7f07-4993-9211-075dc63e7cbf","category": "VALIDATION_ERROR","links": {"knowledge-base": "https://www.hubspot.com/products/service/knowledge-base"}}`),
Body: []byte(`{"message": "Invalid input (details will vary based on the error)","correlationID": "aeb5f871-7f07-4993-9211-075dc63e7cbf","category": "VALIDATION_ERROR","links": {"knowledge-base": "https://www.hubspot.com/products/service/knowledge-base"}}`),
}),
},
args: args{
Expand Down
48 changes: 48 additions & 0 deletions contact.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ type ContactService interface {
Update(contactID string, contact interface{}) (*ResponseResource, error)
Delete(contactID string) error
AssociateAnotherObj(contactID string, conf *AssociationConfig) (*ResponseResource, error)
SearchByEmail(email string) (*ContactSearchResponse, error)
}

// ContactServiceOp handles communication with the product related methods of the HubSpot API.
Expand All @@ -24,6 +25,29 @@ type ContactServiceOp struct {

var _ ContactService = (*ContactServiceOp)(nil)

// ContactSearchRequest represents the request body for searching contacts.
type ContactSearchRequest struct {
FilterGroups []FilterGroup `json:"filterGroups"`
}

// FilterGroup represents a group of filters.
type FilterGroup struct {
Filters []Filter `json:"filters"`
}

// Filter represents a single filter.
type Filter struct {
PropertyName string `json:"propertyName"`
Operator string `json:"operator"`
Values []string `json:"values,omitempty"`
Value string `json:"value,omitempty"`
}

// ContactSearchResponse represents the response from searching contacts.
type ContactSearchResponse struct {
Results []Contact `json:"results"`
}

type Contact struct {
Address *HsStr `json:"address,omitempty"`
AnnualRevenue *HsStr `json:"annualrevenue,omitempty"`
Expand Down Expand Up @@ -367,3 +391,27 @@ func (s *ContactServiceOp) AssociateAnotherObj(contactID string, conf *Associati
}
return resource, nil
}

// SearchByEmail searches for a contact by email.
func (s *ContactServiceOp) SearchByEmail(email string) (*ContactSearchResponse, error) {
req := &ContactSearchRequest{
FilterGroups: []FilterGroup{
{
Filters: []Filter{
{
PropertyName: "email",
Operator: "EQ",
Value: email,
},
},
},
},
}

resource := &ContactSearchResponse{}
if err := s.client.Post(s.contactPath+"/search", req, resource); err != nil {
return nil, err
}

return resource, nil
}
11 changes: 6 additions & 5 deletions contact_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,9 @@ import (
"reflect"
"testing"

"github.com/belong-inc/go-hubspot"
"github.com/google/go-cmp/cmp"

"github.com/belong-inc/go-hubspot"
)

func TestContactServiceOp_Create(t *testing.T) {
Expand Down Expand Up @@ -70,7 +71,7 @@ func TestContactServiceOp_Create(t *testing.T) {
client: hubspot.NewMockClient(&hubspot.MockConfig{
Status: http.StatusBadRequest,
Header: http.Header{},
Body: []byte(`{"message": "Invalid input (details will vary based on the error)","correlationId": "aeb5f871-7f07-4993-9211-075dc63e7cbf","category": "VALIDATION_ERROR","links": {"knowledge-base": "https://www.hubspot.com/products/service/knowledge-base"}}`),
Body: []byte(`{"message": "Invalid input (details will vary based on the error)","correlationID": "aeb5f871-7f07-4993-9211-075dc63e7cbf","category": "VALIDATION_ERROR","links": {"knowledge-base": "https://www.hubspot.com/products/service/knowledge-base"}}`),
}),
},
args: args{
Expand Down Expand Up @@ -164,7 +165,7 @@ func TestContactServiceOp_Update(t *testing.T) {
client: hubspot.NewMockClient(&hubspot.MockConfig{
Status: http.StatusBadRequest,
Header: http.Header{},
Body: []byte(`{"message": "Invalid input (details will vary based on the error)","correlationId": "aeb5f871-7f07-4993-9211-075dc63e7cbf","category": "VALIDATION_ERROR","links": {"knowledge-base": "https://www.hubspot.com/products/service/knowledge-base"}}`),
Body: []byte(`{"message": "Invalid input (details will vary based on the error)","correlationID": "aeb5f871-7f07-4993-9211-075dc63e7cbf","category": "VALIDATION_ERROR","links": {"knowledge-base": "https://www.hubspot.com/products/service/knowledge-base"}}`),
}),
},
args: args{
Expand Down Expand Up @@ -571,7 +572,7 @@ func TestContactServiceOp_Get(t *testing.T) {
client: hubspot.NewMockClient(&hubspot.MockConfig{
Status: http.StatusBadRequest,
Header: http.Header{},
Body: []byte(`{"message": "Invalid input (details will vary based on the error)","correlationId": "aeb5f871-7f07-4993-9211-075dc63e7cbf","category": "VALIDATION_ERROR","links": {"knowledge-base": "https://www.hubspot.com/products/service/knowledge-base"}}`),
Body: []byte(`{"message": "Invalid input (details will vary based on the error)","correlationID": "aeb5f871-7f07-4993-9211-075dc63e7cbf","category": "VALIDATION_ERROR","links": {"knowledge-base": "https://www.hubspot.com/products/service/knowledge-base"}}`),
}),
},
args: args{
Expand Down Expand Up @@ -640,7 +641,7 @@ func TestContactServiceOp_Delete(t *testing.T) {
client: hubspot.NewMockClient(&hubspot.MockConfig{
Status: http.StatusBadRequest,
Header: http.Header{},
Body: []byte(`{"message": "Invalid input (details will vary based on the error)","correlationId": "aeb5f871-7f07-4993-9211-075dc63e7cbf","category": "VALIDATION_ERROR","links": {"knowledge-base": "https://www.hubspot.com/products/service/knowledge-base"}}`),
Body: []byte(`{"message": "Invalid input (details will vary based on the error)","correlationID": "aeb5f871-7f07-4993-9211-075dc63e7cbf","category": "VALIDATION_ERROR","links": {"knowledge-base": "https://www.hubspot.com/products/service/knowledge-base"}}`),
}),
},
args: args{
Expand Down
8 changes: 4 additions & 4 deletions conversation.go
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
package hubspot

const (
visitorIdentificationBasePath = "/conversations/v3/visitor-identification"
visitorIDentificationBasePath = "/conversations/v3/visitor-identification"
)

type Conversation struct {
VisitorIdentification VisitorIdentificationService
VisitorIDentification VisitorIDentificationService
}

func newConversation(c *Client) *Conversation {
return &Conversation{
VisitorIdentification: &VisitorIdentificationServiceOp{
VisitorIDentification: &VisitorIDentificationServiceOp{
client: c,
basePath: visitorIdentificationBasePath,
basePath: visitorIDentificationBasePath,
},
}
}
Loading