From 40aca7b17ccc090e360c2f6b7b768386979313cb Mon Sep 17 00:00:00 2001 From: Nguyen Doan Thanh <145089181+dtng95@users.noreply.github.com> Date: Fri, 20 Sep 2024 14:19:01 +0700 Subject: [PATCH 01/13] V14 Hubspot integration for Forms - update UI --- .../Client/config.outputPath.js | 2 +- .../Client/package-lock.json | 4 +- .../Client/package.json | 2 +- .../Client/public/umbraco-package.json | 3 +- .../Client/src/index.ts | 2 - ...raco.Forms.Integrations.Crm.Hubspot.csproj | 10 +-- .../Microsoft.AspNetCore.ClientAssets.targets | 61 +++++++++++++++++++ ...aco.Forms.Integrations.Crm.Hubspot.targets | 29 --------- 8 files changed, 69 insertions(+), 44 deletions(-) create mode 100644 src/Umbraco.Forms.Integrations.Crm.Hubspot/build/Microsoft.AspNetCore.ClientAssets.targets delete mode 100644 src/Umbraco.Forms.Integrations.Crm.Hubspot/build/Umbraco.Forms.Integrations.Crm.Hubspot.targets diff --git a/src/Umbraco.Forms.Integrations.Crm.Hubspot/Client/config.outputPath.js b/src/Umbraco.Forms.Integrations.Crm.Hubspot/Client/config.outputPath.js index af43f9b..ebdac79 100644 --- a/src/Umbraco.Forms.Integrations.Crm.Hubspot/Client/config.outputPath.js +++ b/src/Umbraco.Forms.Integrations.Crm.Hubspot/Client/config.outputPath.js @@ -1 +1 @@ -export const outputPath = 'Debug' !== 'Release' ? '../wwwroot' : '../obj/Debug/net8.0/clientassets' \ No newline at end of file +export const outputPath = 'Debug' !== 'Release' ? '../wwwroot' : '../obj/Debug/net8.0/clientassets' diff --git a/src/Umbraco.Forms.Integrations.Crm.Hubspot/Client/package-lock.json b/src/Umbraco.Forms.Integrations.Crm.Hubspot/Client/package-lock.json index 1b90c9e..96a75f0 100644 --- a/src/Umbraco.Forms.Integrations.Crm.Hubspot/Client/package-lock.json +++ b/src/Umbraco.Forms.Integrations.Crm.Hubspot/Client/package-lock.json @@ -1,11 +1,11 @@ { - "name": "hubspot", + "name": "hubspot-crm", "version": "0.0.0", "lockfileVersion": 3, "requires": true, "packages": { "": { - "name": "hubspot", + "name": "hubspot-crm", "version": "0.0.0", "dependencies": { "lit": "^3.2.0" diff --git a/src/Umbraco.Forms.Integrations.Crm.Hubspot/Client/package.json b/src/Umbraco.Forms.Integrations.Crm.Hubspot/Client/package.json index e05a534..ae9b190 100644 --- a/src/Umbraco.Forms.Integrations.Crm.Hubspot/Client/package.json +++ b/src/Umbraco.Forms.Integrations.Crm.Hubspot/Client/package.json @@ -1,5 +1,5 @@ { - "name": "hubspot", + "name": "hubspot-crm", "private": true, "version": "0.0.0", "type": "module", diff --git a/src/Umbraco.Forms.Integrations.Crm.Hubspot/Client/public/umbraco-package.json b/src/Umbraco.Forms.Integrations.Crm.Hubspot/Client/public/umbraco-package.json index a389b0b..5f18b74 100644 --- a/src/Umbraco.Forms.Integrations.Crm.Hubspot/Client/public/umbraco-package.json +++ b/src/Umbraco.Forms.Integrations.Crm.Hubspot/Client/public/umbraco-package.json @@ -6,7 +6,8 @@ { "name": "Umbraco EntryPoint", "alias": "Umb.Hubspot.EntryPoint", - "type": "entryPoint" + "type": "entryPoint", + "js": "/App_Plugins/HubSpot/hubspot-crm.js" } ] } \ No newline at end of file diff --git a/src/Umbraco.Forms.Integrations.Crm.Hubspot/Client/src/index.ts b/src/Umbraco.Forms.Integrations.Crm.Hubspot/Client/src/index.ts index 62cc97e..184adc0 100644 --- a/src/Umbraco.Forms.Integrations.Crm.Hubspot/Client/src/index.ts +++ b/src/Umbraco.Forms.Integrations.Crm.Hubspot/Client/src/index.ts @@ -6,8 +6,6 @@ import { manifests as localizationManifests } from "./lang/manifests.js"; import { OpenAPI } from "@umbraco-integrations/hubspot/generated"; -// export * from "./property-editor/index.js"; - export const onInit: UmbEntryPointOnInit = (host, extensionRegistry) => { extensionRegistry.registerMany([ hubspotContext, diff --git a/src/Umbraco.Forms.Integrations.Crm.Hubspot/Umbraco.Forms.Integrations.Crm.Hubspot.csproj b/src/Umbraco.Forms.Integrations.Crm.Hubspot/Umbraco.Forms.Integrations.Crm.Hubspot.csproj index 51e6c95..a224fed 100644 --- a/src/Umbraco.Forms.Integrations.Crm.Hubspot/Umbraco.Forms.Integrations.Crm.Hubspot.csproj +++ b/src/Umbraco.Forms.Integrations.Crm.Hubspot/Umbraco.Forms.Integrations.Crm.Hubspot.csproj @@ -6,6 +6,7 @@ enable true false + /App_Plugins/HubSpot @@ -36,13 +37,6 @@ - - - True - buildTransitive - - - true @@ -59,7 +53,7 @@ - + true diff --git a/src/Umbraco.Forms.Integrations.Crm.Hubspot/build/Microsoft.AspNetCore.ClientAssets.targets b/src/Umbraco.Forms.Integrations.Crm.Hubspot/build/Microsoft.AspNetCore.ClientAssets.targets new file mode 100644 index 0000000..5a3af6b --- /dev/null +++ b/src/Umbraco.Forms.Integrations.Crm.Hubspot/build/Microsoft.AspNetCore.ClientAssets.targets @@ -0,0 +1,61 @@ + + + + Client\ + $(ClientAssetsDirectory)\package-lock.json;$(ClientAssetsDirectory)\package.json + $(ClientAssetsDirectory)node_modules\.package-lock.json + npm ci --no-fund --no-audit --prefer-offline + npm run build + + + $(MSBuildProjectFile);$(ClientAssetsRestoreInputs) + + DispatchToInnerBuilds + + true + + + + + + + + + + + + + + <_ClientAssetsOutputFullPath>$([System.IO.Path]::GetFullPath('$(IntermediateOutputPath)clientassets')) + + + + + + + + + <_ClientAssetsBuildOutput Include="$(IntermediateOutputPath)clientassets\**"> + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/Umbraco.Forms.Integrations.Crm.Hubspot/build/Umbraco.Forms.Integrations.Crm.Hubspot.targets b/src/Umbraco.Forms.Integrations.Crm.Hubspot/build/Umbraco.Forms.Integrations.Crm.Hubspot.targets deleted file mode 100644 index e7d6ae4..0000000 --- a/src/Umbraco.Forms.Integrations.Crm.Hubspot/build/Umbraco.Forms.Integrations.Crm.Hubspot.targets +++ /dev/null @@ -1,29 +0,0 @@ - - - - $(MSBuildThisFileDirectory)..\App_Plugins\UmbracoForms.Integrations\Crm\Hubspot\**\*.* - - - - - - - - - - - - - - - - - - - - From 10b067c04085f8ed643611033c2f624554f9579a Mon Sep 17 00:00:00 2001 From: Nguyen Doan Thanh <145089181+dtng95@users.noreply.github.com> Date: Fri, 20 Sep 2024 15:51:55 +0700 Subject: [PATCH 02/13] V14: Integrations (HubSpot/Forms) - Update UI --- .../Client/src/lang/manifests.ts | 2 +- .../src/property-editor/hubspot-mapping.property-editor.ts | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/Umbraco.Forms.Integrations.Crm.Hubspot/Client/src/lang/manifests.ts b/src/Umbraco.Forms.Integrations.Crm.Hubspot/Client/src/lang/manifests.ts index 072c062..7cfabfb 100644 --- a/src/Umbraco.Forms.Integrations.Crm.Hubspot/Client/src/lang/manifests.ts +++ b/src/Umbraco.Forms.Integrations.Crm.Hubspot/Client/src/lang/manifests.ts @@ -3,7 +3,7 @@ import type { ManifestLocalization } from "@umbraco-cms/backoffice/extension-reg const localizationManifests: Array = [ { type: "localization", - alias: "Forms.Localization.En", + alias: "Hubspot.Localization.En", weight: -100, name: "English (US)", meta: { diff --git a/src/Umbraco.Forms.Integrations.Crm.Hubspot/Client/src/property-editor/hubspot-mapping.property-editor.ts b/src/Umbraco.Forms.Integrations.Crm.Hubspot/Client/src/property-editor/hubspot-mapping.property-editor.ts index 496c2b0..193d020 100644 --- a/src/Umbraco.Forms.Integrations.Crm.Hubspot/Client/src/property-editor/hubspot-mapping.property-editor.ts +++ b/src/Umbraco.Forms.Integrations.Crm.Hubspot/Client/src/property-editor/hubspot-mapping.property-editor.ts @@ -7,7 +7,11 @@ const elementName = "hubspot-mapping-property-editor"; @customElement(elementName) export class HubspotMappingPropertyUiElement extends UmbLitElement implements UmbPropertyEditorUiElement { render() { - return html`
ABCD
`; + return html` +
+ +
+ `; } } From 3e8c892affaf4d5fb810512ce1e2991c249b1b6a Mon Sep 17 00:00:00 2001 From: Nguyen Doan Thanh <145089181+dtng95@users.noreply.github.com> Date: Fri, 20 Sep 2024 17:49:01 +0700 Subject: [PATCH 03/13] Update hubspot-mapping.property-editor.ts - Update UI --- .../hubspot-mapping.property-editor.ts | 126 +++++++++++++++++- 1 file changed, 119 insertions(+), 7 deletions(-) diff --git a/src/Umbraco.Forms.Integrations.Crm.Hubspot/Client/src/property-editor/hubspot-mapping.property-editor.ts b/src/Umbraco.Forms.Integrations.Crm.Hubspot/Client/src/property-editor/hubspot-mapping.property-editor.ts index 193d020..08b8a3b 100644 --- a/src/Umbraco.Forms.Integrations.Crm.Hubspot/Client/src/property-editor/hubspot-mapping.property-editor.ts +++ b/src/Umbraco.Forms.Integrations.Crm.Hubspot/Client/src/property-editor/hubspot-mapping.property-editor.ts @@ -1,19 +1,131 @@ -import { html, customElement, property, css, when } from '@umbraco-cms/backoffice/external/lit'; +import { html, customElement, property, css, when, state, map } from '@umbraco-cms/backoffice/external/lit'; import type { UmbPropertyEditorUiElement } from '@umbraco-cms/backoffice/extension-registry'; import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element'; +import { HUBSPOT_CONTEXT_TOKEN } from '@umbraco-integrations/hubspot/context'; +import { Property } from '@umbraco-integrations/hubspot/generated'; const elementName = "hubspot-mapping-property-editor"; @customElement(elementName) export class HubspotMappingPropertyUiElement extends UmbLitElement implements UmbPropertyEditorUiElement { - render() { - return html` -
- -
- `; + #hubspotContext!: typeof HUBSPOT_CONTEXT_TOKEN.TYPE; + + @property({ type: String }) + public value = ""; + + @state() + public hubspotMappingArray : Array = []; + + @state() + private selectedContactField: string = ""; + + @state() + private selectedFormField: string = ""; + + @state() + private hubspotFields: Array | undefined = []; + + @state() + private formdFields: Array | undefined = []; + + constructor() { + super(); + this.consumeContext(HUBSPOT_CONTEXT_TOKEN, (context) => { + if (!context) return; + this.#hubspotContext = context; + }); + } + + async connectedCallback() { + super.connectedCallback(); + + if(this.value){ + this.hubspotMappingArray = JSON.parse(this.value); } + + await this.#getHubspotFields(); + //await this.#getFormFields(); + } + + async #getHubspotFields(){ + var result = await this.#hubspotContext.getAll(); + if (!result) return; + + this.hubspotFields = result.data; + } + + // async #getFormFields(){ + // var formId = window.location.pathname.split("/")[7]; //Get the formid based on current url. + // var result = await this.#activeCampaignContext.getFormFields(formId); + + // if (!result) return; + + // this.formdFields = result.data; + // } + + #onDeleteClick(idx: number){ + + } + + isDisabled(){ + return false; + } + + #addButtonClick(){ + this.hubspotMappingArray.push(""); + } + + render() { + return html` +
Umbraco forms is configured.
+ +
+ ${this.hubspotMappingArray.length > 0 + ? html` + + + + + + + + + + ${map(this.hubspotMappingArray, (mapping, idx) => html` + + + + + + `)} + +
Form FieldHubspot Field
+ + + + + this.#onDeleteClick(idx)}> + + +
+ ` + : html``} +
+ +
+ +
+ +
+ +
+ `; } +} export default HubspotMappingPropertyUiElement; From 9d47192c501102b62530a41ac72c35320d9f10de Mon Sep 17 00:00:00 2001 From: Nguyen Doan Thanh <145089181+dtng95@users.noreply.github.com> Date: Mon, 23 Sep 2024 17:26:19 +0700 Subject: [PATCH 04/13] V14: Integrations (HubSpot/Forms) - update UI implementation --- .../Controllers/Forms/FormControllerBase.cs | 26 +++ .../Forms/GetFormFieldsController.cs | 32 +++ .../Client/generated/services.gen.ts | 21 +- .../Client/generated/types.gen.ts | 99 +++++++++ .../Client/src/context/hubspot.context.ts | 15 +- .../Client/src/models/hubspot.model.ts | 5 + .../hubspot-mapping.property-editor.ts | 195 +++++++++++++----- .../src/repository/hubspot.repository.ts | 16 +- .../Client/tsconfig.json | 2 +- .../Constants.cs | 1 + 10 files changed, 347 insertions(+), 65 deletions(-) create mode 100644 src/Umbraco.Forms.Integrations.Crm.Hubspot/Api/Management/Controllers/Forms/FormControllerBase.cs create mode 100644 src/Umbraco.Forms.Integrations.Crm.Hubspot/Api/Management/Controllers/Forms/GetFormFieldsController.cs create mode 100644 src/Umbraco.Forms.Integrations.Crm.Hubspot/Client/src/models/hubspot.model.ts diff --git a/src/Umbraco.Forms.Integrations.Crm.Hubspot/Api/Management/Controllers/Forms/FormControllerBase.cs b/src/Umbraco.Forms.Integrations.Crm.Hubspot/Api/Management/Controllers/Forms/FormControllerBase.cs new file mode 100644 index 0000000..994e666 --- /dev/null +++ b/src/Umbraco.Forms.Integrations.Crm.Hubspot/Api/Management/Controllers/Forms/FormControllerBase.cs @@ -0,0 +1,26 @@ +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Umbraco.Cms.Web.Common.Authorization; +using Umbraco.Cms.Web.Common.Routing; +using Umbraco.Forms.Core.Services; + +namespace Umbraco.Forms.Integrations.Crm.Hubspot.Api.Management.Controllers.Forms +{ + [BackOfficeRoute($"{Constants.ManagementApi.RootPath}/v{{version:apiVersion}}/forms")] + [ApiExplorerSettings(GroupName = Constants.ManagementApi.FormGroupName)] + [Authorize(Policy = AuthorizationPolicies.BackOfficeAccess)] + public class FormControllerBase : HubspotControllerBase + { + protected readonly IFormService FormService; + + public FormControllerBase(IFormService formService) + { + FormService = formService; + } + } +} diff --git a/src/Umbraco.Forms.Integrations.Crm.Hubspot/Api/Management/Controllers/Forms/GetFormFieldsController.cs b/src/Umbraco.Forms.Integrations.Crm.Hubspot/Api/Management/Controllers/Forms/GetFormFieldsController.cs new file mode 100644 index 0000000..67d090e --- /dev/null +++ b/src/Umbraco.Forms.Integrations.Crm.Hubspot/Api/Management/Controllers/Forms/GetFormFieldsController.cs @@ -0,0 +1,32 @@ +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Umbraco.Forms.Core.Models; +using Umbraco.Forms.Core.Services; + +namespace Umbraco.Forms.Integrations.Crm.Hubspot.Api.Management.Controllers.Forms +{ + public class GetFormFieldsController : FormControllerBase + { + public GetFormFieldsController(IFormService formService) : base(formService) + { + } + + [HttpGet("fields")] + [ProducesResponseType(typeof(List), StatusCodes.Status200OK)] + public IActionResult GetFormFields(string formId) + { + List formFields = new List(); + var result = FormService.Get(new Guid(formId)); + if (result != null) + { + formFields = result.AllFields; + } + return Ok(formFields); + } + } +} diff --git a/src/Umbraco.Forms.Integrations.Crm.Hubspot/Client/generated/services.gen.ts b/src/Umbraco.Forms.Integrations.Crm.Hubspot/Client/generated/services.gen.ts index 7b58f15..db02f2f 100644 --- a/src/Umbraco.Forms.Integrations.Crm.Hubspot/Client/generated/services.gen.ts +++ b/src/Umbraco.Forms.Integrations.Crm.Hubspot/Client/generated/services.gen.ts @@ -3,7 +3,7 @@ import type { CancelablePromise } from './core/CancelablePromise'; import { OpenAPI } from './core/OpenAPI'; import { request as __request } from './core/request'; -import type { IsAuthorizationConfiguredResponse, GetAuthenticationUrlResponse, AuthorizeData, AuthorizeResponse, DeauthorizeResponse, GetAllResponse } from './types.gen'; +import type { IsAuthorizationConfiguredResponse, GetAuthenticationUrlResponse, AuthorizeData, AuthorizeResponse, DeauthorizeResponse, GetAllResponse, GetFormFieldsData, GetFormFieldsResponse } from './types.gen'; export class ContactsService { /** @@ -65,4 +65,23 @@ export class ContactsService { }); } +} + +export class FormsService { + /** + * @param data The data for the request. + * @param data.formId + * @returns unknown OK + * @throws ApiError + */ + public static getFormFields(data: GetFormFieldsData = {}): CancelablePromise { + return __request(OpenAPI, { + method: 'GET', + url: '/umbraco/hubspot/management/api/v1/forms/fields', + query: { + formId: data.formId + } + }); + } + } \ No newline at end of file diff --git a/src/Umbraco.Forms.Integrations.Crm.Hubspot/Client/generated/types.gen.ts b/src/Umbraco.Forms.Integrations.Crm.Hubspot/Client/generated/types.gen.ts index 0006be4..76e911c 100644 --- a/src/Umbraco.Forms.Integrations.Crm.Hubspot/Client/generated/types.gen.ts +++ b/src/Umbraco.Forms.Integrations.Crm.Hubspot/Client/generated/types.gen.ts @@ -14,6 +14,12 @@ export type AggregateException = { readonly message: string; }; +export type AllowedUploadType = { + type: string; + name: string; + checked: string; +}; + export type Assembly = { readonly definedTypes: Array<(TypeInfo)>; readonly exportedTypes: Array<(Type)>; @@ -161,6 +167,33 @@ export type Exception = { readonly stackTrace?: string | null; }; +export type Field = { + caption: string; + tooltip?: string | null; + /** + * @deprecated + */ + placeholder?: string | null; + cssClass?: string | null; + alias: string; + id: string; + fieldTypeId: string; + prevalueSourceId: string; + dataSourceFieldKey?: string | null; + containsSensitiveData: boolean; + mandatory: boolean; + regex?: string | null; + requiredErrorMessage?: string | null; + invalidErrorMessage?: string | null; + condition?: FieldCondition | null; + settings: { + [key: string]: (string); + }; + preValues: Array<(FieldPrevalue)>; + allowedUploadTypes?: Array<(AllowedUploadType)> | null; + allowMultipleFileUploads: boolean; +}; + export enum FieldAttributes { PRIVATE_SCOPE = 'PrivateScope', PRIVATE = 'Private', @@ -183,6 +216,50 @@ export enum FieldAttributes { RESERVED_MASK = 'ReservedMask' } +export type FieldCondition = { + id: string; + enabled: boolean; + actionType: FieldConditionActionType; + logicType: FieldConditionLogicType; + rules: Array<(FieldConditionRule)>; +}; + +export enum FieldConditionActionType { + SHOW = 'Show', + HIDE = 'Hide' +} + +export enum FieldConditionLogicType { + ALL = 'All', + ANY = 'Any' +} + +export type FieldConditionRule = { + id: string; + field: string; + operator: FieldConditionRuleOperator; + value: string; +}; + +export enum FieldConditionRuleOperator { + IS = 'Is', + IS_NOT = 'IsNot', + GREATER_THEN = 'GreaterThen', + LESS_THEN = 'LessThen', + CONTAINS = 'Contains', + CONTAINS_IGNORE_CASE = 'ContainsIgnoreCase', + STARTS_WITH = 'StartsWith', + STARTS_WITH_IGNORE_CASE = 'StartsWithIgnoreCase', + ENDS_WITH = 'EndsWith', + ENDS_WITH_IGNORE_CASE = 'EndsWithIgnoreCase', + NOT_CONTAINS = 'NotContains', + NOT_CONTAINS_IGNORE_CASE = 'NotContainsIgnoreCase', + NOT_STARTS_WITH = 'NotStartsWith', + NOT_STARTS_WITH_IGNORE_CASE = 'NotStartsWithIgnoreCase', + NOT_ENDS_WITH = 'NotEndsWith', + NOT_ENDS_WITH_IGNORE_CASE = 'NotEndsWithIgnoreCase' +} + export type FieldInfo = { readonly name: string; readonly declaringType?: Type | null; @@ -215,6 +292,11 @@ export type FieldInfo = { readonly fieldHandle: RuntimeFieldHandle; }; +export type FieldPrevalue = { + value: string; + caption?: string | null; +}; + export enum GenericParameterAttributes { NONE = 'None', COVARIANT = 'Covariant', @@ -745,6 +827,12 @@ export type DeauthorizeResponse = AuthorizationResult; export type GetAllResponse = Array<(Property)>; +export type GetFormFieldsData = { + formId?: string; +}; + +export type GetFormFieldsResponse = Array<(Field)>; + export type $OpenApiTs = { '/umbraco/hubspot/management/api/v1/contacts/auth/configured': { get: { @@ -797,4 +885,15 @@ export type $OpenApiTs = { }; }; }; + '/umbraco/hubspot/management/api/v1/forms/fields': { + get: { + req: GetFormFieldsData; + res: { + /** + * OK + */ + 200: Array<(Field)>; + }; + }; + }; }; \ No newline at end of file diff --git a/src/Umbraco.Forms.Integrations.Crm.Hubspot/Client/src/context/hubspot.context.ts b/src/Umbraco.Forms.Integrations.Crm.Hubspot/Client/src/context/hubspot.context.ts index 5f6e447..c7166a1 100644 --- a/src/Umbraco.Forms.Integrations.Crm.Hubspot/Client/src/context/hubspot.context.ts +++ b/src/Umbraco.Forms.Integrations.Crm.Hubspot/Client/src/context/hubspot.context.ts @@ -3,10 +3,14 @@ import { UmbContextToken } from "@umbraco-cms/backoffice/context-api"; import type { UmbControllerHost } from "@umbraco-cms/backoffice/controller-api"; import { HubspotRepository } from "../repository/hubspot.repository"; import { type AuthorizeData } from "@umbraco-integrations/hubspot/generated"; +import { UmbObjectState } from "@umbraco-cms/backoffice/observable-api"; export class HubspotContext extends UmbControllerBase{ #repository: HubspotRepository; + #settingsModel = new UmbObjectState(undefined); + settingsModel = this.#settingsModel.asObservable(); + constructor(host: UmbControllerHost) { super(host); @@ -19,15 +23,16 @@ export class HubspotContext extends UmbControllerBase{ } async isAuthorizationConfigured() { - return await this.#repository.isAuthorizationConfigured(); + const { data } = await this.#repository.isAuthorizationConfigured(); + this.#settingsModel.setValue(data); } async getAuthenticationUrl() { return await this.#repository.getAuthenticationUrl(); } - async authorize(authData: AuthorizeData) { - return await this.#repository.authorize(authData); + async authorize(code: string) { + return await this.#repository.authorize(code); } async deauthorize() { @@ -37,6 +42,10 @@ export class HubspotContext extends UmbControllerBase{ async getAll() { return await this.#repository.getAll(); } + + async getFormFields(formId : string) { + return await this.#repository.getFormFields(formId); + } } export default HubspotContext; diff --git a/src/Umbraco.Forms.Integrations.Crm.Hubspot/Client/src/models/hubspot.model.ts b/src/Umbraco.Forms.Integrations.Crm.Hubspot/Client/src/models/hubspot.model.ts new file mode 100644 index 0000000..0a5524e --- /dev/null +++ b/src/Umbraco.Forms.Integrations.Crm.Hubspot/Client/src/models/hubspot.model.ts @@ -0,0 +1,5 @@ +export interface HubspotMappingValue { + formField: string; + hubspotField: string; + appendValue: boolean; +} \ No newline at end of file diff --git a/src/Umbraco.Forms.Integrations.Crm.Hubspot/Client/src/property-editor/hubspot-mapping.property-editor.ts b/src/Umbraco.Forms.Integrations.Crm.Hubspot/Client/src/property-editor/hubspot-mapping.property-editor.ts index 08b8a3b..f9810a4 100644 --- a/src/Umbraco.Forms.Integrations.Crm.Hubspot/Client/src/property-editor/hubspot-mapping.property-editor.ts +++ b/src/Umbraco.Forms.Integrations.Crm.Hubspot/Client/src/property-editor/hubspot-mapping.property-editor.ts @@ -2,22 +2,25 @@ import { html, customElement, property, css, when, state, map } from '@umbraco-c import type { UmbPropertyEditorUiElement } from '@umbraco-cms/backoffice/extension-registry'; import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element'; import { HUBSPOT_CONTEXT_TOKEN } from '@umbraco-integrations/hubspot/context'; -import { Property } from '@umbraco-integrations/hubspot/generated'; +import { Field, Property } from '@umbraco-integrations/hubspot/generated'; +import { UUISelectEvent } from '@umbraco-cms/backoffice/external/uui'; +import { HubspotMappingValue } from '../models/hubspot.model'; const elementName = "hubspot-mapping-property-editor"; @customElement(elementName) export class HubspotMappingPropertyUiElement extends UmbLitElement implements UmbPropertyEditorUiElement { #hubspotContext!: typeof HUBSPOT_CONTEXT_TOKEN.TYPE; + #settingsModel?: string; @property({ type: String }) public value = ""; @state() - public hubspotMappingArray : Array = []; + public hubspotMappingArray : Array = []; @state() - private selectedContactField: string = ""; + private selectedHubspotField: string = ""; @state() private selectedFormField: string = ""; @@ -26,25 +29,51 @@ export class HubspotMappingPropertyUiElement extends UmbLitElement implements Um private hubspotFields: Array | undefined = []; @state() - private formdFields: Array | undefined = []; + private formdFields: Array | undefined = []; + + @state() + private authorizationCode: string = ""; + + @state() + private authorizationStatus: string = "Unauthenticated"; + + @state() + private authenticationUrl: string | undefined = ""; constructor() { super(); this.consumeContext(HUBSPOT_CONTEXT_TOKEN, (context) => { if (!context) return; this.#hubspotContext = context; + + this.observe(context.settingsModel, (settingsModel) => { + this.#settingsModel = settingsModel; + }); }); } async connectedCallback() { super.connectedCallback(); + if(!this.#settingsModel){ + const { data } = await this.#hubspotContext.getAuthenticationUrl(); + this.authenticationUrl = data; + + + }else{ + this.authorizationStatus = this.#settingsModel!; + } + if(this.value){ this.hubspotMappingArray = JSON.parse(this.value); } await this.#getHubspotFields(); - //await this.#getFormFields(); + await this.#getFormFields(); + } + + async #openAuth(){ + window.open(this.authenticationUrl); } async #getHubspotFields(){ @@ -54,75 +83,127 @@ export class HubspotMappingPropertyUiElement extends UmbLitElement implements Um this.hubspotFields = result.data; } - // async #getFormFields(){ - // var formId = window.location.pathname.split("/")[7]; //Get the formid based on current url. - // var result = await this.#activeCampaignContext.getFormFields(formId); + async #getFormFields(){ + var formId = window.location.pathname.split("/")[7]; //Get the formid based on current url. + var result = await this.#hubspotContext.getFormFields(formId); - // if (!result) return; + if (!result) return; - // this.formdFields = result.data; - // } + this.formdFields = result.data; + } #onDeleteClick(idx: number){ } + async #onConnect(){ + const { data } = await this.#hubspotContext.authorize(this.authorizationCode); + if(data?.result.success){ + this.authorizationStatus = "OAuth"; + this.authorizationCode = ""; + } + } + isDisabled(){ return false; } #addButtonClick(){ - this.hubspotMappingArray.push(""); + this.hubspotMappingArray.push({ + formField: "", + hubspotField: "", + appendValue: false + }); } - + + #onContactSelectChange(e: UUISelectEvent){ + this.selectedHubspotField = e.target.value.toString(); + } + + #onFormFieldSelectChange(e: UUISelectEvent){ + this.selectedFormField = e.target.value.toString(); + } + render() { return html` -
Umbraco forms is configured.
- -
- ${this.hubspotMappingArray.length > 0 - ? html` - - - - - - - - - - ${map(this.hubspotMappingArray, (mapping, idx) => html` + ${this.authorizationStatus === "Unauthenticated" + ? html` +
+

Umbraco Forms is not configured with a HubSpot CRM account.

+

To do this you can either create and save an API key or a Private Access Token into the appsettings.json file.

+

Or you can click here to complete an OAuth connection.

+ +

If your browser is unable to process the automated connection, paste the provided authorization code below and click to complete the authentication.

+ + +
+ ` + : html` +
+ Umbraco Forms is configured with a HubSpot CRM account using: ${this.authorizationStatus}

+
+ +
+ +
+ +
+ ${this.hubspotMappingArray.length > 0 + ? html` +
Form FieldHubspot Field
+ - - - + + + - `)} - -
- - - - - this.#onDeleteClick(idx)}> - - - Form FieldHubspot Field
- ` - : html``} -
- -
- -
- -
- -
+ + + ${map(this.hubspotMappingArray, (mapping, idx) => html` + + + this.#onContactSelectChange(e)} + .options=${ + this.hubspotFields?.map((ft) => ({ + name: ft.label, + value: ft.name, + selected: ft.name === this.selectedHubspotField, + })) ?? []}> + + + this.#onFormFieldSelectChange(e)} + .options=${ + this.formdFields?.map((ft) => ({ + name: ft.caption, + value: ft.id, + selected: ft.id === this.selectedFormField, + })) ?? []}> + + + this.#onDeleteClick(idx)}> + + + + + `)} + + + ` + : html``} + + +
+ +
+ `} `; } } diff --git a/src/Umbraco.Forms.Integrations.Crm.Hubspot/Client/src/repository/hubspot.repository.ts b/src/Umbraco.Forms.Integrations.Crm.Hubspot/Client/src/repository/hubspot.repository.ts index 6d7737b..4e2457b 100644 --- a/src/Umbraco.Forms.Integrations.Crm.Hubspot/Client/src/repository/hubspot.repository.ts +++ b/src/Umbraco.Forms.Integrations.Crm.Hubspot/Client/src/repository/hubspot.repository.ts @@ -1,7 +1,7 @@ import { UmbControllerBase } from "@umbraco-cms/backoffice/class-api"; import type { UmbControllerHost } from "@umbraco-cms/backoffice/controller-api"; import { tryExecuteAndNotify } from "@umbraco-cms/backoffice/resources"; -import { ContactsService, type AuthorizeData } from "@umbraco-integrations/hubspot/generated"; +import { ContactsService, FormsService, type AuthorizeData } from "@umbraco-integrations/hubspot/generated"; export class HubspotRepository extends UmbControllerBase{ constructor(host: UmbControllerHost) { @@ -28,8 +28,8 @@ export class HubspotRepository extends UmbControllerBase{ return { data }; } - async authorize(authData: AuthorizeData) { - const { data, error } = await tryExecuteAndNotify(this, ContactsService.authorize(authData)); + async authorize(code: string) { + const { data, error } = await tryExecuteAndNotify(this, ContactsService.authorize({requestBody: {code: code}})); if (error || !data) { return { error }; @@ -57,4 +57,14 @@ export class HubspotRepository extends UmbControllerBase{ return { data }; } + + async getFormFields(formId: string) { + const { data, error } = await tryExecuteAndNotify(this, FormsService.getFormFields({formId: formId})); + + if (error || !data) { + return { error }; + } + + return { data }; + } } \ No newline at end of file diff --git a/src/Umbraco.Forms.Integrations.Crm.Hubspot/Client/tsconfig.json b/src/Umbraco.Forms.Integrations.Crm.Hubspot/Client/tsconfig.json index 09ecf4d..5836535 100644 --- a/src/Umbraco.Forms.Integrations.Crm.Hubspot/Client/tsconfig.json +++ b/src/Umbraco.Forms.Integrations.Crm.Hubspot/Client/tsconfig.json @@ -17,7 +17,7 @@ /* Linting */ "strict": true, "noUnusedLocals": false, - "noUnusedParameters": true, + "noUnusedParameters": false, "noFallthroughCasesInSwitch": true, "paths": { diff --git a/src/Umbraco.Forms.Integrations.Crm.Hubspot/Constants.cs b/src/Umbraco.Forms.Integrations.Crm.Hubspot/Constants.cs index b406801..815fa6d 100644 --- a/src/Umbraco.Forms.Integrations.Crm.Hubspot/Constants.cs +++ b/src/Umbraco.Forms.Integrations.Crm.Hubspot/Constants.cs @@ -17,6 +17,7 @@ public static class ManagementApi public const string ApiTitle = "Hubspot Management API"; public const string ContactGroupName = "Contacts"; + public const string FormGroupName = "Forms"; } } } From fa82592333466fca24835258109e5d02a66390fb Mon Sep 17 00:00:00 2001 From: Nguyen Doan Thanh <145089181+dtng95@users.noreply.github.com> Date: Tue, 24 Sep 2024 17:53:25 +0700 Subject: [PATCH 05/13] V14: Integrations (HubSpot/Forms) - Continue implementation for Hubspot workflow UI - Smoke testing --- .../Contacts/AuthorizeController.cs | 2 +- .../Client/generated/types.gen.ts | 706 +----------------- .../Client/src/context/hubspot.context.ts | 1 + .../Client/src/lang/en.ts | 6 +- .../hubspot-mapping.property-editor.ts | 298 +++++--- 5 files changed, 214 insertions(+), 799 deletions(-) diff --git a/src/Umbraco.Forms.Integrations.Crm.Hubspot/Api/Management/Controllers/Contacts/AuthorizeController.cs b/src/Umbraco.Forms.Integrations.Crm.Hubspot/Api/Management/Controllers/Contacts/AuthorizeController.cs index cfcb8ed..5c3034a 100644 --- a/src/Umbraco.Forms.Integrations.Crm.Hubspot/Api/Management/Controllers/Contacts/AuthorizeController.cs +++ b/src/Umbraco.Forms.Integrations.Crm.Hubspot/Api/Management/Controllers/Contacts/AuthorizeController.cs @@ -17,7 +17,7 @@ public AuthorizeController(IContactService contactService) : base(contactService } [HttpPost("authorize")] - [ProducesResponseType(typeof(Task), StatusCodes.Status200OK)] + [ProducesResponseType(typeof(AuthorizationResult), StatusCodes.Status200OK)] public async Task Authorize([FromBody] AuthorizationRequest request) => Ok(await ContactService.AuthorizeAsync(request.Code)); } } diff --git a/src/Umbraco.Forms.Integrations.Crm.Hubspot/Client/generated/types.gen.ts b/src/Umbraco.Forms.Integrations.Crm.Hubspot/Client/generated/types.gen.ts index 76e911c..22dfd52 100644 --- a/src/Umbraco.Forms.Integrations.Crm.Hubspot/Client/generated/types.gen.ts +++ b/src/Umbraco.Forms.Integrations.Crm.Hubspot/Client/generated/types.gen.ts @@ -1,55 +1,11 @@ // This file is auto-generated by @hey-api/openapi-ts -export type AggregateException = { - readonly targetSite?: MethodBase | null; - readonly data: { - [key: string]: unknown; - }; - readonly innerException?: Exception | null; - helpLink?: string | null; - source?: string | null; - hResult: number; - readonly stackTrace?: string | null; - readonly innerExceptions: Array<(Exception)>; - readonly message: string; -}; - export type AllowedUploadType = { type: string; name: string; checked: string; }; -export type Assembly = { - readonly definedTypes: Array<(TypeInfo)>; - readonly exportedTypes: Array<(Type)>; - /** - * @deprecated - */ - readonly codeBase?: string | null; - readonly entryPoint?: MethodInfo | null; - readonly fullName?: string | null; - readonly imageRuntimeVersion: string; - readonly isDynamic: boolean; - readonly location: string; - readonly reflectionOnly: boolean; - readonly isCollectible: boolean; - readonly isFullyTrusted: boolean; - readonly customAttributes: Array<(CustomAttributeData)>; - /** - * @deprecated - */ - readonly escapedCodeBase: string; - readonly manifestModule: Module; - readonly modules: Array<(Module)>; - /** - * @deprecated - */ - readonly globalAssemblyCache: boolean; - readonly hostContext: number; - securityRuleSet: SecurityRuleSet; -}; - export type AuthorizationRequest = { code: string; }; @@ -59,93 +15,6 @@ export type AuthorizationResult = { readonly errorMessage: string; }; -export enum CallingConventions { - STANDARD = 'Standard', - VAR_ARGS = 'VarArgs', - ANY = 'Any', - HAS_THIS = 'HasThis', - EXPLICIT_THIS = 'ExplicitThis' -} - -export type ConstructorInfo = { - readonly name: string; - readonly declaringType?: Type | null; - readonly reflectedType?: Type | null; - readonly module: Module; - readonly customAttributes: Array<(CustomAttributeData)>; - readonly isCollectible: boolean; - readonly metadataToken: number; - attributes: MethodAttributes; - methodImplementationFlags: MethodImplAttributes; - callingConvention: CallingConventions; - readonly isAbstract: boolean; - readonly isConstructor: boolean; - readonly isFinal: boolean; - readonly isHideBySig: boolean; - readonly isSpecialName: boolean; - readonly isStatic: boolean; - readonly isVirtual: boolean; - readonly isAssembly: boolean; - readonly isFamily: boolean; - readonly isFamilyAndAssembly: boolean; - readonly isFamilyOrAssembly: boolean; - readonly isPrivate: boolean; - readonly isPublic: boolean; - readonly isConstructedGenericMethod: boolean; - readonly isGenericMethod: boolean; - readonly isGenericMethodDefinition: boolean; - readonly containsGenericParameters: boolean; - readonly methodHandle: RuntimeMethodHandle; - readonly isSecurityCritical: boolean; - readonly isSecuritySafeCritical: boolean; - readonly isSecurityTransparent: boolean; - memberType: MemberTypes; -}; - -export type CustomAttributeData = { - readonly attributeType: Type; - readonly constructor: ConstructorInfo; - readonly constructorArguments: Array<(CustomAttributeTypedArgument)>; - readonly namedArguments: Array<(CustomAttributeNamedArgument)>; -}; - -export type CustomAttributeNamedArgument = { - memberInfo: MemberInfo; - readonly typedValue: CustomAttributeTypedArgument; - readonly memberName: string; - readonly isField: boolean; -}; - -export type CustomAttributeTypedArgument = { - argumentType: Type; - value?: unknown; -}; - -export enum EventAttributes { - NONE = 'None', - SPECIAL_NAME = 'SpecialName', - RTSPECIAL_NAME = 'RTSpecialName', - RESERVED_MASK = 'ReservedMask' -} - -export type EventInfo = { - readonly name: string; - readonly declaringType?: Type | null; - readonly reflectedType?: Type | null; - readonly module: Module; - readonly customAttributes: Array<(CustomAttributeData)>; - readonly isCollectible: boolean; - readonly metadataToken: number; - memberType: MemberTypes; - attributes: EventAttributes; - readonly isSpecialName: boolean; - readonly addMethod?: MethodInfo | null; - readonly removeMethod?: MethodInfo | null; - readonly raiseMethod?: MethodInfo | null; - readonly isMulticast: boolean; - readonly eventHandlerType?: Type | null; -}; - export enum EventMessageTypeModel { DEFAULT = 'Default', INFO = 'Info', @@ -154,19 +23,6 @@ export enum EventMessageTypeModel { WARNING = 'Warning' } -export type Exception = { - readonly targetSite?: MethodBase | null; - readonly message: string; - readonly data: { - [key: string]: unknown; - }; - readonly innerException?: Exception | null; - helpLink?: string | null; - source?: string | null; - hResult: number; - readonly stackTrace?: string | null; -}; - export type Field = { caption: string; tooltip?: string | null; @@ -194,28 +50,6 @@ export type Field = { allowMultipleFileUploads: boolean; }; -export enum FieldAttributes { - PRIVATE_SCOPE = 'PrivateScope', - PRIVATE = 'Private', - FAM_ANDASSEM = 'FamANDAssem', - ASSEMBLY = 'Assembly', - FAMILY = 'Family', - FAM_ORASSEM = 'FamORAssem', - PUBLIC = 'Public', - FIELD_ACCESS_MASK = 'FieldAccessMask', - STATIC = 'Static', - INIT_ONLY = 'InitOnly', - LITERAL = 'Literal', - NOT_SERIALIZED = 'NotSerialized', - HAS_FIELD_RVA = 'HasFieldRVA', - SPECIAL_NAME = 'SpecialName', - RTSPECIAL_NAME = 'RTSpecialName', - HAS_FIELD_MARSHAL = 'HasFieldMarshal', - PINVOKE_IMPL = 'PinvokeImpl', - HAS_DEFAULT = 'HasDefault', - RESERVED_MASK = 'ReservedMask' -} - export type FieldCondition = { id: string; enabled: boolean; @@ -260,559 +94,23 @@ export enum FieldConditionRuleOperator { NOT_ENDS_WITH_IGNORE_CASE = 'NotEndsWithIgnoreCase' } -export type FieldInfo = { - readonly name: string; - readonly declaringType?: Type | null; - readonly reflectedType?: Type | null; - readonly module: Module; - readonly customAttributes: Array<(CustomAttributeData)>; - readonly isCollectible: boolean; - readonly metadataToken: number; - memberType: MemberTypes; - attributes: FieldAttributes; - readonly fieldType: Type; - readonly isInitOnly: boolean; - readonly isLiteral: boolean; - /** - * @deprecated - */ - readonly isNotSerialized: boolean; - readonly isPinvokeImpl: boolean; - readonly isSpecialName: boolean; - readonly isStatic: boolean; - readonly isAssembly: boolean; - readonly isFamily: boolean; - readonly isFamilyAndAssembly: boolean; - readonly isFamilyOrAssembly: boolean; - readonly isPrivate: boolean; - readonly isPublic: boolean; - readonly isSecurityCritical: boolean; - readonly isSecuritySafeCritical: boolean; - readonly isSecurityTransparent: boolean; - readonly fieldHandle: RuntimeFieldHandle; -}; - export type FieldPrevalue = { value: string; caption?: string | null; }; -export enum GenericParameterAttributes { - NONE = 'None', - COVARIANT = 'Covariant', - CONTRAVARIANT = 'Contravariant', - VARIANCE_MASK = 'VarianceMask', - REFERENCE_TYPE_CONSTRAINT = 'ReferenceTypeConstraint', - NOT_NULLABLE_VALUE_TYPE_CONSTRAINT = 'NotNullableValueTypeConstraint', - DEFAULT_CONSTRUCTOR_CONSTRAINT = 'DefaultConstructorConstraint', - SPECIAL_CONSTRAINT_MASK = 'SpecialConstraintMask' -} - -export type ICustomAttributeProvider = { - [key: string]: unknown; -}; - -export type IntPtr = { - [key: string]: unknown; -}; - -export enum LayoutKind { - SEQUENTIAL = 'Sequential', - EXPLICIT = 'Explicit', - AUTO = 'Auto' -} - -export type MemberInfo = { - memberType: MemberTypes; - readonly name: string; - readonly declaringType?: Type | null; - readonly reflectedType?: Type | null; - readonly module: Module; - readonly customAttributes: Array<(CustomAttributeData)>; - readonly isCollectible: boolean; - readonly metadataToken: number; -}; - -export enum MemberTypes { - CONSTRUCTOR = 'Constructor', - EVENT = 'Event', - FIELD = 'Field', - METHOD = 'Method', - PROPERTY = 'Property', - TYPE_INFO = 'TypeInfo', - CUSTOM = 'Custom', - NESTED_TYPE = 'NestedType', - ALL = 'All' -} - -export enum MethodAttributes { - PRIVATE_SCOPE = 'PrivateScope', - REUSE_SLOT = 'ReuseSlot', - PRIVATE = 'Private', - FAM_ANDASSEM = 'FamANDAssem', - ASSEMBLY = 'Assembly', - FAMILY = 'Family', - FAM_ORASSEM = 'FamORAssem', - PUBLIC = 'Public', - MEMBER_ACCESS_MASK = 'MemberAccessMask', - UNMANAGED_EXPORT = 'UnmanagedExport', - STATIC = 'Static', - FINAL = 'Final', - VIRTUAL = 'Virtual', - HIDE_BY_SIG = 'HideBySig', - NEW_SLOT = 'NewSlot', - VTABLE_LAYOUT_MASK = 'VtableLayoutMask', - CHECK_ACCESS_ON_OVERRIDE = 'CheckAccessOnOverride', - ABSTRACT = 'Abstract', - SPECIAL_NAME = 'SpecialName', - RTSPECIAL_NAME = 'RTSpecialName', - PINVOKE_IMPL = 'PinvokeImpl', - HAS_SECURITY = 'HasSecurity', - REQUIRE_SEC_OBJECT = 'RequireSecObject', - RESERVED_MASK = 'ReservedMask' -} - -export type MethodBase = { - memberType: MemberTypes; - readonly name: string; - readonly declaringType?: Type | null; - readonly reflectedType?: Type | null; - readonly module: Module; - readonly customAttributes: Array<(CustomAttributeData)>; - readonly isCollectible: boolean; - readonly metadataToken: number; - attributes: MethodAttributes; - methodImplementationFlags: MethodImplAttributes; - callingConvention: CallingConventions; - readonly isAbstract: boolean; - readonly isConstructor: boolean; - readonly isFinal: boolean; - readonly isHideBySig: boolean; - readonly isSpecialName: boolean; - readonly isStatic: boolean; - readonly isVirtual: boolean; - readonly isAssembly: boolean; - readonly isFamily: boolean; - readonly isFamilyAndAssembly: boolean; - readonly isFamilyOrAssembly: boolean; - readonly isPrivate: boolean; - readonly isPublic: boolean; - readonly isConstructedGenericMethod: boolean; - readonly isGenericMethod: boolean; - readonly isGenericMethodDefinition: boolean; - readonly containsGenericParameters: boolean; - readonly methodHandle: RuntimeMethodHandle; - readonly isSecurityCritical: boolean; - readonly isSecuritySafeCritical: boolean; - readonly isSecurityTransparent: boolean; -}; - -export enum MethodImplAttributes { - IL = 'IL', - MANAGED = 'Managed', - NATIVE = 'Native', - OPTIL = 'OPTIL', - CODE_TYPE_MASK = 'CodeTypeMask', - RUNTIME = 'Runtime', - MANAGED_MASK = 'ManagedMask', - UNMANAGED = 'Unmanaged', - NO_INLINING = 'NoInlining', - FORWARD_REF = 'ForwardRef', - SYNCHRONIZED = 'Synchronized', - NO_OPTIMIZATION = 'NoOptimization', - PRESERVE_SIG = 'PreserveSig', - AGGRESSIVE_INLINING = 'AggressiveInlining', - AGGRESSIVE_OPTIMIZATION = 'AggressiveOptimization', - INTERNAL_CALL = 'InternalCall', - MAX_METHOD_IMPL_VAL = 'MaxMethodImplVal' -} - -export type MethodInfo = { - readonly name: string; - readonly declaringType?: Type | null; - readonly reflectedType?: Type | null; - readonly module: Module; - readonly customAttributes: Array<(CustomAttributeData)>; - readonly isCollectible: boolean; - readonly metadataToken: number; - attributes: MethodAttributes; - methodImplementationFlags: MethodImplAttributes; - callingConvention: CallingConventions; - readonly isAbstract: boolean; - readonly isConstructor: boolean; - readonly isFinal: boolean; - readonly isHideBySig: boolean; - readonly isSpecialName: boolean; - readonly isStatic: boolean; - readonly isVirtual: boolean; - readonly isAssembly: boolean; - readonly isFamily: boolean; - readonly isFamilyAndAssembly: boolean; - readonly isFamilyOrAssembly: boolean; - readonly isPrivate: boolean; - readonly isPublic: boolean; - readonly isConstructedGenericMethod: boolean; - readonly isGenericMethod: boolean; - readonly isGenericMethodDefinition: boolean; - readonly containsGenericParameters: boolean; - readonly methodHandle: RuntimeMethodHandle; - readonly isSecurityCritical: boolean; - readonly isSecuritySafeCritical: boolean; - readonly isSecurityTransparent: boolean; - memberType: MemberTypes; - readonly returnParameter: ParameterInfo; - readonly returnType: Type; - returnTypeCustomAttributes: ICustomAttributeProvider; -}; - -export type Module = { - readonly assembly: Assembly; - readonly fullyQualifiedName: string; - readonly name: string; - readonly mdStreamVersion: number; - readonly moduleVersionId: string; - readonly scopeName: string; - readonly moduleHandle: ModuleHandle; - readonly customAttributes: Array<(CustomAttributeData)>; - readonly metadataToken: number; -}; - -export type ModuleHandle = { - readonly mdStreamVersion: number; -}; - export type NotificationHeaderModel = { message: string; category: string; type: EventMessageTypeModel; }; -export enum ParameterAttributes { - NONE = 'None', - IN = 'In', - OUT = 'Out', - LCID = 'Lcid', - RETVAL = 'Retval', - OPTIONAL = 'Optional', - HAS_DEFAULT = 'HasDefault', - HAS_FIELD_MARSHAL = 'HasFieldMarshal', - RESERVED3 = 'Reserved3', - RESERVED4 = 'Reserved4', - RESERVED_MASK = 'ReservedMask' -} - -export type ParameterInfo = { - attributes: ParameterAttributes; - readonly member: MemberInfo; - readonly name?: string | null; - readonly parameterType: Type; - readonly position: number; - readonly isIn: boolean; - readonly isLcid: boolean; - readonly isOptional: boolean; - readonly isOut: boolean; - readonly isRetval: boolean; - readonly defaultValue?: unknown; - readonly rawDefaultValue?: unknown; - readonly hasDefaultValue: boolean; - readonly customAttributes: Array<(CustomAttributeData)>; - readonly metadataToken: number; -}; - export type Property = { name: string; label: string; description: string; }; -export enum PropertyAttributes { - NONE = 'None', - SPECIAL_NAME = 'SpecialName', - RTSPECIAL_NAME = 'RTSpecialName', - HAS_DEFAULT = 'HasDefault', - RESERVED2 = 'Reserved2', - RESERVED3 = 'Reserved3', - RESERVED4 = 'Reserved4', - RESERVED_MASK = 'ReservedMask' -} - -export type PropertyInfo = { - readonly name: string; - readonly declaringType?: Type | null; - readonly reflectedType?: Type | null; - readonly module: Module; - readonly customAttributes: Array<(CustomAttributeData)>; - readonly isCollectible: boolean; - readonly metadataToken: number; - memberType: MemberTypes; - readonly propertyType: Type; - attributes: PropertyAttributes; - readonly isSpecialName: boolean; - readonly canRead: boolean; - readonly canWrite: boolean; - readonly getMethod?: MethodInfo | null; - readonly setMethod?: MethodInfo | null; -}; - -export type RuntimeFieldHandle = { - readonly value: IntPtr; -}; - -export type RuntimeMethodHandle = { - readonly value: IntPtr; -}; - -export type RuntimeTypeHandle = { - readonly value: IntPtr; -}; - -export enum SecurityRuleSet { - NONE = 'None', - LEVEL1 = 'Level1', - LEVEL2 = 'Level2' -} - -export type StructLayoutAttribute = { - readonly typeId: unknown; - value: LayoutKind; -}; - -export enum TaskCreationOptions { - NONE = 'None', - PREFER_FAIRNESS = 'PreferFairness', - LONG_RUNNING = 'LongRunning', - ATTACHED_TO_PARENT = 'AttachedToParent', - DENY_CHILD_ATTACH = 'DenyChildAttach', - HIDE_SCHEDULER = 'HideScheduler', - RUN_CONTINUATIONS_ASYNCHRONOUSLY = 'RunContinuationsAsynchronously' -} - -export enum TaskStatus { - CREATED = 'Created', - WAITING_FOR_ACTIVATION = 'WaitingForActivation', - WAITING_TO_RUN = 'WaitingToRun', - RUNNING = 'Running', - WAITING_FOR_CHILDREN_TO_COMPLETE = 'WaitingForChildrenToComplete', - RAN_TO_COMPLETION = 'RanToCompletion', - CANCELED = 'Canceled', - FAULTED = 'Faulted' -} - -export type Task_1 = { - readonly id: number; - readonly exception?: AggregateException | null; - status: TaskStatus; - readonly isCanceled: boolean; - readonly isCompleted: boolean; - readonly isCompletedSuccessfully: boolean; - creationOptions: TaskCreationOptions; - readonly asyncState?: unknown; - readonly isFaulted: boolean; - readonly result: AuthorizationResult; -}; - -export type Type = { - readonly name: string; - readonly customAttributes: Array<(CustomAttributeData)>; - readonly isCollectible: boolean; - readonly metadataToken: number; - readonly isInterface: boolean; - memberType: MemberTypes; - readonly namespace?: string | null; - readonly assemblyQualifiedName?: string | null; - readonly fullName?: string | null; - readonly assembly: Assembly; - readonly module: Module; - readonly isNested: boolean; - readonly declaringType?: Type | null; - readonly declaringMethod?: MethodBase | null; - readonly reflectedType?: Type | null; - readonly underlyingSystemType: Type; - readonly isTypeDefinition: boolean; - readonly isArray: boolean; - readonly isByRef: boolean; - readonly isPointer: boolean; - readonly isConstructedGenericType: boolean; - readonly isGenericParameter: boolean; - readonly isGenericTypeParameter: boolean; - readonly isGenericMethodParameter: boolean; - readonly isGenericType: boolean; - readonly isGenericTypeDefinition: boolean; - readonly isSZArray: boolean; - readonly isVariableBoundArray: boolean; - readonly isByRefLike: boolean; - readonly isFunctionPointer: boolean; - readonly isUnmanagedFunctionPointer: boolean; - readonly hasElementType: boolean; - readonly genericTypeArguments: Array<(Type)>; - readonly genericParameterPosition: number; - genericParameterAttributes: GenericParameterAttributes; - attributes: TypeAttributes; - readonly isAbstract: boolean; - readonly isImport: boolean; - readonly isSealed: boolean; - readonly isSpecialName: boolean; - readonly isClass: boolean; - readonly isNestedAssembly: boolean; - readonly isNestedFamANDAssem: boolean; - readonly isNestedFamily: boolean; - readonly isNestedFamORAssem: boolean; - readonly isNestedPrivate: boolean; - readonly isNestedPublic: boolean; - readonly isNotPublic: boolean; - readonly isPublic: boolean; - readonly isAutoLayout: boolean; - readonly isExplicitLayout: boolean; - readonly isLayoutSequential: boolean; - readonly isAnsiClass: boolean; - readonly isAutoClass: boolean; - readonly isUnicodeClass: boolean; - readonly isCOMObject: boolean; - readonly isContextful: boolean; - readonly isEnum: boolean; - readonly isMarshalByRef: boolean; - readonly isPrimitive: boolean; - readonly isValueType: boolean; - readonly isSignatureType: boolean; - readonly isSecurityCritical: boolean; - readonly isSecuritySafeCritical: boolean; - readonly isSecurityTransparent: boolean; - readonly structLayoutAttribute?: StructLayoutAttribute | null; - readonly typeInitializer?: ConstructorInfo | null; - readonly typeHandle: RuntimeTypeHandle; - readonly guid: string; - readonly baseType?: Type | null; - /** - * @deprecated - */ - readonly isSerializable: boolean; - readonly containsGenericParameters: boolean; - readonly isVisible: boolean; -}; - -export enum TypeAttributes { - NOT_PUBLIC = 'NotPublic', - AUTO_LAYOUT = 'AutoLayout', - ANSI_CLASS = 'AnsiClass', - CLASS = 'Class', - PUBLIC = 'Public', - NESTED_PUBLIC = 'NestedPublic', - NESTED_PRIVATE = 'NestedPrivate', - NESTED_FAMILY = 'NestedFamily', - NESTED_ASSEMBLY = 'NestedAssembly', - NESTED_FAM_ANDASSEM = 'NestedFamANDAssem', - VISIBILITY_MASK = 'VisibilityMask', - NESTED_FAM_ORASSEM = 'NestedFamORAssem', - SEQUENTIAL_LAYOUT = 'SequentialLayout', - EXPLICIT_LAYOUT = 'ExplicitLayout', - LAYOUT_MASK = 'LayoutMask', - INTERFACE = 'Interface', - CLASS_SEMANTICS_MASK = 'ClassSemanticsMask', - ABSTRACT = 'Abstract', - SEALED = 'Sealed', - SPECIAL_NAME = 'SpecialName', - RTSPECIAL_NAME = 'RTSpecialName', - IMPORT = 'Import', - SERIALIZABLE = 'Serializable', - WINDOWS_RUNTIME = 'WindowsRuntime', - UNICODE_CLASS = 'UnicodeClass', - AUTO_CLASS = 'AutoClass', - STRING_FORMAT_MASK = 'StringFormatMask', - CUSTOM_FORMAT_CLASS = 'CustomFormatClass', - HAS_SECURITY = 'HasSecurity', - RESERVED_MASK = 'ReservedMask', - BEFORE_FIELD_INIT = 'BeforeFieldInit', - CUSTOM_FORMAT_MASK = 'CustomFormatMask' -} - -export type TypeInfo = { - readonly name: string; - readonly customAttributes: Array<(CustomAttributeData)>; - readonly isCollectible: boolean; - readonly metadataToken: number; - readonly isInterface: boolean; - memberType: MemberTypes; - readonly namespace?: string | null; - readonly assemblyQualifiedName?: string | null; - readonly fullName?: string | null; - readonly assembly: Assembly; - readonly module: Module; - readonly isNested: boolean; - readonly declaringType?: Type | null; - readonly declaringMethod?: MethodBase | null; - readonly reflectedType?: Type | null; - readonly underlyingSystemType: Type; - readonly isTypeDefinition: boolean; - readonly isArray: boolean; - readonly isByRef: boolean; - readonly isPointer: boolean; - readonly isConstructedGenericType: boolean; - readonly isGenericParameter: boolean; - readonly isGenericTypeParameter: boolean; - readonly isGenericMethodParameter: boolean; - readonly isGenericType: boolean; - readonly isGenericTypeDefinition: boolean; - readonly isSZArray: boolean; - readonly isVariableBoundArray: boolean; - readonly isByRefLike: boolean; - readonly isFunctionPointer: boolean; - readonly isUnmanagedFunctionPointer: boolean; - readonly hasElementType: boolean; - readonly genericTypeArguments: Array<(Type)>; - readonly genericParameterPosition: number; - genericParameterAttributes: GenericParameterAttributes; - attributes: TypeAttributes; - readonly isAbstract: boolean; - readonly isImport: boolean; - readonly isSealed: boolean; - readonly isSpecialName: boolean; - readonly isClass: boolean; - readonly isNestedAssembly: boolean; - readonly isNestedFamANDAssem: boolean; - readonly isNestedFamily: boolean; - readonly isNestedFamORAssem: boolean; - readonly isNestedPrivate: boolean; - readonly isNestedPublic: boolean; - readonly isNotPublic: boolean; - readonly isPublic: boolean; - readonly isAutoLayout: boolean; - readonly isExplicitLayout: boolean; - readonly isLayoutSequential: boolean; - readonly isAnsiClass: boolean; - readonly isAutoClass: boolean; - readonly isUnicodeClass: boolean; - readonly isCOMObject: boolean; - readonly isContextful: boolean; - readonly isEnum: boolean; - readonly isMarshalByRef: boolean; - readonly isPrimitive: boolean; - readonly isValueType: boolean; - readonly isSignatureType: boolean; - readonly isSecurityCritical: boolean; - readonly isSecuritySafeCritical: boolean; - readonly isSecurityTransparent: boolean; - readonly structLayoutAttribute?: StructLayoutAttribute | null; - readonly typeInitializer?: ConstructorInfo | null; - readonly typeHandle: RuntimeTypeHandle; - readonly guid: string; - readonly baseType?: Type | null; - /** - * @deprecated - */ - readonly isSerializable: boolean; - readonly containsGenericParameters: boolean; - readonly isVisible: boolean; - readonly genericTypeParameters: Array<(Type)>; - readonly declaredConstructors: Array<(ConstructorInfo)>; - readonly declaredEvents: Array<(EventInfo)>; - readonly declaredFields: Array<(FieldInfo)>; - readonly declaredMembers: Array<(MemberInfo)>; - readonly declaredMethods: Array<(MethodInfo)>; - readonly declaredNestedTypes: Array<(TypeInfo)>; - readonly declaredProperties: Array<(PropertyInfo)>; - readonly implementedInterfaces: Array<(Type)>; -}; - export type IsAuthorizationConfiguredResponse = string; export type GetAuthenticationUrlResponse = string; @@ -821,7 +119,7 @@ export type AuthorizeData = { requestBody?: AuthorizationRequest; }; -export type AuthorizeResponse = Task_1; +export type AuthorizeResponse = AuthorizationResult; export type DeauthorizeResponse = AuthorizationResult; @@ -861,7 +159,7 @@ export type $OpenApiTs = { /** * OK */ - 200: Task_1; + 200: AuthorizationResult; }; }; }; diff --git a/src/Umbraco.Forms.Integrations.Crm.Hubspot/Client/src/context/hubspot.context.ts b/src/Umbraco.Forms.Integrations.Crm.Hubspot/Client/src/context/hubspot.context.ts index c7166a1..9adfc3a 100644 --- a/src/Umbraco.Forms.Integrations.Crm.Hubspot/Client/src/context/hubspot.context.ts +++ b/src/Umbraco.Forms.Integrations.Crm.Hubspot/Client/src/context/hubspot.context.ts @@ -20,6 +20,7 @@ export class HubspotContext extends UmbControllerBase{ async hostConnected() { super.hostConnected(); + this.isAuthorizationConfigured(); } async isAuthorizationConfigured() { diff --git a/src/Umbraco.Forms.Integrations.Crm.Hubspot/Client/src/lang/en.ts b/src/Umbraco.Forms.Integrations.Crm.Hubspot/Client/src/lang/en.ts index f2b01e4..944d888 100644 --- a/src/Umbraco.Forms.Integrations.Crm.Hubspot/Client/src/lang/en.ts +++ b/src/Umbraco.Forms.Integrations.Crm.Hubspot/Client/src/lang/en.ts @@ -3,5 +3,9 @@ export default { formProviderWorkflows:{ FieldMappingsLabel : `Field Mappings`, FieldMappingsDescription: `Map Umbraco Form fields to Hubspot contact fields`, - } + }, + hubspotFormWorkflow:{ + SelectHubspotField : `Select Hubspot field`, + SelectFormField: `Select Form field`, + }, } as UmbLocalizationDictionary; \ No newline at end of file diff --git a/src/Umbraco.Forms.Integrations.Crm.Hubspot/Client/src/property-editor/hubspot-mapping.property-editor.ts b/src/Umbraco.Forms.Integrations.Crm.Hubspot/Client/src/property-editor/hubspot-mapping.property-editor.ts index f9810a4..c89b566 100644 --- a/src/Umbraco.Forms.Integrations.Crm.Hubspot/Client/src/property-editor/hubspot-mapping.property-editor.ts +++ b/src/Umbraco.Forms.Integrations.Crm.Hubspot/Client/src/property-editor/hubspot-mapping.property-editor.ts @@ -3,8 +3,9 @@ import type { UmbPropertyEditorUiElement } from '@umbraco-cms/backoffice/extensi import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element'; import { HUBSPOT_CONTEXT_TOKEN } from '@umbraco-integrations/hubspot/context'; import { Field, Property } from '@umbraco-integrations/hubspot/generated'; -import { UUISelectEvent } from '@umbraco-cms/backoffice/external/uui'; +import { UUIInputEvent, UUISelectEvent } from '@umbraco-cms/backoffice/external/uui'; import { HubspotMappingValue } from '../models/hubspot.model'; +import { UMB_NOTIFICATION_CONTEXT, UmbNotificationColor } from '@umbraco-cms/backoffice/notification'; const elementName = "hubspot-mapping-property-editor"; @@ -55,25 +56,14 @@ export class HubspotMappingPropertyUiElement extends UmbLitElement implements Um async connectedCallback() { super.connectedCallback(); - if(!this.#settingsModel){ + if (!this.#settingsModel || this.#settingsModel === "Unauthenticated"){ const { data } = await this.#hubspotContext.getAuthenticationUrl(); this.authenticationUrl = data; - - - }else{ + } else{ this.authorizationStatus = this.#settingsModel!; - } - if(this.value){ - this.hubspotMappingArray = JSON.parse(this.value); + await this.loadData(); } - - await this.#getHubspotFields(); - await this.#getFormFields(); - } - - async #openAuth(){ - window.open(this.authenticationUrl); } async #getHubspotFields(){ @@ -92,20 +82,89 @@ export class HubspotMappingPropertyUiElement extends UmbLitElement implements Um this.formdFields = result.data; } - #onDeleteClick(idx: number){ - + async #openAuth(){ + window.open(this.authenticationUrl); + window.addEventListener("message", async (event: MessageEvent) => { + if (event.data.type === "hubspot:oauth:success") { + this.authorizationCode = event.data.code; + + await this.#onConnect(); + } + }, false); } async #onConnect(){ const { data } = await this.#hubspotContext.authorize(this.authorizationCode); - if(data?.result.success){ + + if(!data) return; + + if(data.success){ this.authorizationStatus = "OAuth"; this.authorizationCode = ""; + + await this.loadData(); + + this.requestUpdate(); + this.dispatchEvent(new CustomEvent("authorizationStatus")); + this._showSuccess("Your Umbraco Forms installation is now connected to your HubSpot account"); + }else{ + this._showError(data.errorMessage); } } - isDisabled(){ - return false; + async loadData(){ + await this.#getHubspotFields(); + await this.#getFormFields(); + + if (this.value){ + this.hubspotMappingArray = JSON.parse(this.value); + } + } + + async #deauthorize(){ + //TODO: add overlay to confirm deauthorize + const { data } = await this.#hubspotContext.deauthorize(); + + if(!data) return; + + if (data.success){ + this.authorizationStatus = "Unauthenticated"; + this.authorizationCode = ""; + + const { data } = await this.#hubspotContext.getAuthenticationUrl(); + if (data){ + this.authenticationUrl = data; + } + + this._showSuccess("Your Umbraco Forms installation is no longer connected to your HubSpot account"); + }else{ + this._showError(data.errorMessage!); + } + + this.dispatchEvent(new CustomEvent("authorizationStatus")); + } + + private async _showSuccess(message: string) { + await this._showMessage(message, "positive"); + } + + private async _showError(message: string) { + await this._showMessage(message, "danger"); + } + + private async _showMessage(message: string, color: UmbNotificationColor) { + const notificationContext = await this.getContext(UMB_NOTIFICATION_CONTEXT); + notificationContext?.peek(color, { + data: { message }, + }); + } + + #onDeleteClick(idx: number){ + this.hubspotMappingArray.splice(idx, 1); + + this.value = JSON.stringify(this.hubspotMappingArray); + this.requestUpdate(); + this.dispatchEvent(new CustomEvent('property-value-change')); } #addButtonClick(){ @@ -114,98 +173,151 @@ export class HubspotMappingPropertyUiElement extends UmbLitElement implements Um hubspotField: "", appendValue: false }); + + this.value = JSON.stringify(this.hubspotMappingArray); + this.requestUpdate(); + this.dispatchEvent(new CustomEvent('property-value-change')); } - #onContactSelectChange(e: UUISelectEvent){ + #onHubspotSelectChange(e: UUISelectEvent, idx: number){ this.selectedHubspotField = e.target.value.toString(); + this.hubspotMappingArray[idx].hubspotField = this.selectedHubspotField; + + this.value = JSON.stringify(this.hubspotMappingArray); + this.requestUpdate(); + this.dispatchEvent(new CustomEvent('property-value-change')); } - #onFormFieldSelectChange(e: UUISelectEvent){ + #onFormFieldSelectChange(e: UUISelectEvent, idx: number){ this.selectedFormField = e.target.value.toString(); + this.hubspotMappingArray[idx].formField = this.selectedFormField; + + this.value = JSON.stringify(this.hubspotMappingArray); + this.requestUpdate(); + this.dispatchEvent(new CustomEvent('property-value-change')); + } + + #onInputChange(e: UUIInputEvent){ + this.authorizationCode = e.target.value.toString(); + } + + #getHubspotDescription(name: string){ + if (!this.hubspotFields) return; + var result = this.hubspotFields.find(h => h.name == name); + if (!result) return; + return result.description; } render() { return html` - ${this.authorizationStatus === "Unauthenticated" - ? html` -
-

Umbraco Forms is not configured with a HubSpot CRM account.

-

To do this you can either create and save an API key or a Private Access Token into the appsettings.json file.

-

Or you can click here to complete an OAuth connection.

- -

If your browser is unable to process the automated connection, paste the provided authorization code below and click to complete the authentication.

- - -
- ` - : html` -
- Umbraco Forms is configured with a HubSpot CRM account using: ${this.authorizationStatus}

-
- -
- -
- -
- ${this.hubspotMappingArray.length > 0 + ${this.authorizationStatus === "Unauthenticated" + ? html` +
+

Umbraco Forms is not configured with a HubSpot CRM account.

+

To do this you can either create and save an API key or a Private Access Token into the appsettings.json file.

+

Or you can click here to complete an OAuth connection.

+

If your browser is unable to process the automated connection, paste the provided authorization code below and click to complete the authentication.

+ this.#onInputChange(e)}> + +
+ ` + : html` +
+ Umbraco Forms is configured with a HubSpot CRM account using: ${this.authorizationStatus}

+
+ +
+ + + + + +
+ + + +
+
+ +
+ ${this.hubspotMappingArray.length > 0 ? html` - - - - - - - - - - ${map(this.hubspotMappingArray, (mapping, idx) => html` +
Form FieldHubspot Field
+ - - + + + + + + ${map(this.hubspotMappingArray, (mapping, idx) => html` + + + - - - `)} - -
- this.#onContactSelectChange(e)} - .options=${ - this.hubspotFields?.map((ft) => ({ - name: ft.label, - value: ft.name, - selected: ft.name === this.selectedHubspotField, - })) ?? []}> - - this.#onFormFieldSelectChange(e)} + Form FieldHubspot Field
+ this.#onFormFieldSelectChange(e, idx)} + .options=${ + this.formdFields?.map((ft) => ({ + name: ft.caption, + value: ft.id, + selected: ft.id === mapping.formField, + })) ?? []}> + + this.#onHubspotSelectChange(e, idx)} .options=${ - this.formdFields?.map((ft) => ({ - name: ft.caption, - value: ft.id, - selected: ft.id === this.selectedFormField, + this.hubspotFields?.map((ft) => ({ + name: ft.label, + value: ft.name, + selected: ft.name === mapping.hubspotField, })) ?? []}> - - this.#onDeleteClick(idx)}> - - -
+ + + this.#onDeleteClick(idx)}> + + + + + + + Description: ${this.#getHubspotDescription(mapping.hubspotField)} + + + `)} + + ` : html``} -
- -
- -
+
`} `; } + + static styles = [ + css` + .hubspot-wf-auth-link{ + cursor: pointer; + } + + .hubspot-wf-button, .hubspot-wf-table { + margin-top: 10px; + } + + .hubspot-wf-table th{ + text-align: justify; + } + + .hubspot-wf-table td.description{ + padding-bottom: 15px; + } + `]; } export default HubspotMappingPropertyUiElement; From 90288eabeaeb2a02655ee8846edaf6184e0030c1 Mon Sep 17 00:00:00 2001 From: Nguyen Doan Thanh <145089181+dtng95@users.noreply.github.com> Date: Tue, 24 Sep 2024 18:31:16 +0700 Subject: [PATCH 06/13] V14: Integrations (HubSpot/Forms) - Update form field dto - Change some css - Re generate api --- .../Forms/GetFormFieldsController.cs | 8 +- .../Client/generated/types.gen.ts | 83 +------------------ .../hubspot-mapping.property-editor.ts | 16 +++- .../Dtos/HubspotWorkflowFormFieldDto.cs | 18 ++++ 4 files changed, 37 insertions(+), 88 deletions(-) create mode 100644 src/Umbraco.Forms.Integrations.Crm.Hubspot/Models/Dtos/HubspotWorkflowFormFieldDto.cs diff --git a/src/Umbraco.Forms.Integrations.Crm.Hubspot/Api/Management/Controllers/Forms/GetFormFieldsController.cs b/src/Umbraco.Forms.Integrations.Crm.Hubspot/Api/Management/Controllers/Forms/GetFormFieldsController.cs index 67d090e..89fe6e2 100644 --- a/src/Umbraco.Forms.Integrations.Crm.Hubspot/Api/Management/Controllers/Forms/GetFormFieldsController.cs +++ b/src/Umbraco.Forms.Integrations.Crm.Hubspot/Api/Management/Controllers/Forms/GetFormFieldsController.cs @@ -5,8 +5,8 @@ using System.Linq; using System.Text; using System.Threading.Tasks; -using Umbraco.Forms.Core.Models; using Umbraco.Forms.Core.Services; +using Umbraco.Forms.Integrations.Crm.Hubspot.Models.Dtos; namespace Umbraco.Forms.Integrations.Crm.Hubspot.Api.Management.Controllers.Forms { @@ -17,14 +17,14 @@ public GetFormFieldsController(IFormService formService) : base(formService) } [HttpGet("fields")] - [ProducesResponseType(typeof(List), StatusCodes.Status200OK)] + [ProducesResponseType(typeof(List), StatusCodes.Status200OK)] public IActionResult GetFormFields(string formId) { - List formFields = new List(); + List formFields = new List(); var result = FormService.Get(new Guid(formId)); if (result != null) { - formFields = result.AllFields; + formFields = result.AllFields.Select(s => new HubspotWorkflowFormFieldDto{ Caption = s.Caption, Id = s.Id }).ToList(); } return Ok(formFields); } diff --git a/src/Umbraco.Forms.Integrations.Crm.Hubspot/Client/generated/types.gen.ts b/src/Umbraco.Forms.Integrations.Crm.Hubspot/Client/generated/types.gen.ts index 22dfd52..726f04c 100644 --- a/src/Umbraco.Forms.Integrations.Crm.Hubspot/Client/generated/types.gen.ts +++ b/src/Umbraco.Forms.Integrations.Crm.Hubspot/Client/generated/types.gen.ts @@ -1,11 +1,5 @@ // This file is auto-generated by @hey-api/openapi-ts -export type AllowedUploadType = { - type: string; - name: string; - checked: string; -}; - export type AuthorizationRequest = { code: string; }; @@ -23,80 +17,9 @@ export enum EventMessageTypeModel { WARNING = 'Warning' } -export type Field = { +export type HubspotWorkflowFormFieldDto = { caption: string; - tooltip?: string | null; - /** - * @deprecated - */ - placeholder?: string | null; - cssClass?: string | null; - alias: string; - id: string; - fieldTypeId: string; - prevalueSourceId: string; - dataSourceFieldKey?: string | null; - containsSensitiveData: boolean; - mandatory: boolean; - regex?: string | null; - requiredErrorMessage?: string | null; - invalidErrorMessage?: string | null; - condition?: FieldCondition | null; - settings: { - [key: string]: (string); - }; - preValues: Array<(FieldPrevalue)>; - allowedUploadTypes?: Array<(AllowedUploadType)> | null; - allowMultipleFileUploads: boolean; -}; - -export type FieldCondition = { - id: string; - enabled: boolean; - actionType: FieldConditionActionType; - logicType: FieldConditionLogicType; - rules: Array<(FieldConditionRule)>; -}; - -export enum FieldConditionActionType { - SHOW = 'Show', - HIDE = 'Hide' -} - -export enum FieldConditionLogicType { - ALL = 'All', - ANY = 'Any' -} - -export type FieldConditionRule = { id: string; - field: string; - operator: FieldConditionRuleOperator; - value: string; -}; - -export enum FieldConditionRuleOperator { - IS = 'Is', - IS_NOT = 'IsNot', - GREATER_THEN = 'GreaterThen', - LESS_THEN = 'LessThen', - CONTAINS = 'Contains', - CONTAINS_IGNORE_CASE = 'ContainsIgnoreCase', - STARTS_WITH = 'StartsWith', - STARTS_WITH_IGNORE_CASE = 'StartsWithIgnoreCase', - ENDS_WITH = 'EndsWith', - ENDS_WITH_IGNORE_CASE = 'EndsWithIgnoreCase', - NOT_CONTAINS = 'NotContains', - NOT_CONTAINS_IGNORE_CASE = 'NotContainsIgnoreCase', - NOT_STARTS_WITH = 'NotStartsWith', - NOT_STARTS_WITH_IGNORE_CASE = 'NotStartsWithIgnoreCase', - NOT_ENDS_WITH = 'NotEndsWith', - NOT_ENDS_WITH_IGNORE_CASE = 'NotEndsWithIgnoreCase' -} - -export type FieldPrevalue = { - value: string; - caption?: string | null; }; export type NotificationHeaderModel = { @@ -129,7 +52,7 @@ export type GetFormFieldsData = { formId?: string; }; -export type GetFormFieldsResponse = Array<(Field)>; +export type GetFormFieldsResponse = Array<(HubspotWorkflowFormFieldDto)>; export type $OpenApiTs = { '/umbraco/hubspot/management/api/v1/contacts/auth/configured': { @@ -190,7 +113,7 @@ export type $OpenApiTs = { /** * OK */ - 200: Array<(Field)>; + 200: Array<(HubspotWorkflowFormFieldDto)>; }; }; }; diff --git a/src/Umbraco.Forms.Integrations.Crm.Hubspot/Client/src/property-editor/hubspot-mapping.property-editor.ts b/src/Umbraco.Forms.Integrations.Crm.Hubspot/Client/src/property-editor/hubspot-mapping.property-editor.ts index c89b566..725df25 100644 --- a/src/Umbraco.Forms.Integrations.Crm.Hubspot/Client/src/property-editor/hubspot-mapping.property-editor.ts +++ b/src/Umbraco.Forms.Integrations.Crm.Hubspot/Client/src/property-editor/hubspot-mapping.property-editor.ts @@ -2,7 +2,7 @@ import { html, customElement, property, css, when, state, map } from '@umbraco-c import type { UmbPropertyEditorUiElement } from '@umbraco-cms/backoffice/extension-registry'; import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element'; import { HUBSPOT_CONTEXT_TOKEN } from '@umbraco-integrations/hubspot/context'; -import { Field, Property } from '@umbraco-integrations/hubspot/generated'; +import { HubspotWorkflowFormFieldDto, Property } from '@umbraco-integrations/hubspot/generated'; import { UUIInputEvent, UUISelectEvent } from '@umbraco-cms/backoffice/external/uui'; import { HubspotMappingValue } from '../models/hubspot.model'; import { UMB_NOTIFICATION_CONTEXT, UmbNotificationColor } from '@umbraco-cms/backoffice/notification'; @@ -30,7 +30,7 @@ export class HubspotMappingPropertyUiElement extends UmbLitElement implements Um private hubspotFields: Array | undefined = []; @state() - private formdFields: Array | undefined = []; + private formdFields: Array | undefined = []; @state() private authorizationCode: string = ""; @@ -222,8 +222,9 @@ export class HubspotMappingPropertyUiElement extends UmbLitElement implements Um ` : html` -
- Umbraco Forms is configured with a HubSpot CRM account using: ${this.authorizationStatus}

+
+ Umbraco Forms is configured with a HubSpot CRM account using: + ${this.authorizationStatus}

@@ -302,6 +303,13 @@ export class HubspotMappingPropertyUiElement extends UmbLitElement implements Um static styles = [ css` + .hubspot-wf-status{ + margin-top: 10px; + padding: 10px; + background-color: #202454; + color: #ffffff; + } + .hubspot-wf-auth-link{ cursor: pointer; } diff --git a/src/Umbraco.Forms.Integrations.Crm.Hubspot/Models/Dtos/HubspotWorkflowFormFieldDto.cs b/src/Umbraco.Forms.Integrations.Crm.Hubspot/Models/Dtos/HubspotWorkflowFormFieldDto.cs new file mode 100644 index 0000000..01653e0 --- /dev/null +++ b/src/Umbraco.Forms.Integrations.Crm.Hubspot/Models/Dtos/HubspotWorkflowFormFieldDto.cs @@ -0,0 +1,18 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.Serialization; +using System.Text; +using System.Threading.Tasks; + +namespace Umbraco.Forms.Integrations.Crm.Hubspot.Models.Dtos +{ + public class HubspotWorkflowFormFieldDto + { + [DataMember(Name = "caption")] + public string Caption { get; set; } = string.Empty; + + [DataMember(Name = "id")] + public Guid Id { get; set; } + } +} From 58ba947aaab73b91a9d59e3b6d6f6f26be0d0be6 Mon Sep 17 00:00:00 2001 From: Nguyen Doan Thanh <145089181+dtng95@users.noreply.github.com> Date: Wed, 25 Sep 2024 14:06:41 +0700 Subject: [PATCH 07/13] V14: Integrations (HubSpot/Forms) - Namespace cleanup - Add confirmation dialog when deauthorize --- .../Contacts/AuthorizeController.cs | 5 ---- .../Contacts/ContactControllerBase.cs | 5 ---- .../Contacts/DeauthorizeController.cs | 5 ---- .../Contacts/GetAllPropertiesController.cs | 6 ---- .../GetAuthenticationUrlController.cs | 5 ---- .../IsAuthorizationConfiguredController.cs | 5 ---- .../Controllers/Forms/FormControllerBase.cs | 10 ++----- .../Forms/GetFormFieldsController.cs | 5 ---- .../Controllers/HubspotControllerBase.cs | 9 +----- .../hubspot-mapping.property-editor.ts | 29 +++++++++---------- 10 files changed, 17 insertions(+), 67 deletions(-) diff --git a/src/Umbraco.Forms.Integrations.Crm.Hubspot/Api/Management/Controllers/Contacts/AuthorizeController.cs b/src/Umbraco.Forms.Integrations.Crm.Hubspot/Api/Management/Controllers/Contacts/AuthorizeController.cs index 5c3034a..c96fbbf 100644 --- a/src/Umbraco.Forms.Integrations.Crm.Hubspot/Api/Management/Controllers/Contacts/AuthorizeController.cs +++ b/src/Umbraco.Forms.Integrations.Crm.Hubspot/Api/Management/Controllers/Contacts/AuthorizeController.cs @@ -1,10 +1,5 @@ using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; using Umbraco.Forms.Integrations.Crm.Hubspot.Models.Dtos; using Umbraco.Forms.Integrations.Crm.Hubspot.Services; diff --git a/src/Umbraco.Forms.Integrations.Crm.Hubspot/Api/Management/Controllers/Contacts/ContactControllerBase.cs b/src/Umbraco.Forms.Integrations.Crm.Hubspot/Api/Management/Controllers/Contacts/ContactControllerBase.cs index 6634181..097a8ec 100644 --- a/src/Umbraco.Forms.Integrations.Crm.Hubspot/Api/Management/Controllers/Contacts/ContactControllerBase.cs +++ b/src/Umbraco.Forms.Integrations.Crm.Hubspot/Api/Management/Controllers/Contacts/ContactControllerBase.cs @@ -1,10 +1,5 @@ using Asp.Versioning; using Microsoft.AspNetCore.Mvc; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; using Umbraco.Cms.Web.Common.Routing; using Umbraco.Forms.Integrations.Crm.Hubspot.Services; diff --git a/src/Umbraco.Forms.Integrations.Crm.Hubspot/Api/Management/Controllers/Contacts/DeauthorizeController.cs b/src/Umbraco.Forms.Integrations.Crm.Hubspot/Api/Management/Controllers/Contacts/DeauthorizeController.cs index 2868958..5c06f8f 100644 --- a/src/Umbraco.Forms.Integrations.Crm.Hubspot/Api/Management/Controllers/Contacts/DeauthorizeController.cs +++ b/src/Umbraco.Forms.Integrations.Crm.Hubspot/Api/Management/Controllers/Contacts/DeauthorizeController.cs @@ -1,10 +1,5 @@ using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; using Umbraco.Forms.Integrations.Crm.Hubspot.Models.Dtos; using Umbraco.Forms.Integrations.Crm.Hubspot.Services; diff --git a/src/Umbraco.Forms.Integrations.Crm.Hubspot/Api/Management/Controllers/Contacts/GetAllPropertiesController.cs b/src/Umbraco.Forms.Integrations.Crm.Hubspot/Api/Management/Controllers/Contacts/GetAllPropertiesController.cs index 897a379..56a513e 100644 --- a/src/Umbraco.Forms.Integrations.Crm.Hubspot/Api/Management/Controllers/Contacts/GetAllPropertiesController.cs +++ b/src/Umbraco.Forms.Integrations.Crm.Hubspot/Api/Management/Controllers/Contacts/GetAllPropertiesController.cs @@ -1,11 +1,5 @@ using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using Umbraco.Cms.Web.Common.Attributes; using Umbraco.Forms.Integrations.Crm.Hubspot.Models.Responses; using Umbraco.Forms.Integrations.Crm.Hubspot.Services; diff --git a/src/Umbraco.Forms.Integrations.Crm.Hubspot/Api/Management/Controllers/Contacts/GetAuthenticationUrlController.cs b/src/Umbraco.Forms.Integrations.Crm.Hubspot/Api/Management/Controllers/Contacts/GetAuthenticationUrlController.cs index 1c1a30e..a51f409 100644 --- a/src/Umbraco.Forms.Integrations.Crm.Hubspot/Api/Management/Controllers/Contacts/GetAuthenticationUrlController.cs +++ b/src/Umbraco.Forms.Integrations.Crm.Hubspot/Api/Management/Controllers/Contacts/GetAuthenticationUrlController.cs @@ -1,10 +1,5 @@ using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; using Umbraco.Forms.Integrations.Crm.Hubspot.Services; namespace Umbraco.Forms.Integrations.Crm.Hubspot.Api.Management.Controllers.Contacts diff --git a/src/Umbraco.Forms.Integrations.Crm.Hubspot/Api/Management/Controllers/Contacts/IsAuthorizationConfiguredController.cs b/src/Umbraco.Forms.Integrations.Crm.Hubspot/Api/Management/Controllers/Contacts/IsAuthorizationConfiguredController.cs index 71b6437..ece49a8 100644 --- a/src/Umbraco.Forms.Integrations.Crm.Hubspot/Api/Management/Controllers/Contacts/IsAuthorizationConfiguredController.cs +++ b/src/Umbraco.Forms.Integrations.Crm.Hubspot/Api/Management/Controllers/Contacts/IsAuthorizationConfiguredController.cs @@ -1,10 +1,5 @@ using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; using Umbraco.Forms.Integrations.Crm.Hubspot.Services; namespace Umbraco.Forms.Integrations.Crm.Hubspot.Api.Management.Controllers.Contacts diff --git a/src/Umbraco.Forms.Integrations.Crm.Hubspot/Api/Management/Controllers/Forms/FormControllerBase.cs b/src/Umbraco.Forms.Integrations.Crm.Hubspot/Api/Management/Controllers/Forms/FormControllerBase.cs index 994e666..de9babb 100644 --- a/src/Umbraco.Forms.Integrations.Crm.Hubspot/Api/Management/Controllers/Forms/FormControllerBase.cs +++ b/src/Umbraco.Forms.Integrations.Crm.Hubspot/Api/Management/Controllers/Forms/FormControllerBase.cs @@ -1,19 +1,13 @@ -using Microsoft.AspNetCore.Authorization; +using Asp.Versioning; using Microsoft.AspNetCore.Mvc; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using Umbraco.Cms.Web.Common.Authorization; using Umbraco.Cms.Web.Common.Routing; using Umbraco.Forms.Core.Services; namespace Umbraco.Forms.Integrations.Crm.Hubspot.Api.Management.Controllers.Forms { + [ApiVersion("1.0")] [BackOfficeRoute($"{Constants.ManagementApi.RootPath}/v{{version:apiVersion}}/forms")] [ApiExplorerSettings(GroupName = Constants.ManagementApi.FormGroupName)] - [Authorize(Policy = AuthorizationPolicies.BackOfficeAccess)] public class FormControllerBase : HubspotControllerBase { protected readonly IFormService FormService; diff --git a/src/Umbraco.Forms.Integrations.Crm.Hubspot/Api/Management/Controllers/Forms/GetFormFieldsController.cs b/src/Umbraco.Forms.Integrations.Crm.Hubspot/Api/Management/Controllers/Forms/GetFormFieldsController.cs index 89fe6e2..4cb17fb 100644 --- a/src/Umbraco.Forms.Integrations.Crm.Hubspot/Api/Management/Controllers/Forms/GetFormFieldsController.cs +++ b/src/Umbraco.Forms.Integrations.Crm.Hubspot/Api/Management/Controllers/Forms/GetFormFieldsController.cs @@ -1,10 +1,5 @@ using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; using Umbraco.Forms.Core.Services; using Umbraco.Forms.Integrations.Crm.Hubspot.Models.Dtos; diff --git a/src/Umbraco.Forms.Integrations.Crm.Hubspot/Api/Management/Controllers/HubspotControllerBase.cs b/src/Umbraco.Forms.Integrations.Crm.Hubspot/Api/Management/Controllers/HubspotControllerBase.cs index e8f0291..b6b0dd0 100644 --- a/src/Umbraco.Forms.Integrations.Crm.Hubspot/Api/Management/Controllers/HubspotControllerBase.cs +++ b/src/Umbraco.Forms.Integrations.Crm.Hubspot/Api/Management/Controllers/HubspotControllerBase.cs @@ -1,14 +1,7 @@ -using Asp.Versioning; -using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; using Umbraco.Cms.Api.Common.Attributes; using Umbraco.Cms.Web.Common.Authorization; -using Umbraco.Cms.Web.Common.Routing; namespace Umbraco.Forms.Integrations.Crm.Hubspot.Api.Management.Controllers { diff --git a/src/Umbraco.Forms.Integrations.Crm.Hubspot/Client/src/property-editor/hubspot-mapping.property-editor.ts b/src/Umbraco.Forms.Integrations.Crm.Hubspot/Client/src/property-editor/hubspot-mapping.property-editor.ts index 725df25..5a10ae0 100644 --- a/src/Umbraco.Forms.Integrations.Crm.Hubspot/Client/src/property-editor/hubspot-mapping.property-editor.ts +++ b/src/Umbraco.Forms.Integrations.Crm.Hubspot/Client/src/property-editor/hubspot-mapping.property-editor.ts @@ -6,6 +6,7 @@ import { HubspotWorkflowFormFieldDto, Property } from '@umbraco-integrations/hub import { UUIInputEvent, UUISelectEvent } from '@umbraco-cms/backoffice/external/uui'; import { HubspotMappingValue } from '../models/hubspot.model'; import { UMB_NOTIFICATION_CONTEXT, UmbNotificationColor } from '@umbraco-cms/backoffice/notification'; +import { umbConfirmModal } from '@umbraco-cms/backoffice/modal'; const elementName = "hubspot-mapping-property-editor"; @@ -20,12 +21,6 @@ export class HubspotMappingPropertyUiElement extends UmbLitElement implements Um @state() public hubspotMappingArray : Array = []; - @state() - private selectedHubspotField: string = ""; - - @state() - private selectedFormField: string = ""; - @state() private hubspotFields: Array | undefined = []; @@ -96,9 +91,9 @@ export class HubspotMappingPropertyUiElement extends UmbLitElement implements Um async #onConnect(){ const { data } = await this.#hubspotContext.authorize(this.authorizationCode); - if(!data) return; + if (!data) return; - if(data.success){ + if (data.success){ this.authorizationStatus = "OAuth"; this.authorizationCode = ""; @@ -107,7 +102,7 @@ export class HubspotMappingPropertyUiElement extends UmbLitElement implements Um this.requestUpdate(); this.dispatchEvent(new CustomEvent("authorizationStatus")); this._showSuccess("Your Umbraco Forms installation is now connected to your HubSpot account"); - }else{ + } else{ this._showError(data.errorMessage); } } @@ -122,7 +117,13 @@ export class HubspotMappingPropertyUiElement extends UmbLitElement implements Um } async #deauthorize(){ - //TODO: add overlay to confirm deauthorize + await umbConfirmModal(this, { + color: "danger", + headline: "Confirmation", + content: "Are you sure you wish to disconnect your Hubspot account?", + confirmLabel: 'Disconnect', + }); + const { data } = await this.#hubspotContext.deauthorize(); if(!data) return; @@ -137,7 +138,7 @@ export class HubspotMappingPropertyUiElement extends UmbLitElement implements Um } this._showSuccess("Your Umbraco Forms installation is no longer connected to your HubSpot account"); - }else{ + } else{ this._showError(data.errorMessage!); } @@ -180,8 +181,7 @@ export class HubspotMappingPropertyUiElement extends UmbLitElement implements Um } #onHubspotSelectChange(e: UUISelectEvent, idx: number){ - this.selectedHubspotField = e.target.value.toString(); - this.hubspotMappingArray[idx].hubspotField = this.selectedHubspotField; + this.hubspotMappingArray[idx].hubspotField = e.target.value.toString(); this.value = JSON.stringify(this.hubspotMappingArray); this.requestUpdate(); @@ -189,8 +189,7 @@ export class HubspotMappingPropertyUiElement extends UmbLitElement implements Um } #onFormFieldSelectChange(e: UUISelectEvent, idx: number){ - this.selectedFormField = e.target.value.toString(); - this.hubspotMappingArray[idx].formField = this.selectedFormField; + this.hubspotMappingArray[idx].formField = e.target.value.toString(); this.value = JSON.stringify(this.hubspotMappingArray); this.requestUpdate(); From 28f1507ee205769bd433f4f2177d77c7c6544fc7 Mon Sep 17 00:00:00 2001 From: Nguyen Doan Thanh <145089181+dtng95@users.noreply.github.com> Date: Wed, 25 Sep 2024 15:09:45 +0700 Subject: [PATCH 08/13] Delete lit.svg --- .../Client/src/assets/lit.svg | 1 - 1 file changed, 1 deletion(-) delete mode 100644 src/Umbraco.Forms.Integrations.Crm.Hubspot/Client/src/assets/lit.svg diff --git a/src/Umbraco.Forms.Integrations.Crm.Hubspot/Client/src/assets/lit.svg b/src/Umbraco.Forms.Integrations.Crm.Hubspot/Client/src/assets/lit.svg deleted file mode 100644 index 4a9c1fe..0000000 --- a/src/Umbraco.Forms.Integrations.Crm.Hubspot/Client/src/assets/lit.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file From 99bc9d1ddafba9e7ed61f204d128155c5f850b8b Mon Sep 17 00:00:00 2001 From: Adrian Cojocariu Date: Wed, 25 Sep 2024 12:15:18 +0300 Subject: [PATCH 09/13] Restore OAuthProxy web project. --- src/Umbraco.Forms.Integrations.sln | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/Umbraco.Forms.Integrations.sln b/src/Umbraco.Forms.Integrations.sln index ba7147d..02bad23 100644 --- a/src/Umbraco.Forms.Integrations.sln +++ b/src/Umbraco.Forms.Integrations.sln @@ -37,6 +37,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Umbraco.Forms.Integrations. EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Umbraco.Forms.Integrations.Testsite.V14", "Umbraco.Forms.Integrations.Testsite.V14\Umbraco.Forms.Integrations.Testsite.V14.csproj", "{8595CB83-F6E1-485D-A776-E4EB5DA13436}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Umbraco.Cms.Integrations.OAuthProxy", "Umbraco.Cms.Integrations.OAuthProxy\Umbraco.Cms.Integrations.OAuthProxy.csproj", "{221D3F2B-0373-478B-9266-7ADE09E77F5B}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -67,6 +69,10 @@ Global {8595CB83-F6E1-485D-A776-E4EB5DA13436}.Debug|Any CPU.Build.0 = Debug|Any CPU {8595CB83-F6E1-485D-A776-E4EB5DA13436}.Release|Any CPU.ActiveCfg = Release|Any CPU {8595CB83-F6E1-485D-A776-E4EB5DA13436}.Release|Any CPU.Build.0 = Release|Any CPU + {221D3F2B-0373-478B-9266-7ADE09E77F5B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {221D3F2B-0373-478B-9266-7ADE09E77F5B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {221D3F2B-0373-478B-9266-7ADE09E77F5B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {221D3F2B-0373-478B-9266-7ADE09E77F5B}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -81,6 +87,7 @@ Global {104D2677-6B53-4FF9-BB62-A68BD1D2884E} = {B068CD05-EA88-4457-B8D9-6DB899E7EBE1} {084CA526-1E5D-4AD7-8715-C5D6342CB3A0} = {104D2677-6B53-4FF9-BB62-A68BD1D2884E} {B437434B-2A95-4C8E-AF6E-4B55D4781C70} = {B05E7FB6-2403-4971-AB34-4BE43A69FBE2} + {221D3F2B-0373-478B-9266-7ADE09E77F5B} = {621A30D4-2251-43FF-BB4A-A4808C6A67D6} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {24944114-049F-4C44-95C5-E50600988018} From 07ce1ae59d5a0c952d918b8390af22c60194a181 Mon Sep 17 00:00:00 2001 From: Nguyen Doan Thanh <145089181+dtng95@users.noreply.github.com> Date: Mon, 30 Sep 2024 17:58:08 +0700 Subject: [PATCH 10/13] V14: Integrations (HubSpot/Forms) - Namespace cleanup - Regenerate API - Update PR from comments - Remove other project references on test site --- .../Contacts/AuthorizeController.cs | 2 +- .../Client/public/vite.svg | 1 - .../Client/src/lang/manifests.ts | 70 ----------------- .../Configuration/AppSettings.cs | 19 ----- .../Configuration/ServiceConfiguration.cs | 51 ------------- .../Constants.cs | 9 +-- .../Extensions/ObjectExtensions.cs | 56 -------------- .../Filters/SignatureValidationAttribute.cs | 47 ------------ .../HubspotComposer.cs | 5 +- .../HubspotServerVariablesParsingHandler.cs | 76 ------------------- .../HubspotWorkflow.cs | 38 ++-------- .../Models/Dtos/AuthorizationRequest.cs | 4 +- .../Models/Dtos/AuthorizationResult.cs | 6 +- .../Dtos/HubspotWorkflowFormFieldDto.cs | 7 +- .../Models/MappedProperty.cs | 8 +- .../Models/Requests/PropertiesRequestV1.cs | 9 +-- .../Models/Requests/PropertiesRequestV3.cs | 6 +- .../Models/Responses/ErrorResponse.cs | 4 +- .../Models/Responses/PropertiesResponse.cs | 7 +- .../Models/Responses/Property.cs | 8 +- .../Services/BaseTokenRequest.cs | 6 +- .../Services/GetTokenRequest.cs | 6 +- .../Services/HubspotContactService.cs | 26 +++---- .../Services/IContactService.cs | 5 +- .../Services/RefreshTokenRequest.cs | 6 +- .../Services/TokenResponse.cs | 8 +- ...aco.Forms.Integrations.Testsite.V14.csproj | 2 - 27 files changed, 63 insertions(+), 429 deletions(-) delete mode 100644 src/Umbraco.Forms.Integrations.Crm.Hubspot/Client/public/vite.svg delete mode 100644 src/Umbraco.Forms.Integrations.Crm.Hubspot/Configuration/AppSettings.cs delete mode 100644 src/Umbraco.Forms.Integrations.Crm.Hubspot/Configuration/ServiceConfiguration.cs delete mode 100644 src/Umbraco.Forms.Integrations.Crm.Hubspot/Extensions/ObjectExtensions.cs delete mode 100644 src/Umbraco.Forms.Integrations.Crm.Hubspot/Filters/SignatureValidationAttribute.cs delete mode 100644 src/Umbraco.Forms.Integrations.Crm.Hubspot/HubspotServerVariablesParsingHandler.cs diff --git a/src/Umbraco.Forms.Integrations.Crm.Hubspot/Api/Management/Controllers/Contacts/AuthorizeController.cs b/src/Umbraco.Forms.Integrations.Crm.Hubspot/Api/Management/Controllers/Contacts/AuthorizeController.cs index c96fbbf..42f0903 100644 --- a/src/Umbraco.Forms.Integrations.Crm.Hubspot/Api/Management/Controllers/Contacts/AuthorizeController.cs +++ b/src/Umbraco.Forms.Integrations.Crm.Hubspot/Api/Management/Controllers/Contacts/AuthorizeController.cs @@ -13,6 +13,6 @@ public AuthorizeController(IContactService contactService) : base(contactService [HttpPost("authorize")] [ProducesResponseType(typeof(AuthorizationResult), StatusCodes.Status200OK)] - public async Task Authorize([FromBody] AuthorizationRequest request) => Ok(await ContactService.AuthorizeAsync(request.Code)); + public async Task Authorize([FromBody]AuthorizationRequest request) => Ok(await ContactService.AuthorizeAsync(request.Code)); } } diff --git a/src/Umbraco.Forms.Integrations.Crm.Hubspot/Client/public/vite.svg b/src/Umbraco.Forms.Integrations.Crm.Hubspot/Client/public/vite.svg deleted file mode 100644 index e7b8dfb..0000000 --- a/src/Umbraco.Forms.Integrations.Crm.Hubspot/Client/public/vite.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/Umbraco.Forms.Integrations.Crm.Hubspot/Client/src/lang/manifests.ts b/src/Umbraco.Forms.Integrations.Crm.Hubspot/Client/src/lang/manifests.ts index 7cfabfb..e7e0f49 100644 --- a/src/Umbraco.Forms.Integrations.Crm.Hubspot/Client/src/lang/manifests.ts +++ b/src/Umbraco.Forms.Integrations.Crm.Hubspot/Client/src/lang/manifests.ts @@ -10,76 +10,6 @@ const localizationManifests: Array = [ culture: "en", }, js: () => import("./en.js"), - // }, - // { - // type: "localization", - // alias: "Forms.Localization.Cs_CZ", - // weight: -100, - // name: "Czech", - // meta: { - // culture: "cs-cz", - // }, - // js: () => import("./cs-cz.js"), - // }, - // { - // type: "localization", - // alias: "Forms.Localization.Da_DK", - // weight: -100, - // name: "Danish", - // meta: { - // culture: "da-dk", - // }, - // js: () => import("./da-dk.js"), - // }, - // { - // type: "localization", - // alias: "Forms.Localization.En_GB", - // weight: -100, - // name: "English (UK)", - // meta: { - // culture: "en-gb", - // }, - // js: () => import("./en-gb.js"), - // }, - // { - // type: "localization", - // alias: "Forms.Localization.Es_ES", - // weight: -100, - // name: "Spanish", - // meta: { - // culture: "es-es", - // }, - // js: () => import("./es-es.js"), - // }, - // { - // type: "localization", - // alias: "Forms.Localization.Fr_FR", - // weight: -100, - // name: "French", - // meta: { - // culture: "fr-fr", - // }, - // js: () => import("./fr-fr.js"), - // }, - // { - // type: "localization", - // alias: "Forms.Localization.It_IT", - // weight: -100, - // name: "French", - // meta: { - // culture: "it-it", - // }, - // js: () => import("./it-it.js"), - // }, - // { - // type: "localization", - // alias: "Forms.Localization.Pl_PL", - // weight: -100, - // name: "Polish", - // meta: { - // culture: "pl-pl", - // }, - // js: () => import("./pl-pl.js"), }, ]; export const manifests = [...localizationManifests]; \ No newline at end of file diff --git a/src/Umbraco.Forms.Integrations.Crm.Hubspot/Configuration/AppSettings.cs b/src/Umbraco.Forms.Integrations.Crm.Hubspot/Configuration/AppSettings.cs deleted file mode 100644 index e64fb03..0000000 --- a/src/Umbraco.Forms.Integrations.Crm.Hubspot/Configuration/AppSettings.cs +++ /dev/null @@ -1,19 +0,0 @@ -namespace Umbraco.Forms.Integrations.Crm.Hubspot.Configuration -{ - public class AppSettings - { - public string HubspotClientSecret { get; set; } - - public string HubspotFormsClientSecret { get; set; } - - public string SemrushClientSecret { get; set; } - - public string ShopifyClientSecret { get; set; } - - public string GoogleClientSecret { get; set; } - - public string DynamicsClientSecret { get; set; } - - public string this[string propertyName] => (string)GetType().GetProperty(propertyName)?.GetValue(this, null); - } -} diff --git a/src/Umbraco.Forms.Integrations.Crm.Hubspot/Configuration/ServiceConfiguration.cs b/src/Umbraco.Forms.Integrations.Crm.Hubspot/Configuration/ServiceConfiguration.cs deleted file mode 100644 index ff032aa..0000000 --- a/src/Umbraco.Forms.Integrations.Crm.Hubspot/Configuration/ServiceConfiguration.cs +++ /dev/null @@ -1,51 +0,0 @@ -using System; -using System.Collections.Generic; - -using Microsoft.Extensions.DependencyInjection; - -namespace Umbraco.Forms.Integrations.Crm.Hubspot.Configuration -{ - public static class ServiceConfiguration - { - /// - /// Integrated services with their token URIs - /// - public static Dictionary ServiceProviders = new() - { - { "Hubspot", "oauth/v1/token" }, - { "HubspotForms", "oauth/v1/token" }, - { "Semrush", "oauth2/access_token" }, - { "Shopify", "oauth/access_token" }, - { "Google", "token"}, - { "Dynamics", "oauth2/v2.0/token" } - }; - - public static void AddServiceClients(this IServiceCollection services) - { - services.AddHttpClient("HubspotToken", c => - { - c.BaseAddress = new Uri("https://api.hubapi.com/"); - }); - services.AddHttpClient("HubspotFormsToken", c => - { - c.BaseAddress = new Uri("https://api.hubapi.com/"); - }); - services.AddHttpClient("SemrushToken", c => - { - c.BaseAddress = new Uri("https://oauth.semrush.com/"); - }); - services.AddHttpClient("ShopifyToken", c => - { - c.BaseAddress = new Uri("https://shop-replace.myshopify.com/admin/"); - }); - services.AddHttpClient("GoogleToken", c => - { - c.BaseAddress = new Uri("https://oauth2.googleapis.com/"); - }); - services.AddHttpClient("DynamicsToken", c => - { - c.BaseAddress = new Uri("https://login.microsoftonline.com/common/"); - }); - } - } -} diff --git a/src/Umbraco.Forms.Integrations.Crm.Hubspot/Constants.cs b/src/Umbraco.Forms.Integrations.Crm.Hubspot/Constants.cs index 815fa6d..f7876fb 100644 --- a/src/Umbraco.Forms.Integrations.Crm.Hubspot/Constants.cs +++ b/src/Umbraco.Forms.Integrations.Crm.Hubspot/Constants.cs @@ -1,10 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace Umbraco.Forms.Integrations.Crm.Hubspot +namespace Umbraco.Forms.Integrations.Crm.Hubspot { public class Constants { @@ -17,6 +11,7 @@ public static class ManagementApi public const string ApiTitle = "Hubspot Management API"; public const string ContactGroupName = "Contacts"; + public const string FormGroupName = "Forms"; } } diff --git a/src/Umbraco.Forms.Integrations.Crm.Hubspot/Extensions/ObjectExtensions.cs b/src/Umbraco.Forms.Integrations.Crm.Hubspot/Extensions/ObjectExtensions.cs deleted file mode 100644 index d358aea..0000000 --- a/src/Umbraco.Forms.Integrations.Crm.Hubspot/Extensions/ObjectExtensions.cs +++ /dev/null @@ -1,56 +0,0 @@ -using Newtonsoft.Json; -using System.Collections.Generic; -using System.Linq; -using System.Reflection; - -namespace Umbraco.Forms.Integrations.Crm.Hubspot.Extensions -{ - public static class ObjectExtensions - { - /// - /// Converts an object to a dictionary of it's properties. - /// - /// - /// Hat-tip: https://stackoverflow.com/a/4944547 - /// - public static T ToObject(this IDictionary source) - where T : class, new() - { - var obj = new T(); - var type = obj.GetType(); - - foreach (var item in source) - { - type - .GetProperty(item.Key) - .SetValue(obj, item.Value, null); - } - - return obj; - } - - /// - /// Converts an dictionary of properties to an object. - /// - /// - /// Hat-tip: https://stackoverflow.com/a/4944547 - /// - public static IDictionary AsDictionary(this object source, BindingFlags bindingAttr = BindingFlags.Public | BindingFlags.Instance) => - source.GetType().GetProperties(bindingAttr).ToDictionary - ( - propInfo => GetPropertyName(propInfo), - propInfo => (propInfo.GetValue(source, null)?.ToString()) - ); - - private static string GetPropertyName(PropertyInfo propInfo) - { - var jsonPropertyAttribute = ((JsonPropertyAttribute[])propInfo.GetCustomAttributes(typeof(JsonPropertyAttribute), true)).SingleOrDefault(); - if (jsonPropertyAttribute == null) - { - return propInfo.Name; - } - - return jsonPropertyAttribute.PropertyName; - } - } -} diff --git a/src/Umbraco.Forms.Integrations.Crm.Hubspot/Filters/SignatureValidationAttribute.cs b/src/Umbraco.Forms.Integrations.Crm.Hubspot/Filters/SignatureValidationAttribute.cs deleted file mode 100644 index 6ad90ee..0000000 --- a/src/Umbraco.Forms.Integrations.Crm.Hubspot/Filters/SignatureValidationAttribute.cs +++ /dev/null @@ -1,47 +0,0 @@ -using Microsoft.AspNetCore.Mvc; -using Microsoft.AspNetCore.Mvc.Filters; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Options; -using System; -using System.IO; -using System.Linq; -using System.Security.Cryptography; -using System.Text; -using System.Threading.Tasks; -using Umbraco.Forms.Integrations.Crm.Hubspot.Configuration; - -namespace Umbraco.Forms.Integrations.Crm.Hubspot.Filters -{ - public class SignatureValidationAttribute : ActionFilterAttribute - { - private const string HeaderKey = "X-Shopify-Hmac-Sha256"; - - public override async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next) - { - var appSettings = context.HttpContext.RequestServices.GetService>().Value; - - var hmacHeaderValues = context.HttpContext.Request.Headers - .FirstOrDefault(kvp => kvp.Key.Equals(HeaderKey, StringComparison.OrdinalIgnoreCase)).Value; - - if (hmacHeaderValues.Count == 0) - { - context.Result = new UnauthorizedResult(); - return; - } - - string hmacHeader = hmacHeaderValues.First(); - - HMACSHA256 hmac = new HMACSHA256(Encoding.UTF8.GetBytes(appSettings.ShopifyClientSecret)); - - var bodyStream = new StreamReader(context.HttpContext.Request.Body); - string requestBody = await bodyStream.ReadToEndAsync(); - string hash = Convert.ToBase64String(hmac.ComputeHash(Encoding.UTF8.GetBytes(requestBody))); - - if (hash != hmacHeader) - { - context.Result = new UnauthorizedResult(); - return; - } - } - } -} diff --git a/src/Umbraco.Forms.Integrations.Crm.Hubspot/HubspotComposer.cs b/src/Umbraco.Forms.Integrations.Crm.Hubspot/HubspotComposer.cs index f226a6a..9d25d49 100644 --- a/src/Umbraco.Forms.Integrations.Crm.Hubspot/HubspotComposer.cs +++ b/src/Umbraco.Forms.Integrations.Crm.Hubspot/HubspotComposer.cs @@ -3,7 +3,6 @@ using Swashbuckle.AspNetCore.SwaggerGen; using Umbraco.Cms.Core.Composing; using Umbraco.Cms.Core.DependencyInjection; -using Umbraco.Cms.Core.Notifications; using Umbraco.Forms.Core.Providers; using Umbraco.Forms.Integrations.Crm.Hubspot.Configuration; using Umbraco.Forms.Integrations.Crm.Hubspot.Services; @@ -19,8 +18,6 @@ public void Compose(IUmbracoBuilder builder) builder.Services.AddSingleton(); - builder.AddNotificationHandler(); - builder.WithCollectionBuilder() .Add(); @@ -33,7 +30,7 @@ public void Compose(IUmbracoBuilder builder) { Title = Constants.ManagementApi.ApiTitle, Version = "Latest", - Description = $"Describes the {Constants.ManagementApi.ApiTitle} available for handling Hubspot automation and configuration." + Description = $"Describes the {Constants.ManagementApi.ApiTitle} available for handling Hubspot-CRM automation and configuration." }); options.CustomOperationIds(e => $"{e.ActionDescriptor.RouteValues["action"]}"); diff --git a/src/Umbraco.Forms.Integrations.Crm.Hubspot/HubspotServerVariablesParsingHandler.cs b/src/Umbraco.Forms.Integrations.Crm.Hubspot/HubspotServerVariablesParsingHandler.cs deleted file mode 100644 index b21d57c..0000000 --- a/src/Umbraco.Forms.Integrations.Crm.Hubspot/HubspotServerVariablesParsingHandler.cs +++ /dev/null @@ -1,76 +0,0 @@ -using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Routing; -using Microsoft.Extensions.Options; -using System; -using System.Collections.Generic; -using System.Runtime.Serialization; -using Umbraco.Cms.Core.Events; -using Umbraco.Cms.Core.Notifications; -using Umbraco.Extensions; -using Umbraco.Forms.Integrations.Crm.Hubspot.Api.Management.Controllers; -using Umbraco.Forms.Integrations.Crm.Hubspot.Configuration; - -namespace Umbraco.Forms.Integrations.Crm.Hubspot -{ - public class HubspotServerVariablesParsingHandler : INotificationHandler - { - private readonly IHttpContextAccessor _httpContextAccessor; - private readonly LinkGenerator _linkGenerator; - private readonly HubspotSettings _settings; - - public HubspotServerVariablesParsingHandler(IHttpContextAccessor httpContextAccessor, LinkGenerator linkGenerator, IOptions options) - { - _httpContextAccessor = httpContextAccessor; - - _linkGenerator = linkGenerator; - - _settings = options.Value; - } - - public void Handle(ServerVariablesParsingNotification notification) - { - IDictionary serverVars = notification.ServerVariables; - - if (!serverVars.ContainsKey("umbracoUrls")) - { - throw new ArgumentException("Missing umbracoUrls"); - } - - var umbracoUrlsObject = serverVars["umbracoUrls"]; - if (umbracoUrlsObject == null) - { - throw new ArgumentException("Null umbracoUrls"); - } - - if (!(umbracoUrlsObject is Dictionary umbracoUrls)) - { - throw new ArgumentException("Invalid umbracoUrls"); - } - - if(_httpContextAccessor.HttpContext == null) - { - throw new InvalidOperationException("HttpContext is null"); - } - - //umbracoUrls["umbracoFormsIntegrationsCrmHubspotBaseUrl"] = - // _linkGenerator.GetUmbracoApiServiceBaseUrl(controller => controller.GetAll()); - - if (serverVars.ContainsKey("umbracoPlugins")) - { - var umbracoPlugins = (Dictionary)serverVars["umbracoPlugins"]; - umbracoPlugins.Add("umbracoFormsIntegrationsCrmHubspot", new ClientSideConfiguration - { - AllowContactUpdate = _settings.AllowContactUpdate - }); - } - - } - - [DataContract] - internal sealed class ClientSideConfiguration - { - [DataMember(Name = "allowContactUpdate")] - public bool AllowContactUpdate { get; set; } - } - } -} diff --git a/src/Umbraco.Forms.Integrations.Crm.Hubspot/HubspotWorkflow.cs b/src/Umbraco.Forms.Integrations.Crm.Hubspot/HubspotWorkflow.cs index f40afba..9e9e690 100644 --- a/src/Umbraco.Forms.Integrations.Crm.Hubspot/HubspotWorkflow.cs +++ b/src/Umbraco.Forms.Integrations.Crm.Hubspot/HubspotWorkflow.cs @@ -1,15 +1,9 @@ using Microsoft.Extensions.Logging; using Newtonsoft.Json; - -using System; -using System.Collections.Generic; -using System.Reflection; using Umbraco.Forms.Core; using Umbraco.Forms.Core.Attributes; using Umbraco.Forms.Core.Enums; -using Umbraco.Forms.Core.Interfaces; -using Umbraco.Forms.Core.Models; using Umbraco.Forms.Integrations.Crm.Hubspot.Models; using Umbraco.Forms.Integrations.Crm.Hubspot.Services; @@ -41,26 +35,27 @@ public HubspotWorkflow(ILogger logger, IContactService contactS public WorkflowExecutionStatus Execute(WorkflowExecutionContext context) { - var workflowName = GetWorkflowName(); + throw new NotImplementedException(); + } + public override async Task ExecuteAsync(WorkflowExecutionContext context) + { var fieldMappingsRawJson = FieldMappings; var fieldMappings = JsonConvert.DeserializeObject>(fieldMappingsRawJson); if (fieldMappings.Count == 0) { - _logger.LogWarning("Workflow {WorkflowName}: Missing HubSpot field mappings for workflow for the form {FormName} ({FormId})", - workflowName, context.Form.Name, context.Form.Id); + _logger.LogWarning("Save Contact to HubSpot: Missing HubSpot field mappings for workflow for the form {FormName} ({FormId})", context.Form.Name, context.Form.Id); return WorkflowExecutionStatus.NotConfigured; } - var commandResult = _contactService.PostContactAsync(context.Record, fieldMappings, null).GetAwaiter().GetResult(); + var commandResult = await _contactService.PostContactAsync(context.Record, fieldMappings, null); switch (commandResult) { case CommandResult.NotConfigured: - _logger.LogWarning("Workflow {WorkflowName}: Could not complete contact request for {FormName} ({FormId}) as the workflow is not correctly configured.", - workflowName, context.Form.Name, context.Form.Id); + _logger.LogWarning("Save Contact to HubSpot: Could not complete contact request for {FormName} ({FormId}) as the workflow is not correctly configured.", context.Form.Name, context.Form.Id); return WorkflowExecutionStatus.NotConfigured; case CommandResult.Failed: - _logger.LogWarning("Workflow {WorkflowName}: Failed for {FormName} ({FormId}).", workflowName, context.Form.Name, context.Form.Id); + _logger.LogWarning("Save Contact to HubSpot: Failed for {FormName} ({FormId}).", context.Form.Name, context.Form.Id); return WorkflowExecutionStatus.Failed; case CommandResult.Success: return WorkflowExecutionStatus.Completed; @@ -69,23 +64,6 @@ public WorkflowExecutionStatus Execute(WorkflowExecutionContext context) } } - public override Task ExecuteAsync(WorkflowExecutionContext context) - { - throw new NotImplementedException(); - } - public override List ValidateSettings() => new List(); - - /// - /// Get workflow's name using reflection in regards to breaking changes between Forms 11 and 12. - /// - /// - private string GetWorkflowName() - { - var workflow = typeof(WorkflowType).GetProperty(nameof(Workflow)).GetValue(this); - var name = workflow.GetType().GetProperty(nameof(Workflow.Name)).GetValue(workflow).ToString(); - - return name; - } } } diff --git a/src/Umbraco.Forms.Integrations.Crm.Hubspot/Models/Dtos/AuthorizationRequest.cs b/src/Umbraco.Forms.Integrations.Crm.Hubspot/Models/Dtos/AuthorizationRequest.cs index b272442..7d95e18 100644 --- a/src/Umbraco.Forms.Integrations.Crm.Hubspot/Models/Dtos/AuthorizationRequest.cs +++ b/src/Umbraco.Forms.Integrations.Crm.Hubspot/Models/Dtos/AuthorizationRequest.cs @@ -1,10 +1,10 @@ -using Newtonsoft.Json; +using System.Text.Json.Serialization; namespace Umbraco.Forms.Integrations.Crm.Hubspot.Models.Dtos { public class AuthorizationRequest { - [JsonProperty("code")] + [JsonPropertyName("code")] public string Code { get; set; } } } diff --git a/src/Umbraco.Forms.Integrations.Crm.Hubspot/Models/Dtos/AuthorizationResult.cs b/src/Umbraco.Forms.Integrations.Crm.Hubspot/Models/Dtos/AuthorizationResult.cs index f7506a2..46fdbbd 100644 --- a/src/Umbraco.Forms.Integrations.Crm.Hubspot/Models/Dtos/AuthorizationResult.cs +++ b/src/Umbraco.Forms.Integrations.Crm.Hubspot/Models/Dtos/AuthorizationResult.cs @@ -1,4 +1,4 @@ -using Newtonsoft.Json; +using System.Text.Json.Serialization; namespace Umbraco.Forms.Integrations.Crm.Hubspot.Models.Dtos { @@ -8,10 +8,10 @@ private AuthorizationResult() { } - [JsonProperty("success")] + [JsonPropertyName("success")] public bool Success { get; private set; } - [JsonProperty("errorMessage")] + [JsonPropertyName("errorMessage")] public string ErrorMessage { get; private set; } public static AuthorizationResult AsSuccess() => diff --git a/src/Umbraco.Forms.Integrations.Crm.Hubspot/Models/Dtos/HubspotWorkflowFormFieldDto.cs b/src/Umbraco.Forms.Integrations.Crm.Hubspot/Models/Dtos/HubspotWorkflowFormFieldDto.cs index 01653e0..e8283ce 100644 --- a/src/Umbraco.Forms.Integrations.Crm.Hubspot/Models/Dtos/HubspotWorkflowFormFieldDto.cs +++ b/src/Umbraco.Forms.Integrations.Crm.Hubspot/Models/Dtos/HubspotWorkflowFormFieldDto.cs @@ -1,9 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Runtime.Serialization; -using System.Text; -using System.Threading.Tasks; +using System.Runtime.Serialization; namespace Umbraco.Forms.Integrations.Crm.Hubspot.Models.Dtos { diff --git a/src/Umbraco.Forms.Integrations.Crm.Hubspot/Models/MappedProperty.cs b/src/Umbraco.Forms.Integrations.Crm.Hubspot/Models/MappedProperty.cs index 70b8189..dd96d5e 100644 --- a/src/Umbraco.Forms.Integrations.Crm.Hubspot/Models/MappedProperty.cs +++ b/src/Umbraco.Forms.Integrations.Crm.Hubspot/Models/MappedProperty.cs @@ -1,16 +1,16 @@ -using Newtonsoft.Json; +using System.Text.Json.Serialization; namespace Umbraco.Forms.Integrations.Crm.Hubspot.Models { public class MappedProperty { - [JsonProperty(PropertyName = "formField")] + [JsonPropertyName("formField")] public string FormField { get; set; } - [JsonProperty(PropertyName = "hubspotField")] + [JsonPropertyName("hubspotField")] public string HubspotField { get; set; } - [JsonProperty(PropertyName = "appendValue")] + [JsonPropertyName("appendValue")] public bool AppendValue { get; set; } } } diff --git a/src/Umbraco.Forms.Integrations.Crm.Hubspot/Models/Requests/PropertiesRequestV1.cs b/src/Umbraco.Forms.Integrations.Crm.Hubspot/Models/Requests/PropertiesRequestV1.cs index e230a25..ee2c6db 100644 --- a/src/Umbraco.Forms.Integrations.Crm.Hubspot/Models/Requests/PropertiesRequestV1.cs +++ b/src/Umbraco.Forms.Integrations.Crm.Hubspot/Models/Requests/PropertiesRequestV1.cs @@ -1,11 +1,10 @@ -using Newtonsoft.Json; -using System.Collections.Generic; +using System.Text.Json.Serialization; namespace Umbraco.Forms.Integrations.Crm.Hubspot { internal class PropertiesRequestV1 { - [JsonProperty(PropertyName = "properties")] + [JsonPropertyName("properties")] public IList Properties { get; set; } = new List(); internal class PropertyValue @@ -16,10 +15,10 @@ public PropertyValue(string property, string value) Value = value; } - [JsonProperty(PropertyName = "property")] + [JsonPropertyName("property")] public string Property { get; } - [JsonProperty(PropertyName = "value")] + [JsonPropertyName("value")] public string Value { get; } } } diff --git a/src/Umbraco.Forms.Integrations.Crm.Hubspot/Models/Requests/PropertiesRequestV3.cs b/src/Umbraco.Forms.Integrations.Crm.Hubspot/Models/Requests/PropertiesRequestV3.cs index 12a4337..825f2d5 100644 --- a/src/Umbraco.Forms.Integrations.Crm.Hubspot/Models/Requests/PropertiesRequestV3.cs +++ b/src/Umbraco.Forms.Integrations.Crm.Hubspot/Models/Requests/PropertiesRequestV3.cs @@ -1,11 +1,11 @@ -using Newtonsoft.Json; -using Newtonsoft.Json.Linq; +using Newtonsoft.Json.Linq; +using System.Text.Json.Serialization; namespace Umbraco.Forms.Integrations.Crm.Hubspot { internal class PropertiesRequestV3 { - [JsonProperty(PropertyName = "properties")] + [JsonPropertyName("properties")] public JObject Properties { get; set; } = new JObject(); } } diff --git a/src/Umbraco.Forms.Integrations.Crm.Hubspot/Models/Responses/ErrorResponse.cs b/src/Umbraco.Forms.Integrations.Crm.Hubspot/Models/Responses/ErrorResponse.cs index 7eff2d1..4997f30 100644 --- a/src/Umbraco.Forms.Integrations.Crm.Hubspot/Models/Responses/ErrorResponse.cs +++ b/src/Umbraco.Forms.Integrations.Crm.Hubspot/Models/Responses/ErrorResponse.cs @@ -1,10 +1,10 @@ -using Newtonsoft.Json; +using System.Text.Json.Serialization; namespace Umbraco.Forms.Integrations.Crm.Hubspot.Models.Responses { public class ErrorResponse { - [JsonProperty(PropertyName = "message")] + [JsonPropertyName("message")] public string Message { get; set; } } } diff --git a/src/Umbraco.Forms.Integrations.Crm.Hubspot/Models/Responses/PropertiesResponse.cs b/src/Umbraco.Forms.Integrations.Crm.Hubspot/Models/Responses/PropertiesResponse.cs index 0ae0231..c466a41 100644 --- a/src/Umbraco.Forms.Integrations.Crm.Hubspot/Models/Responses/PropertiesResponse.cs +++ b/src/Umbraco.Forms.Integrations.Crm.Hubspot/Models/Responses/PropertiesResponse.cs @@ -1,11 +1,10 @@ -using Newtonsoft.Json; -using System.Collections.Generic; +using System.Text.Json.Serialization; namespace Umbraco.Forms.Integrations.Crm.Hubspot.Models.Responses { public class PropertiesResponse { - [JsonProperty(PropertyName = "results")] + [JsonPropertyName("results")] public List Results { get; set; } } -} +} \ No newline at end of file diff --git a/src/Umbraco.Forms.Integrations.Crm.Hubspot/Models/Responses/Property.cs b/src/Umbraco.Forms.Integrations.Crm.Hubspot/Models/Responses/Property.cs index 35f0cf7..461d4c9 100644 --- a/src/Umbraco.Forms.Integrations.Crm.Hubspot/Models/Responses/Property.cs +++ b/src/Umbraco.Forms.Integrations.Crm.Hubspot/Models/Responses/Property.cs @@ -1,16 +1,16 @@ -using Newtonsoft.Json; +using System.Text.Json.Serialization; namespace Umbraco.Forms.Integrations.Crm.Hubspot.Models.Responses { public class Property { - [JsonProperty(PropertyName = "name")] + [JsonPropertyName("name")] public string Name { get; set; } - [JsonProperty(PropertyName = "label")] + [JsonPropertyName("label")] public string Label { get; set; } - [JsonProperty(PropertyName = "description")] + [JsonPropertyName("description")] public string Description { get; set; } } } diff --git a/src/Umbraco.Forms.Integrations.Crm.Hubspot/Services/BaseTokenRequest.cs b/src/Umbraco.Forms.Integrations.Crm.Hubspot/Services/BaseTokenRequest.cs index c1cce7e..87cbb0a 100644 --- a/src/Umbraco.Forms.Integrations.Crm.Hubspot/Services/BaseTokenRequest.cs +++ b/src/Umbraco.Forms.Integrations.Crm.Hubspot/Services/BaseTokenRequest.cs @@ -1,4 +1,4 @@ -using Newtonsoft.Json; +using System.Text.Json.Serialization; namespace Umbraco.Forms.Integrations.Crm.Hubspot.Services { @@ -6,10 +6,10 @@ internal abstract class BaseTokenRequest { public abstract string GrantType { get; } - [JsonProperty("client_id")] + [JsonPropertyName("client_id")] public string ClientId { get; set; } - [JsonProperty("redirect_uri")] + [JsonPropertyName("redirect_uri")] public string RedirectUrl { get; set; } } } diff --git a/src/Umbraco.Forms.Integrations.Crm.Hubspot/Services/GetTokenRequest.cs b/src/Umbraco.Forms.Integrations.Crm.Hubspot/Services/GetTokenRequest.cs index 7a4bbd3..2dec747 100644 --- a/src/Umbraco.Forms.Integrations.Crm.Hubspot/Services/GetTokenRequest.cs +++ b/src/Umbraco.Forms.Integrations.Crm.Hubspot/Services/GetTokenRequest.cs @@ -1,13 +1,13 @@ -using Newtonsoft.Json; +using System.Text.Json.Serialization; namespace Umbraco.Forms.Integrations.Crm.Hubspot.Services { internal class GetTokenRequest : BaseTokenRequest { - [JsonProperty("grant_type")] + [JsonPropertyName("grant_type")] public override string GrantType => "authorization_code"; - [JsonProperty("code")] + [JsonPropertyName("code")] public string AuthorizationCode { get; set; } } } diff --git a/src/Umbraco.Forms.Integrations.Crm.Hubspot/Services/HubspotContactService.cs b/src/Umbraco.Forms.Integrations.Crm.Hubspot/Services/HubspotContactService.cs index 8ec3024..da0b3c0 100644 --- a/src/Umbraco.Forms.Integrations.Crm.Hubspot/Services/HubspotContactService.cs +++ b/src/Umbraco.Forms.Integrations.Crm.Hubspot/Services/HubspotContactService.cs @@ -1,18 +1,12 @@ -using Microsoft.Extensions.Configuration; -using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; -using Newtonsoft.Json; -using System; -using System.Collections.Generic; -using System.Linq; using System.Net; -using System.Net.Http; using System.Net.Http.Headers; using System.Text; -using System.Threading.Tasks; - +using System.Text.Json; using Umbraco.Cms.Core.Cache; using Umbraco.Cms.Core.Services; +using Umbraco.Extensions; using Umbraco.Forms.Core.Persistence.Dtos; using Umbraco.Forms.Integrations.Crm.Hubspot.Configuration; using Umbraco.Forms.Integrations.Crm.Hubspot.Extensions; @@ -78,7 +72,7 @@ public async Task AuthorizeAsync(string code) if (response.IsSuccessStatusCode) { var responseContent = await response.Content.ReadAsStringAsync(); - var tokenResponse = JsonConvert.DeserializeObject(responseContent); + var tokenResponse = JsonSerializer.Deserialize(responseContent); // Add the access token details to the cache. _appCaches.RuntimeCache.Insert(AccessTokenCacheKey, () => tokenResponse.AccessToken); @@ -132,7 +126,7 @@ public async Task> GetContactPropertiesAsync() // Map the properties to our simpler object, as we don't need all the fields in the response. var properties = new List(); var responseContent = await response.Content.ReadAsStringAsync(); - var responseContentAsJson = JsonConvert.DeserializeObject(responseContent); + var responseContentAsJson = JsonSerializer.Deserialize(responseContent); properties.AddRange(responseContentAsJson.Results); return properties.OrderBy(x => x.Label); } @@ -333,7 +327,7 @@ private async Task RefreshOAuthAccessToken(string refreshToken) if (response.IsSuccessStatusCode) { var responseContent = await response.Content.ReadAsStringAsync(); - var tokenResponse = JsonConvert.DeserializeObject(responseContent); + var tokenResponse = JsonSerializer.Deserialize(responseContent); // Update the token details in the cache. _appCaches.RuntimeCache.Insert(AccessTokenCacheKey, () => tokenResponse.AccessToken); @@ -365,7 +359,7 @@ private async Task GetResponse( string contentType = null) { var httpClient = _httpClientFactory.CreateClient(); - + var requestMessage = new HttpRequestMessage { Method = httpMethod, @@ -406,10 +400,12 @@ private static HttpContent CreateRequestContent(object data, string contentType) switch (contentType) { case JsonContentType: - var serializedData = JsonConvert.SerializeObject(data); + var serializedData = JsonSerializer.Serialize(data); return new StringContent(serializedData, Encoding.UTF8, contentType); case "application/x-www-form-urlencoded": - return new FormUrlEncodedContent(data.AsDictionary()); + var json = JsonSerializer.Serialize(data); + var dictionary = JsonSerializer.Deserialize>(json); + return new FormUrlEncodedContent(dictionary); default: throw new InvalidOperationException($"Unexpected content type: {contentType}"); } diff --git a/src/Umbraco.Forms.Integrations.Crm.Hubspot/Services/IContactService.cs b/src/Umbraco.Forms.Integrations.Crm.Hubspot/Services/IContactService.cs index ba8113f..f9af375 100644 --- a/src/Umbraco.Forms.Integrations.Crm.Hubspot/Services/IContactService.cs +++ b/src/Umbraco.Forms.Integrations.Crm.Hubspot/Services/IContactService.cs @@ -1,7 +1,4 @@ -using System.Collections.Generic; -using System.Threading.Tasks; - -using Umbraco.Forms.Core.Persistence.Dtos; +using Umbraco.Forms.Core.Persistence.Dtos; using Umbraco.Forms.Integrations.Crm.Hubspot.Models; using Umbraco.Forms.Integrations.Crm.Hubspot.Models.Dtos; using Umbraco.Forms.Integrations.Crm.Hubspot.Models.Responses; diff --git a/src/Umbraco.Forms.Integrations.Crm.Hubspot/Services/RefreshTokenRequest.cs b/src/Umbraco.Forms.Integrations.Crm.Hubspot/Services/RefreshTokenRequest.cs index f149bb0..f59a5f5 100644 --- a/src/Umbraco.Forms.Integrations.Crm.Hubspot/Services/RefreshTokenRequest.cs +++ b/src/Umbraco.Forms.Integrations.Crm.Hubspot/Services/RefreshTokenRequest.cs @@ -1,13 +1,13 @@ -using Newtonsoft.Json; +using System.Text.Json.Serialization; namespace Umbraco.Forms.Integrations.Crm.Hubspot.Services { internal class RefreshTokenRequest : BaseTokenRequest { - [JsonProperty("grant_type")] + [JsonPropertyName("grant_type")] public override string GrantType => "refresh_token"; - [JsonProperty("refresh_token")] + [JsonPropertyName("refresh_token")] public string RefreshToken { get; set; } } } diff --git a/src/Umbraco.Forms.Integrations.Crm.Hubspot/Services/TokenResponse.cs b/src/Umbraco.Forms.Integrations.Crm.Hubspot/Services/TokenResponse.cs index 9eb8bc7..926b412 100644 --- a/src/Umbraco.Forms.Integrations.Crm.Hubspot/Services/TokenResponse.cs +++ b/src/Umbraco.Forms.Integrations.Crm.Hubspot/Services/TokenResponse.cs @@ -1,16 +1,16 @@ -using Newtonsoft.Json; +using System.Text.Json.Serialization; namespace Umbraco.Forms.Integrations.Crm.Hubspot.Services { internal class TokenResponse { - [JsonProperty("refresh_token")] + [JsonPropertyName("refresh_token")] public string RefreshToken { get; set; } - [JsonProperty("access_token")] + [JsonPropertyName("access_token")] public string AccessToken { get; set; } - [JsonProperty("expires_in")] + [JsonPropertyName("expires_in")] public int ExpiresInSeconds { get; set; } } } diff --git a/src/Umbraco.Forms.Integrations.Testsite.V14/Umbraco.Forms.Integrations.Testsite.V14.csproj b/src/Umbraco.Forms.Integrations.Testsite.V14/Umbraco.Forms.Integrations.Testsite.V14.csproj index 796e334..7025e45 100644 --- a/src/Umbraco.Forms.Integrations.Testsite.V14/Umbraco.Forms.Integrations.Testsite.V14.csproj +++ b/src/Umbraco.Forms.Integrations.Testsite.V14/Umbraco.Forms.Integrations.Testsite.V14.csproj @@ -12,8 +12,6 @@ - - From 2da311f56e3025ff6041d52f2f9901b602bd1933 Mon Sep 17 00:00:00 2001 From: Adrian Cojocariu Date: Tue, 1 Oct 2024 15:59:25 +0300 Subject: [PATCH 11/13] Replace JObject with JsonObject --- .../Models/Requests/PropertiesRequestV3.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Umbraco.Forms.Integrations.Crm.Hubspot/Models/Requests/PropertiesRequestV3.cs b/src/Umbraco.Forms.Integrations.Crm.Hubspot/Models/Requests/PropertiesRequestV3.cs index 825f2d5..4d2b443 100644 --- a/src/Umbraco.Forms.Integrations.Crm.Hubspot/Models/Requests/PropertiesRequestV3.cs +++ b/src/Umbraco.Forms.Integrations.Crm.Hubspot/Models/Requests/PropertiesRequestV3.cs @@ -1,4 +1,4 @@ -using Newtonsoft.Json.Linq; +using System.Text.Json.Nodes; using System.Text.Json.Serialization; namespace Umbraco.Forms.Integrations.Crm.Hubspot @@ -6,6 +6,6 @@ namespace Umbraco.Forms.Integrations.Crm.Hubspot internal class PropertiesRequestV3 { [JsonPropertyName("properties")] - public JObject Properties { get; set; } = new JObject(); + public JsonObject Properties { get; set; } = new JsonObject(); } } From f4e20534e4106c75e6c3f4b85cee810644fb7395 Mon Sep 17 00:00:00 2001 From: Nguyen Doan Thanh <145089181+dtng95@users.noreply.github.com> Date: Wed, 2 Oct 2024 15:31:56 +0700 Subject: [PATCH 12/13] V14 Integrations (Semrush) - Minor changes --- .../Client/src/lang/en.ts | 2 +- .../Constants.cs | 2 +- .../HubspotComposer.cs | 2 +- .../HubspotWorkflow.cs | 10 ++-------- .../Services/HubspotContactService.cs | 18 +++++++++--------- 5 files changed, 14 insertions(+), 20 deletions(-) diff --git a/src/Umbraco.Forms.Integrations.Crm.Hubspot/Client/src/lang/en.ts b/src/Umbraco.Forms.Integrations.Crm.Hubspot/Client/src/lang/en.ts index 944d888..21b0f91 100644 --- a/src/Umbraco.Forms.Integrations.Crm.Hubspot/Client/src/lang/en.ts +++ b/src/Umbraco.Forms.Integrations.Crm.Hubspot/Client/src/lang/en.ts @@ -5,7 +5,7 @@ export default { FieldMappingsDescription: `Map Umbraco Form fields to Hubspot contact fields`, }, hubspotFormWorkflow:{ - SelectHubspotField : `Select Hubspot field`, + SelectHubspotField : `Select HubSpot field`, SelectFormField: `Select Form field`, }, } as UmbLocalizationDictionary; \ No newline at end of file diff --git a/src/Umbraco.Forms.Integrations.Crm.Hubspot/Constants.cs b/src/Umbraco.Forms.Integrations.Crm.Hubspot/Constants.cs index f7876fb..7c2b253 100644 --- a/src/Umbraco.Forms.Integrations.Crm.Hubspot/Constants.cs +++ b/src/Umbraco.Forms.Integrations.Crm.Hubspot/Constants.cs @@ -8,7 +8,7 @@ public static class ManagementApi public const string ApiName = "hubspot-management"; - public const string ApiTitle = "Hubspot Management API"; + public const string ApiTitle = "HubSpot Management API"; public const string ContactGroupName = "Contacts"; diff --git a/src/Umbraco.Forms.Integrations.Crm.Hubspot/HubspotComposer.cs b/src/Umbraco.Forms.Integrations.Crm.Hubspot/HubspotComposer.cs index 9d25d49..bd78c26 100644 --- a/src/Umbraco.Forms.Integrations.Crm.Hubspot/HubspotComposer.cs +++ b/src/Umbraco.Forms.Integrations.Crm.Hubspot/HubspotComposer.cs @@ -30,7 +30,7 @@ public void Compose(IUmbracoBuilder builder) { Title = Constants.ManagementApi.ApiTitle, Version = "Latest", - Description = $"Describes the {Constants.ManagementApi.ApiTitle} available for handling Hubspot-CRM automation and configuration." + Description = $"Describes the {Constants.ManagementApi.ApiTitle} available for handling HubSpot CRM automation and configuration." }); options.CustomOperationIds(e => $"{e.ActionDescriptor.RouteValues["action"]}"); diff --git a/src/Umbraco.Forms.Integrations.Crm.Hubspot/HubspotWorkflow.cs b/src/Umbraco.Forms.Integrations.Crm.Hubspot/HubspotWorkflow.cs index 9e9e690..2af79c5 100644 --- a/src/Umbraco.Forms.Integrations.Crm.Hubspot/HubspotWorkflow.cs +++ b/src/Umbraco.Forms.Integrations.Crm.Hubspot/HubspotWorkflow.cs @@ -1,6 +1,5 @@ using Microsoft.Extensions.Logging; - -using Newtonsoft.Json; +using System.Text.Json; using Umbraco.Forms.Core; using Umbraco.Forms.Core.Attributes; using Umbraco.Forms.Core.Enums; @@ -33,15 +32,10 @@ public HubspotWorkflow(ILogger logger, IContactService contactS [Setting("Field Mappings", Description = "Map Umbraco Form fields to HubSpot contact fields", View = "Hubspot.PropertyEditorUi.Mapping")] public string FieldMappings { get; set; } - public WorkflowExecutionStatus Execute(WorkflowExecutionContext context) - { - throw new NotImplementedException(); - } - public override async Task ExecuteAsync(WorkflowExecutionContext context) { var fieldMappingsRawJson = FieldMappings; - var fieldMappings = JsonConvert.DeserializeObject>(fieldMappingsRawJson); + var fieldMappings = JsonSerializer.Deserialize>(fieldMappingsRawJson); if (fieldMappings.Count == 0) { _logger.LogWarning("Save Contact to HubSpot: Missing HubSpot field mappings for workflow for the form {FormName} ({FormId})", context.Form.Name, context.Form.Id); diff --git a/src/Umbraco.Forms.Integrations.Crm.Hubspot/Services/HubspotContactService.cs b/src/Umbraco.Forms.Integrations.Crm.Hubspot/Services/HubspotContactService.cs index da0b3c0..3bcb96b 100644 --- a/src/Umbraco.Forms.Integrations.Crm.Hubspot/Services/HubspotContactService.cs +++ b/src/Umbraco.Forms.Integrations.Crm.Hubspot/Services/HubspotContactService.cs @@ -68,7 +68,7 @@ public async Task AuthorizeAsync(string code) AuthorizationCode = code, }; var response = await GetResponse(OAuthTokenProxyUrl, - HttpMethod.Post, content: tokenRequest, contentType: "application/x-www-form-urlencoded").ConfigureAwait(false); + HttpMethod.Post, content: tokenRequest, contentType: "application/x-www-form-urlencoded"); if (response.IsSuccessStatusCode) { var responseContent = await response.Content.ReadAsStringAsync(); @@ -108,7 +108,7 @@ public async Task> GetContactPropertiesAsync() var requestUrl = $"{CrmV3ApiBaseUrl}properties/contacts"; var httpMethod = HttpMethod.Get; - var response = await GetResponse(requestUrl, httpMethod, authenticationDetails).ConfigureAwait(false); + var response = await GetResponse(requestUrl, httpMethod, authenticationDetails); if (response.IsSuccessStatusCode == false) { var retryResult = await HandleFailedRequest(response.StatusCode, requestUrl, httpMethod, authenticationDetails); @@ -190,7 +190,7 @@ public async Task PostContactAsync(Record record, List UpdateContactAsync(Record record, Authenticati // It uses the V1 API but support suggests it will be added to V3 before being depreciated so we can use safely: // https://community.hubspot.com/t5/APIs-Integrations/Get-Contacts-from-contact-list-using-email/m-p/419493/highlight/true#M41567 var requestUrl = $"{CrmApiHost}/contacts/v1/contact/email/{email}/profile"; - var response = await GetResponse(requestUrl, HttpMethod.Post, authenticationDetails, postData, JsonContentType).ConfigureAwait(false); + var response = await GetResponse(requestUrl, HttpMethod.Post, authenticationDetails, postData, JsonContentType); if (response.IsSuccessStatusCode == false) { var retryResult = await HandleFailedRequest(response.StatusCode, requestUrl, HttpMethod.Post, authenticationDetails, postData, JsonContentType); @@ -308,7 +308,7 @@ private async Task GetOAuthAccessTokenFromCacheOrRefreshToken(string ref if (accessToken != null) { // No access token in the cache, so get a new one from the refresh token. - await RefreshOAuthAccessToken(refreshToken).ConfigureAwait(false); + await RefreshOAuthAccessToken(refreshToken); accessToken = _appCaches.RuntimeCache.Get(AccessTokenCacheKey).ToString(); } @@ -323,7 +323,7 @@ private async Task RefreshOAuthAccessToken(string refreshToken) RedirectUrl = OAuthRedirectUrl, RefreshToken = refreshToken, }; - var response = await GetResponse(OAuthTokenProxyUrl, HttpMethod.Post, content: tokenRequest, contentType: "application/x-www-form-urlencoded").ConfigureAwait(false); + var response = await GetResponse(OAuthTokenProxyUrl, HttpMethod.Post, content: tokenRequest, contentType: "application/x-www-form-urlencoded"); if (response.IsSuccessStatusCode) { var responseContent = await response.Content.ReadAsStringAsync(); @@ -382,12 +382,12 @@ private async Task GetResponse( case AuthenticationMode.OAuth: requestMessage.Headers.Authorization = new AuthenticationHeaderValue("Bearer", - await GetOAuthAccessTokenFromCacheOrRefreshToken(authenticationDetails.RefreshToken).ConfigureAwait(false)); + await GetOAuthAccessTokenFromCacheOrRefreshToken(authenticationDetails.RefreshToken)); break; } } - return await httpClient.SendAsync(requestMessage).ConfigureAwait(false); + return await httpClient.SendAsync(requestMessage); } private static HttpContent CreateRequestContent(object data, string contentType) @@ -430,7 +430,7 @@ private async Task HandleFailedRequest( await RefreshOAuthAccessToken(authenticationDetails.RefreshToken); // Repeat the operation using the refreshed token. - var response = await GetResponse(requestUrl, httpMethod, authenticationDetails, content, contentType).ConfigureAwait(false); + var response = await GetResponse(requestUrl, httpMethod, authenticationDetails, content, contentType); if (response.IsSuccessStatusCode) { result.Success = true; From 7c5c5a91e3802c0cc0e14a72a221d5a0c51c9f8c Mon Sep 17 00:00:00 2001 From: Nguyen Doan Thanh <145089181+dtng95@users.noreply.github.com> Date: Wed, 2 Oct 2024 16:30:21 +0700 Subject: [PATCH 13/13] Update Umbraco.Forms.Integrations.Testsite.V14.csproj - remove Hubspot reference from test site --- .../Umbraco.Forms.Integrations.Testsite.V14.csproj | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/Umbraco.Forms.Integrations.Testsite.V14/Umbraco.Forms.Integrations.Testsite.V14.csproj b/src/Umbraco.Forms.Integrations.Testsite.V14/Umbraco.Forms.Integrations.Testsite.V14.csproj index 7025e45..ac6c694 100644 --- a/src/Umbraco.Forms.Integrations.Testsite.V14/Umbraco.Forms.Integrations.Testsite.V14.csproj +++ b/src/Umbraco.Forms.Integrations.Testsite.V14/Umbraco.Forms.Integrations.Testsite.V14.csproj @@ -11,10 +11,6 @@ - - - - true