From c2cc455fb6549bb37c8ed57101dac9319f3d37c5 Mon Sep 17 00:00:00 2001 From: balajisoundar Date: Mon, 9 Oct 2023 21:25:50 +0530 Subject: [PATCH] fix: [one-click-binding] gsheets connection mode issue (#27613) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Description Updated the permission check on the Google sheet to look in the following path `atasourceConfiguration.authentication.scopeString` #### PR fixes following issue(s) Fixes https://github.com/appsmithorg/appsmith/issues/27102 > if no issue exists, please create an issue and ask the maintainers about this first > > #### Media > A video or a GIF is preferred. when using Loom, don’t embed because it looks like it’s a GIF. instead, just link to the video > > #### Type of change > Please delete options that are not relevant. - Bug fix (non-breaking change which fixes an issue) - New feature (non-breaking change which adds functionality) - Breaking change (fix or feature that would cause existing functionality to not work as expected) - Chore (housekeeping or task changes that don't impact user perception) - This change requires a documentation update > > > ## Testing > #### How Has This Been Tested? > Please describe the tests that you ran to verify your changes. Also list any relevant details for your test configuration. > Delete anything that is not relevant - [ ] Manual - [ ] JUnit - [ ] Jest - [ ] Cypress > > #### Test Plan > Add Testsmith test cases links that relate to this PR > > #### Issues raised during DP testing > Link issues raised during DP testing for better visiblity and tracking (copy link from comments dropped on this PR) > > > ## Checklist: #### Dev activity - [ ] My code follows the style guidelines of this project - [ ] I have performed a self-review of my own code - [ ] I have commented my code, particularly in hard-to-understand areas - [ ] I have made corresponding changes to the documentation - [ ] My changes generate no new warnings - [ ] I have added tests that prove my fix is effective or that my feature works - [ ] New and existing unit tests pass locally with my changes - [ ] PR is being merged under a feature flag #### QA activity: - [ ] [Speedbreak features](https://github.com/appsmithorg/TestSmith/wiki/Guidelines-for-test-plans#speedbreakers-) have been covered - [ ] Test plan covers all impacted features and [areas of interest](https://github.com/appsmithorg/TestSmith/wiki/Guidelines-for-test-plans#areas-of-interest-) - [ ] Test plan has been peer reviewed by project stakeholders and other QA members - [ ] Manually tested functionality on DP - [ ] We had an implementation alignment call with stakeholders post QA Round 2 - [ ] Cypress test cases have been added and approved by SDET/manual QA - [ ] Added `Test Plan Approved` label after Cypress tests were reviewed - [ ] Added `Test Plan Approved` label after JUnit tests were reviewed --- .../BaseQueryGenerator.ts | 10 +++- .../WidgetQueryGenerators/GSheets/index.ts | 12 ++++ .../useSource/useDatasourceOptions.tsx | 9 +-- .../WidgetQueryGeneratorForm/utils.test.ts | 58 +++++++++++++++++++ .../WidgetQueryGeneratorForm/utils.ts | 11 ++++ app/client/src/entities/Datasource/index.ts | 1 + 6 files changed, 96 insertions(+), 5 deletions(-) create mode 100644 app/client/src/components/editorComponents/WidgetQueryGeneratorForm/utils.test.ts diff --git a/app/client/src/WidgetQueryGenerators/BaseQueryGenerator.ts b/app/client/src/WidgetQueryGenerators/BaseQueryGenerator.ts index 8aab940a82..e93e6bc137 100644 --- a/app/client/src/WidgetQueryGenerators/BaseQueryGenerator.ts +++ b/app/client/src/WidgetQueryGenerators/BaseQueryGenerator.ts @@ -1 +1,9 @@ -export class BaseQueryGenerator {} +import type { DatasourceStorage } from "entities/Datasource"; + +export class BaseQueryGenerator { + static getConnectionMode( + datasourceConfiguration: DatasourceStorage["datasourceConfiguration"], + ) { + return datasourceConfiguration?.connection?.mode; + } +} diff --git a/app/client/src/WidgetQueryGenerators/GSheets/index.ts b/app/client/src/WidgetQueryGenerators/GSheets/index.ts index b55765c26f..b79a1ef3b4 100644 --- a/app/client/src/WidgetQueryGenerators/GSheets/index.ts +++ b/app/client/src/WidgetQueryGenerators/GSheets/index.ts @@ -9,6 +9,7 @@ import type { } from "WidgetQueryGenerators/types"; import { removeSpecialChars } from "utils/helpers"; import { DatasourceConnectionMode } from "entities/Datasource"; +import type { DatasourceStorage } from "entities/Datasource"; enum COMMAND_TYPES { "FIND" = "FETCH_MANY", @@ -47,6 +48,7 @@ export default abstract class GSheets extends BaseQueryGenerator { }, }; } + private static buildFind( widgetConfig: WidgetQueryGenerationConfig, formConfig: WidgetQueryGenerationFormConfig, @@ -306,6 +308,16 @@ export default abstract class GSheets extends BaseQueryGenerator { return configs.filter((val) => !!val); } + static getConnectionMode( + datasourceConfiguration: DatasourceStorage["datasourceConfiguration"], + ) { + return datasourceConfiguration?.authentication?.scopeString?.includes( + "spreadsheets.readonly", + ) + ? DatasourceConnectionMode.READ_ONLY + : DatasourceConnectionMode.READ_WRITE; + } + static getTotalRecordExpression(binding: string) { return `${binding}.length`; } diff --git a/app/client/src/components/editorComponents/WidgetQueryGeneratorForm/CommonControls/DatasourceDropdown/useSource/useDatasourceOptions.tsx b/app/client/src/components/editorComponents/WidgetQueryGeneratorForm/CommonControls/DatasourceDropdown/useSource/useDatasourceOptions.tsx index 16af43a257..b438d9dac4 100644 --- a/app/client/src/components/editorComponents/WidgetQueryGeneratorForm/CommonControls/DatasourceDropdown/useSource/useDatasourceOptions.tsx +++ b/app/client/src/components/editorComponents/WidgetQueryGeneratorForm/CommonControls/DatasourceDropdown/useSource/useDatasourceOptions.tsx @@ -33,6 +33,7 @@ import { getCurrentWorkspaceId } from "@appsmith/selectors/workspaceSelectors"; import type { WidgetProps } from "widgets/BaseWidget"; import { WidgetQueryGeneratorFormContext } from "components/editorComponents/WidgetQueryGeneratorForm/index"; import { getAssetUrl } from "@appsmith/utils/airgapHelpers"; +import { getDatasourceConnectionMode } from "components/editorComponents/WidgetQueryGeneratorForm/utils"; interface DatasourceOptionsProps { widget: WidgetProps; @@ -83,10 +84,10 @@ function useDatasourceOptions(props: DatasourceOptionsProps) { isValid: isEnvironmentValid(datasource, currentEnvironment), pluginPackageName: pluginsPackageNamesMap[datasource.pluginId], isSample: false, - connectionMode: getEnvironmentConfiguration( - datasource, - currentEnvironment, - )?.connection?.mode, + connectionMode: getDatasourceConnectionMode( + pluginsPackageNamesMap[datasource.pluginId], + getEnvironmentConfiguration(datasource, currentEnvironment), + ), }, icon: ( diff --git a/app/client/src/components/editorComponents/WidgetQueryGeneratorForm/utils.test.ts b/app/client/src/components/editorComponents/WidgetQueryGeneratorForm/utils.test.ts new file mode 100644 index 0000000000..135c90005d --- /dev/null +++ b/app/client/src/components/editorComponents/WidgetQueryGeneratorForm/utils.test.ts @@ -0,0 +1,58 @@ +import WidgetQueryGeneratorRegistry from "utils/WidgetQueryGeneratorRegistry"; +import { getDatasourceConnectionMode } from "./utils"; +import type { DatasourceStorage } from "entities/Datasource"; +import { PluginPackageName } from "entities/Action"; +import PostgreSQL from "WidgetQueryGenerators/PostgreSQL"; +import GSheets from "WidgetQueryGenerators/GSheets"; + +describe("getDatasourceConnectionMode", () => { + beforeAll(() => { + WidgetQueryGeneratorRegistry.register( + PluginPackageName.POSTGRES, + PostgreSQL, + ); + WidgetQueryGeneratorRegistry.register( + PluginPackageName.GOOGLE_SHEETS, + GSheets, + ); + }); + + it("should return the connection mode from the query generator", () => { + expect( + getDatasourceConnectionMode(PluginPackageName.POSTGRES, { + connection: { + mode: "READ_ONLY", + }, + } as DatasourceStorage["datasourceConfiguration"]), + ).toEqual("READ_ONLY"); + + expect( + getDatasourceConnectionMode(PluginPackageName.GOOGLE_SHEETS, { + authentication: { + scopeString: "spreadsheets.readonly", + }, + } as DatasourceStorage["datasourceConfiguration"]), + ).toEqual("READ_ONLY"); + + expect( + getDatasourceConnectionMode(PluginPackageName.GOOGLE_SHEETS, { + authentication: { + scopeString: "spreadsheets", + }, + } as DatasourceStorage["datasourceConfiguration"]), + ).toEqual("READ_WRITE"); + }); + + it("should return null if the query generator is not found", () => { + const result = getDatasourceConnectionMode( + "non-existent-plugin-package-name", + { + connection: { + mode: "READ_ONLY", + }, + } as DatasourceStorage["datasourceConfiguration"], + ); + + expect(result).toBe(undefined); + }); +}); diff --git a/app/client/src/components/editorComponents/WidgetQueryGeneratorForm/utils.ts b/app/client/src/components/editorComponents/WidgetQueryGeneratorForm/utils.ts index ff5a265ec1..74eb994dd1 100644 --- a/app/client/src/components/editorComponents/WidgetQueryGeneratorForm/utils.ts +++ b/app/client/src/components/editorComponents/WidgetQueryGeneratorForm/utils.ts @@ -1,4 +1,6 @@ import { isNumber } from "lodash"; +import WidgetQueryGeneratorRegistry from "utils/WidgetQueryGeneratorRegistry"; +import type { DatasourceStorage } from "entities/Datasource"; export const getSheetUrl = (sheetId: string): string => `https://docs.google.com/spreadsheets/d/${sheetId}/edit#gid=0`; @@ -9,3 +11,12 @@ export const isValidGsheetConfig = (config: Record) => isNumber(Number(config.tableHeaderIndex)) && !isNaN(Number(config.tableHeaderIndex)) && config.tableHeaderIndex > 0; + +export const getDatasourceConnectionMode = ( + pluginPackageName: string, + datasourceConfiguration?: DatasourceStorage["datasourceConfiguration"], +) => { + const queryGenerator = WidgetQueryGeneratorRegistry.get(pluginPackageName); + + return queryGenerator?.getConnectionMode(datasourceConfiguration); +}; diff --git a/app/client/src/entities/Datasource/index.ts b/app/client/src/entities/Datasource/index.ts index b9ca51279e..a54ecb2950 100644 --- a/app/client/src/entities/Datasource/index.ts +++ b/app/client/src/entities/Datasource/index.ts @@ -54,6 +54,7 @@ export interface DatasourceAuthentication { authenticationType?: string; secretExists?: Record; isAuthorized?: boolean; + scopeString?: string; } export interface DatasourceColumns {