Skip to content

Commit

Permalink
Merge pull request #62 from wakflo/feature/web-728-hubspot-connector
Browse files Browse the repository at this point in the history
feat: implement hubspot connector
  • Loading branch information
jaymesC authored Nov 7, 2024
2 parents 359dafc + 71fc52c commit 22372ad
Show file tree
Hide file tree
Showing 15 changed files with 1,198 additions and 0 deletions.
2 changes: 2 additions & 0 deletions connectors.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ import (
"github.com/wakflo/extensions/internal/connectors/googlemail"
"github.com/wakflo/extensions/internal/connectors/goscript"
"github.com/wakflo/extensions/internal/connectors/harvest"
"github.com/wakflo/extensions/internal/connectors/hubspot"
"github.com/wakflo/extensions/internal/connectors/javascript"
"github.com/wakflo/extensions/internal/connectors/jiracloud"
"github.com/wakflo/extensions/internal/connectors/jsonconverter"
Expand Down Expand Up @@ -112,6 +113,7 @@ func RegisterConnectors() []*sdk.ConnectorPlugin {
monday.NewConnector, // Monday.com
zoom.NewConnector, // Zoom
flexport.NewConnector, // Flexport
hubspot.NewConnector, // Hubspot
jiracloud.NewConnector, // Jira Cloud
prisync.NewConnector, // Prisync
github.NewConnector, // Github
Expand Down
46 changes: 46 additions & 0 deletions internal/connectors/hubspot/lib.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
// Copyright 2022-present Wakflo
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package hubspot

import (
sdk "github.com/wakflo/go-sdk/connector"
)

func NewConnector() (*sdk.ConnectorPlugin, error) {
return sdk.CreateConnector(&sdk.CreateConnectorArgs{
Name: "Hubspot",
Description: "Powerful CRM that offers tools for sales, customer service, and marketing automation.",
Logo: "logos:hubspot",
Version: "0.0.1",
Group: sdk.ConnectorGroupApps,
Authors: []string{"Wakflo <integrations@wakflo.com>"},
Triggers: []sdk.ITrigger{
NewTicketCreated(),
NewContactCreated(),
NewCompanyCreated(),
NewDealCreated(),
NewTaskCreated(),
},
Operations: []sdk.IOperation{
NewCreateContactOperation(),
NewListContactsOperation(),
NewRetrieveContactOperation(),
NewCreateTicketOperation(),
NewListTicketsOperation(),
NewSearchOwnerByEmailOperation(),
NewSearchOwnerByEmailOperation(),
},
})
}
66 changes: 66 additions & 0 deletions internal/connectors/hubspot/model.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
package hubspot

import "time"

type contactRequest struct {
Properties map[string]interface{} `json:"properties"`
}

type ListResponse struct {
Lists []List `json:"lists"`
}

type List struct {
ProcessingType string `json:"processingType"`
ObjectTypeID string `json:"objectTypeId"`
UpdatedByID string `json:"updatedById"`
FiltersUpdatedAt time.Time `json:"filtersUpdatedAt"`
ListID string `json:"listId"`
CreatedAt time.Time `json:"createdAt"`
ProcessingStatus string `json:"processingStatus"`
DeletedAt time.Time `json:"deletedAt"`
ListVersion int `json:"listVersion"`
Size int `json:"size"`
Name string `json:"name"`
CreatedByID string `json:"createdById"`
FilterBranch FilterBranch `json:"filterBranch"`
UpdatedAt time.Time `json:"updatedAt"`
}

type FilterBranch struct {
FilterBranchType string `json:"filterBranchType"`
FilterBranches []FilterBranch `json:"filterBranches"`
FilterBranchOperator string `json:"filterBranchOperator"`
Filters []interface{} `json:"filters"`
}

type DealPipelineResponse struct {
Results []PipelineResult `json:"results"`
}

type PipelineResult struct {
CreatedAt time.Time `json:"createdAt"`
ArchivedAt time.Time `json:"archivedAt"`
Archived bool `json:"archived"`
DisplayOrder int `json:"displayOrder"`
Stages []Stage `json:"stages"`
Label string `json:"label"`
ID string `json:"id"`
UpdatedAt time.Time `json:"updatedAt"`
}

type Stage struct {
CreatedAt time.Time `json:"createdAt"`
ArchivedAt time.Time `json:"archivedAt"`
Archived bool `json:"archived"`
Metadata StageMetadata `json:"metadata"`
DisplayOrder int `json:"displayOrder"`
WritePermissions string `json:"writePermissions"`
Label string `json:"label"`
ID string `json:"id"`
UpdatedAt time.Time `json:"updatedAt"`
}

type StageMetadata struct {
TicketState string `json:"ticketState"`
}
103 changes: 103 additions & 0 deletions internal/connectors/hubspot/operation_create_contact.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
// Copyright 2022-present Wakflo
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package hubspot

import (
"encoding/json"
"net/http"

"github.com/wakflo/go-sdk/autoform"
sdk "github.com/wakflo/go-sdk/connector"
sdkcore "github.com/wakflo/go-sdk/core"
)

type createNewContactProps struct {
FirstName string `json:"firstname"`
LastName string `json:"lastname"`
Email string `json:"email"`
Zip string `json:"zip"`
}

type CreateContactOperation struct {
options *sdk.OperationInfo
}

func NewCreateContactOperation() *CreateContactOperation {
return &CreateContactOperation{
options: &sdk.OperationInfo{
Name: "Create new Contact",
Description: "Create new contact",
Auth: sharedAuth,
Input: map[string]*sdkcore.AutoFormSchema{
"firstname": autoform.NewShortTextField().
SetDisplayName("First Name").
SetDescription("First Name").
SetRequired(true).Build(),
"lastname": autoform.NewShortTextField().
SetDisplayName("Last Name").
SetDescription("Last name").
SetRequired(true).Build(),
"email": autoform.NewShortTextField().
SetDisplayName("Email").
SetDescription("Email").
SetRequired(false).Build(),
"zip": autoform.NewShortTextField().
SetDisplayName("Zip").
SetDescription("Zip Code").
SetRequired(false).Build(),
},
SampleOutput: map[string]interface{}{},
ErrorSettings: sdkcore.StepErrorSettings{
ContinueOnError: false,
RetryOnError: false,
},
RequireAuth: true,
},
}
}

func (c *CreateContactOperation) Run(ctx *sdk.RunContext) (sdk.JSON, error) {
input := sdk.InputToType[createNewContactProps](ctx)

contact := contactRequest{
Properties: map[string]interface{}{
"firstname": input.FirstName,
"lastname": input.LastName,
"email": input.Email,
"zip": input.Zip,
},
}

newContact, err := json.Marshal(contact)
if err != nil {
return nil, err
}

reqURL := "/crm/v3/objects/contacts"

resp, err := hubspotClient(reqURL, ctx.Auth.AccessToken, http.MethodPost, newContact)
if err != nil {
return nil, err
}
return resp, nil
}

func (c *CreateContactOperation) Test(ctx *sdk.RunContext) (sdk.JSON, error) {
return c.Run(ctx)
}

func (c *CreateContactOperation) GetInfo() *sdk.OperationInfo {
return c.options
}
101 changes: 101 additions & 0 deletions internal/connectors/hubspot/operation_create_ticket.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
// Copyright 2022-present Wakflo
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package hubspot

import (
"encoding/json"
"net/http"

"github.com/wakflo/go-sdk/autoform"
sdk "github.com/wakflo/go-sdk/connector"
sdkcore "github.com/wakflo/go-sdk/core"
)

type createNewTicketProps struct {
Subject string `json:"subject"`
Content string `json:"content"`
Priority string `json:"hs_ticket_priority"`
}

type CreateTicketOperation struct {
options *sdk.OperationInfo
}

func NewCreateTicketOperation() *CreateTicketOperation {
return &CreateTicketOperation{
options: &sdk.OperationInfo{
Name: "Create new Ticket",
Description: "Create new contact",
Auth: sharedAuth,
Input: map[string]*sdkcore.AutoFormSchema{
"subject": autoform.NewShortTextField().
SetDisplayName("Ticket Subject").
SetDescription("subject of the ticket to create").
SetRequired(true).Build(),
"content": autoform.NewShortTextField().
SetDisplayName("Ticket Description").
SetDescription("ticket description").
SetRequired(false).Build(),
"hs_ticket_priority": autoform.NewSelectField().
SetDisplayName("Format").
SetDescription("The format of the email to read").
SetOptions(hubspotPriority).
SetRequired(false).
Build(),
},
SampleOutput: map[string]interface{}{},
ErrorSettings: sdkcore.StepErrorSettings{
ContinueOnError: false,
RetryOnError: false,
},
RequireAuth: true,
},
}
}

func (c *CreateTicketOperation) Run(ctx *sdk.RunContext) (sdk.JSON, error) {
input := sdk.InputToType[createNewTicketProps](ctx)

ticket := contactRequest{
Properties: map[string]interface{}{
"subject": input.Subject,
"content": input.Content,
"hs_ticket_priority": input.Priority,
"hs_pipeline": "0",
"hs_pipeline_stage": "1",
},
}

newTicket, err := json.Marshal(ticket)
if err != nil {
return nil, err
}

reqURL := "/crm/v3/objects/tickets"

resp, err := hubspotClient(reqURL, ctx.Auth.AccessToken, http.MethodPost, newTicket)
if err != nil {
return nil, err
}
return resp, nil
}

func (c *CreateTicketOperation) Test(ctx *sdk.RunContext) (sdk.JSON, error) {
return c.Run(ctx)
}

func (c *CreateTicketOperation) GetInfo() *sdk.OperationInfo {
return c.options
}
Loading

0 comments on commit 22372ad

Please sign in to comment.