Repository: amp-labs/connectors
Pull request #92 (2024-03-14 21:33:07)

chore(deps): bump github.com/spyzhov/ajson from 0.9.0 to 0.9.1
Bumps [github.com/spyzhov/ajson](https://github.com/spyzhov/ajson) from 0.9.0 to 0.9.1.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a href="https://github.com/spyzhov/ajson/releases">github.com/spyzhov/ajson's releases</a>.</em></p>
<blockquote>
<h2>v0.9.1</h2>
<p>Fixed error handling for <code>cmd/ajson</code></p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a href="https://github.com/spyzhov/ajson/commit/2f5aaeae25d9fc0cc086389f10785d88433e9eff"><code>2f5aaea</code></a> Fix error handling in cmd (<a href="https://redirect.github.com/spyzhov/ajson/issues/66">#66</a>)</li>
<li>See full diff in <a href="https://github.com/spyzhov/ajson/compare/v0.9.0...v0.9.1">compare view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=github.com/spyzhov/ajson&package-manager=go_modules&previous-version=0.9.0&new-version=0.9.1)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)


</details>


Patch:
diff --git a/go.mod b/go.mod
index 51344f73..98da7900 100644
--- a/go.mod
+++ b/go.mod
@@ -6,7 +6,7 @@ require (
 	github.com/brianvoe/gofakeit/v6 v6.28.0
 	github.com/go-playground/validator v9.31.0+incompatible
 	github.com/joho/godotenv v1.5.1
-	github.com/spyzhov/ajson v0.9.0
+	github.com/spyzhov/ajson v0.9.1
 	github.com/stretchr/testify v1.9.0
 	github.com/subchen/go-xmldom v1.1.2
 	golang.org/x/oauth2 v0.18.0
diff --git a/go.sum b/go.sum
index fa6a8675..7f0999b8 100644
--- a/go.sum
+++ b/go.sum
@@ -23,8 +23,8 @@ github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ=
 github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI=
 github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
 github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
-github.com/spyzhov/ajson v0.9.0 h1:tF46gJGOenYVj+k9K1U1XpCxVWhmiyY5PsVCAs1+OJ0=
-github.com/spyzhov/ajson v0.9.0/go.mod h1:a6oSw0MMb7Z5aD2tPoPO+jq11ETKgXUr2XktHdT8Wt8=
+github.com/spyzhov/ajson v0.9.1 h1:izsDkOC9yznlpA2BxJcrkr8Q5Gyjf43yeSc2Wz0g/aU=
+github.com/spyzhov/ajson v0.9.1/go.mod h1:a6oSw0MMb7Z5aD2tPoPO+jq11ETKgXUr2XktHdT8Wt8=
 github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
 github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
 github.com/subchen/go-xmldom v1.1.2 h1:7evI2YqfYYOnuj+PBwyaOZZYjl3iWq35P6KfBUw9jeU=
diff --git a/providers/catalog.go b/providers/catalog.go
index d67fe62c..866ed756 100644
--- a/providers/catalog.go
+++ b/providers/catalog.go
@@ -10,11 +10,14 @@ const (
 	LinkedIn   Provider = "linkedIn"
 	Salesloft  Provider = "salesloft"
 	Outreach   Provider = "outreach"
+	Sellsy     Provider = "sellsy"
+	Attio      Provider = "attio"
 	Close      Provider = "close"
 	Keap       Provider = "keap"
 	Asana      Provider = "asana"
 	Dropbox    Provider = "dropbox"
 	Notion     Provider = "notion"
+	Gong       Provider = "gong"
 )
 
 // ================================================================================
@@ -31,6 +34,11 @@ var catalog = CatalogType{ // nolint:gochecknoglobals
 			TokenURL:                  "https://{{.workspace}}.my.salesforce.com/services/oauth2/token",
 			ExplicitScopesRequired:    false,
 			ExplicitWorkspaceRequired: true,
+			TokenMetadataFields: TokenMetadataFields{
+				ConsumerRefField:  "id",
+				WorkspaceRefField: "instance_url",
+				ScopesField:       "scope",
+			},
 		},
 		Support: Support{
 			BulkWrite: true,
@@ -73,6 +81,9 @@ var catalog = CatalogType{ // nolint:gochecknoglobals
 			TokenURL:                  "https://www.linkedin.com/oauth/v2/accessToken",
 			ExplicitScopesRequired:    true,
 			ExplicitWorkspaceRequired: false,
+			TokenMetadataFields: TokenMetadataFields{
+				ScopesField: "scope",
+			},
 		},
 		Support: Support{
 			BulkWrite: false,
@@ -83,7 +94,7 @@ var catalog = CatalogType{ // nolint:gochecknoglobals
 		},
 	},
 
-	// SalesLoft configuration
+	// Salesloft configuration
 	Salesloft: {
 		AuthType: Oauth2,
 		BaseURL:  "https://api.salesloft.com",
@@ -121,15 +132,52 @@ var catalog = CatalogType{ // nolint:gochecknoglobals
 		},
 	},
 
+	// Sellsy configuration
+	Sellsy: {
+		AuthType: Oauth2,
+		BaseURL:  "https://api.sellsy.com",
+		OauthOpts: OauthOpts{
+			AuthURL:                   "https://login.sellsy.com/oauth2/authorization",
+			TokenURL:                  "https://login.sellsy.com/oauth2/access-tokens",
+			ExplicitScopesRequired:    false,
+			ExplicitWorkspaceRequired: false,
+		},
+		Support: Support{
+			BulkWrite: false,
+			Proxy:     false,
+			Read:      false,
+			Subscribe: false,
+			Write:     false,
+		},
+	},
+
+	// Attio configuration
+	Attio: {
+		AuthType: Oauth2,
+		BaseURL:  "https://api.attio.com/api",
+		OauthOpts: OauthOpts{
+			AuthURL:                   "https://app.attio.com/authorize",
+			TokenURL:                  "https://app.attio.com/oauth/token",
+			ExplicitScopesRequired:    true,
+			ExplicitWorkspaceRequired: false,
+		},
+		Support: Support{
+			BulkWrite: false,
+			Proxy:     false,
+			Read:      false,
+			Subscribe: false,
+			Write:     false,
+		},
+	},
+
 	// Close configuration
 	Close: {
 		AuthType: Oauth2,
 		BaseURL:  "https://api.close.com/api",
 		OauthOpts: OauthOpts{
-
 			AuthURL:                   "https://app.close.com/oauth2/authorize",
-			TokenURL:                  "https://api.close.com/oauth2/token/",
-			ExplicitScopesRequired:    true,
+			TokenURL:                  "https://api.close.com/oauth2/token",
+			ExplicitScopesRequired:    false,
 			ExplicitWorkspaceRequired: false,
 		},
 		Support: Support{
@@ -146,7 +194,6 @@ var catalog = CatalogType{ // nolint:gochecknoglobals
 		BaseURL:  "https://api.infusionsoft.com",
 
 		OauthOpts: OauthOpts{
-
 			AuthURL:                   "https://accounts.infusionsoft.com/app/oauth/authorize",
 			TokenURL:                  "https://api.infusionsoft.com/token",
 			ExplicitScopesRequired:    false,
@@ -208,6 +255,10 @@ var catalog = CatalogType{ // nolint:gochecknoglobals
 			TokenURL:                  "https://api.notion.com/v1/oauth/token",
 			ExplicitScopesRequired:    false,
 			ExplicitWorkspaceRequired: false,
+			TokenMetadataFields: TokenMetadataFields{
+				ConsumerRefField:  "owner.user.id",
+				WorkspaceRefField: "workspace_id",
+			},
 		},
 		Support: Support{
 			BulkWrite: false,
@@ -217,4 +268,23 @@ var catalog = CatalogType{ // nolint:gochecknoglobals
 			Write:     false,
 		},
 	},
+
+	// Gong configuration
+	Gong: {
+		AuthType: Oauth2,
+		BaseURL:  "https://{{.workspace}}.api.gong.io",
+		OauthOpts: OauthOpts{
+			AuthURL:                   "https://app.gong.io/oauth2/authorize",
+			TokenURL:                  "https://app.gong.io/oauth2/generate-customer-token",
+			ExplicitScopesRequired:    true,
+			ExplicitWorkspaceRequired: false,
+		},
+		Support: Support{
+			BulkWrite: false,
+			Proxy:     false,
+			Read:      false,
+			Subscribe: false,
+			Write:     false,
+		},
+	},
 }
diff --git a/providers/types.gen.go b/providers/types.gen.go
index 7147fe64..cdb00f36 100644
--- a/providers/types.gen.go
+++ b/providers/types.gen.go
@@ -16,10 +16,11 @@ type CatalogType map[string]ProviderInfo
 
 // OauthOpts defines model for OauthOpts.
 type OauthOpts struct {
-	AuthURL                   string `json:"authURL" validate:"required"`
-	ExplicitScopesRequired    bool   `json:"explicitScopesRequired"`
-	ExplicitWorkspaceRequired bool   `json:"explicitWorkspaceRequired"`
-	TokenURL                  string `json:"tokenURL" validate:"required"`
+	AuthURL                   string              `json:"authURL" validate:"required"`
+	ExplicitScopesRequired    bool                `json:"explicitScopesRequired"`
+	ExplicitWorkspaceRequired bool                `json:"explicitWorkspaceRequired"`
+	TokenMetadataFields       TokenMetadataFields `json:"tokenMetadataFields"`
+	TokenURL                  string              `json:"tokenURL" validate:"required"`
 }
 
 // Provider defines model for Provider.
@@ -45,3 +46,10 @@ type Support struct {
 	Subscribe bool `json:"subscribe"`
 	Write     bool `json:"write"`
 }
+
+// TokenMetadataFields defines model for TokenMetadataFields.
+type TokenMetadataFields struct {
+	ConsumerRefField  string `json:"consumerRefField,omitempty"`
+	ScopesField       string `json:"scopesField,omitempty"`
+	WorkspaceRefField string `json:"workspaceRefField,omitempty"`
+}
diff --git a/providers/types.yaml b/providers/types.yaml
index 90cb53e2..a344a1f4 100644
--- a/providers/types.yaml
+++ b/providers/types.yaml
@@ -42,6 +42,22 @@ components:
         write:
           type: boolean
 
+    TokenMetadataFields:
+      type: object
+      properties:
+        workspaceRefField:
+          type: string
+          example: account-id
+          x-go-type-skip-optional-pointer: true
+        consumerRefField:
+          type: string
+          example: user-id
+          x-go-type-skip-optional-pointer: true
+        scopesField:
+          type: string
+          example: scopes
+          x-go-type-skip-optional-pointer: true
+
     OauthOpts:
       type: object
       x-oapi-codegen-extra-tags:
@@ -51,6 +67,7 @@ components:
           - tokenURL
           - explicitScopesRequired
           - explicitWorkspaceRequired
+          - tokenMetadataFields
       properties:
         authURL:
           type: string
@@ -68,6 +85,8 @@ components:
         explicitWorkspaceRequired:
           type: boolean
           example: true
+        tokenMetadataFields:
+          $ref: '#/components/schemas/TokenMetadataFields'
 
     ProviderOpts:
         type: object


Test patch:
diff --git a/providers/catalog_test.go b/providers/catalog_test.go
index e1c382df..a7b0f294 100644
--- a/providers/catalog_test.go
+++ b/providers/catalog_test.go
@@ -34,6 +34,11 @@ var testCases = []struct { // nolint
 				TokenURL:                  "https://example.my.salesforce.com/services/oauth2/token",
 				ExplicitWorkspaceRequired: true,
 				ExplicitScopesRequired:    false,
+				TokenMetadataFields: TokenMetadataFields{
+					ConsumerRefField:  "id",
+					WorkspaceRefField: "instance_url",
+					ScopesField:       "scope",
+				},
 			},
 			BaseURL: "https://example.my.salesforce.com",
 			ProviderOpts: ProviderOpts{
@@ -88,6 +93,9 @@ var testCases = []struct { // nolint
 				TokenURL:                  "https://www.linkedin.com/oauth/v2/accessToken",
 				ExplicitScopesRequired:    true,
 				ExplicitWorkspaceRequired: false,
+				TokenMetadataFields: TokenMetadataFields{
+					ScopesField: "scope",
+				},
 			},
 			BaseURL: "https://api.linkedin.com",
 		},
@@ -150,6 +158,54 @@ var testCases = []struct { // nolint
 		expectedErr: nil,
 	},
 
+	{
+		provider: Sellsy,
+		expected: &ProviderInfo{
+			AuthType: Oauth2,
+			OauthOpts: OauthOpts{
+				AuthURL:                   "https://login.sellsy.com/oauth2/authorization",
+				TokenURL:                  "https://login.sellsy.com/oauth2/access-tokens",
+				ExplicitScopesRequired:    false,
+				ExplicitWorkspaceRequired: false,
+			},
+			Support: Support{
+				BulkWrite: false,
+				Proxy:     false,
+				Read:      false,
+				Subscribe: false,
+				Write:     false,
+			},
+			BaseURL: "https://api.sellsy.com",
+		},
+		expectedErr: nil,
+	},
+
+	{
+		provider:    Attio,
+		description: "Valid Attio provider config with non-existent substitutions",
+		substitutions: map[string]string{
+			"nonexistentvar": "abc",
+		},
+		expected: &ProviderInfo{
+			Support: Support{
+				Read:      false,
+				Write:     false,
+				BulkWrite: false,
+				Subscribe: false,
+				Proxy:     false,
+			},
+			AuthType: Oauth2,
+			OauthOpts: OauthOpts{
+				AuthURL:                   "https://app.attio.com/authorize",
+				TokenURL:                  "https://app.attio.com/oauth/token",
+				ExplicitScopesRequired:    true,
+				ExplicitWorkspaceRequired: false,
+			},
+			BaseURL: "https://api.attio.com/api",
+		},
+		expectedErr: nil,
+	},
+
 	{
 		provider:    Close,
 		description: "Valid Close provider config with no substitutions",
@@ -165,7 +221,7 @@ var testCases = []struct { // nolint
 			AuthType: Oauth2,
 			OauthOpts: OauthOpts{
 				AuthURL:                   "https://app.close.com/oauth2/authorize",
-				TokenURL:                  "https://api.close.com/oauth2/token/",
+				TokenURL:                  "https://api.close.com/oauth2/token",
 				ExplicitScopesRequired:    false,
 				ExplicitWorkspaceRequired: false,
 			},
@@ -236,7 +292,11 @@ var testCases = []struct { // nolint
 				Subscribe: false,
 				Write:     false,
 			},
-			BaseURL:  "https://api.dropboxapi.com/2/",
+			BaseURL: "https://api.dropboxapi.com/2/",
+		},
+		expectedErr: nil,
+	},
+	{
 		provider:    Notion,
 		description: "Valid Notion provider config with no substitutions",
 		expected: &ProviderInfo{
@@ -245,7 +305,7 @@ var testCases = []struct { // nolint
 				Write:     false,
 				BulkWrite: false,
 				Subscribe: false,
-				Proxy:     false,
+				Proxy:     true,
 			},
 			AuthType: Oauth2,
 			OauthOpts: OauthOpts{
@@ -253,11 +313,40 @@ var testCases = []struct { // nolint
 				TokenURL:                  "https://api.notion.com/v1/oauth/token",
 				ExplicitScopesRequired:    false,
 				ExplicitWorkspaceRequired: false,
+				TokenMetadataFields: TokenMetadataFields{
+					WorkspaceRefField: "workspace_id",
+					ConsumerRefField:  "owner.user.id",
+				},
 			},
 			BaseURL: "https://api.notion.com",
 		},
 		expectedErr: nil,
 	},
+	{
+		provider:    Gong,
+		description: "Gong provider config with valid substitutions",
+		substitutions: map[string]string{
+			"workspace": "testing",
+		},
+		expected: &ProviderInfo{
+			Support: Support{
+				Read:      false,
+				Write:     false,
+				BulkWrite: false,
+				Subscribe: false,
+				Proxy:     false,
+			},
+			AuthType: Oauth2,
+			OauthOpts: OauthOpts{
+				AuthURL:                   "https://app.gong.io/oauth2/authorize",
+				TokenURL:                  "https://app.gong.io/oauth2/generate-customer-token",
+				ExplicitWorkspaceRequired: false,
+				ExplicitScopesRequired:    true,
+			},
+			BaseURL: "https://testing.api.gong.io",
+		},
+		expectedErr: nil,
+	},
 }
 
 func TestReadInfo(t *testing.T) { // nolint