Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,9 @@ public class ErrorMessages extends BasePluginErrorMessages {

public static final String MISSING_ROW_INDEX_ERROR_MSG = "Missing required field 'Row index'";

public static final String MISSING_SPREADSHEET_URL_SELECTED_SHEETS_ERROR_MSG =
"Missing required field 'Spreadsheet Url'. Please check if your datasource is authorized to use this spreadsheet.";

public static final String UNABLE_TO_CREATE_URI_ERROR_MSG = "Unable to create URI";

public static final String MISSING_VALID_RESPONSE_ERROR_MSG = "Missing a valid response object.";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@
import static com.appsmith.external.helpers.PluginUtils.getDataValueSafelyFromFormData;
import static com.appsmith.external.helpers.PluginUtils.setDataValueSafelyInFormData;
import static com.appsmith.external.helpers.PluginUtils.validConfigurationPresentInFormData;
import static com.external.utils.SheetsUtil.getUserAuthorizedSheetIds;
import static com.external.utils.SheetsUtil.validateAndGetUserAuthorizedSheetIds;
import static java.lang.Boolean.TRUE;

@Slf4j
Expand Down Expand Up @@ -175,7 +175,8 @@ public Mono<ActionExecutionResult> executeCommon(

// This will get list of authorised sheet ids from datasource config, and transform execution response to
// contain only authorised files
final Set<String> userAuthorizedSheetIds = getUserAuthorizedSheetIds(datasourceConfiguration);
final Set<String> userAuthorizedSheetIds =
validateAndGetUserAuthorizedSheetIds(datasourceConfiguration, methodConfig);

// Triggering the actual REST API call
return executionMethod
Expand Down Expand Up @@ -338,7 +339,8 @@ public Mono<TriggerResultDTO> trigger(

// This will get list of authorised sheet ids from datasource config, and transform trigger response to
// contain only authorised files
Set<String> userAuthorizedSheetIds = getUserAuthorizedSheetIds(datasourceConfiguration);
Set<String> userAuthorizedSheetIds =
validateAndGetUserAuthorizedSheetIds(datasourceConfiguration, methodConfig);

return triggerMethod
.getTriggerClient(client, methodConfig)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
package com.external.utils;

import com.appsmith.external.exceptions.pluginExceptions.AppsmithPluginError;
import com.appsmith.external.exceptions.pluginExceptions.AppsmithPluginException;
import com.appsmith.external.models.DatasourceConfiguration;
import com.appsmith.external.models.OAuth2;
import com.external.config.MethodConfig;
import com.external.constants.ErrorMessages;
import com.external.enums.GoogleSheetMethodEnum;
import com.fasterxml.jackson.databind.JsonNode;

Expand All @@ -17,8 +21,10 @@ public class SheetsUtil {
private static final String FILE_SPECIFIC_DRIVE_SCOPE = "https://www.googleapis.com/auth/drive.file";
private static final int USER_AUTHORIZED_SHEET_IDS_INDEX = 1;

public static Set<String> getUserAuthorizedSheetIds(DatasourceConfiguration datasourceConfiguration) {
public static Set<String> validateAndGetUserAuthorizedSheetIds(
DatasourceConfiguration datasourceConfiguration, MethodConfig methodConfig) {
OAuth2 oAuth2 = (OAuth2) datasourceConfiguration.getAuthentication();
Set<String> userAuthorisedSheetIds = null;
if (!isEmpty(datasourceConfiguration.getProperties())
&& datasourceConfiguration.getProperties().size() > 1
&& datasourceConfiguration.getProperties().get(USER_AUTHORIZED_SHEET_IDS_INDEX) != null
Expand All @@ -33,9 +39,23 @@ public static Set<String> getUserAuthorizedSheetIds(DatasourceConfiguration data
.getProperties()
.get(USER_AUTHORIZED_SHEET_IDS_INDEX)
.getValue();
return new HashSet<String>(temp);
userAuthorisedSheetIds = new HashSet<String>(temp);

// This is added specifically for selected gsheets, so that whenever authorisation changes from one sheet to
// another
// We throw an error, this is done because when we use drive.file scope which is for selected sheets through
// file picker
// The access token for this scope grants access to all selected sheets across datasources
// we want to constraint the access for datasource to the sheet which was selected during ds authorisation
if (methodConfig != null
&& methodConfig.getSpreadsheetId() != null
&& !userAuthorisedSheetIds.contains(methodConfig.getSpreadsheetId())) {
throw new AppsmithPluginException(
AppsmithPluginError.PLUGIN_EXECUTE_ARGUMENT_ERROR,
ErrorMessages.MISSING_SPREADSHEET_URL_SELECTED_SHEETS_ERROR_MSG);
}
}
return null;
return userAuthorisedSheetIds;
}

public static Map<String, String> getSpreadsheetData(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,35 +1,36 @@
package com.external.config;

import com.appsmith.external.exceptions.pluginExceptions.AppsmithPluginException;
import com.appsmith.external.models.DatasourceConfiguration;
import com.appsmith.external.models.OAuth2;
import com.appsmith.external.models.Property;
import com.external.constants.ErrorMessages;
import com.external.utils.SheetsUtil;
import com.fasterxml.jackson.core.JsonProcessingException;
import org.junit.jupiter.api.Test;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.*;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.*;

public class SheetsUtilTest {

@Test
public void testGetUserAuthorizedSheetIds_allsheets_returnsNull() throws JsonProcessingException {
public void testValidateAndGetUserAuthorizedSheetIds_allsheets_returnsNull() throws JsonProcessingException {
DatasourceConfiguration dsConfig = new DatasourceConfiguration();
List<Property> propList = new ArrayList<Property>();
Property prop = new Property();
prop.setKey("emailAddress");
prop.setValue("test_email");
propList.add(prop);
dsConfig.setProperties(propList);
Set<String> result = SheetsUtil.getUserAuthorizedSheetIds(dsConfig);
assertEquals(result, null);
Set<String> result = SheetsUtil.validateAndGetUserAuthorizedSheetIds(dsConfig, null);
assertEquals(null, result);
}

@Test
public void testGetUserAuthorizedSheetIds_specificSheets_returnsSetOfFileIds() throws JsonProcessingException {
public void testValidateAndGetUserAuthorizedSheetIds_specificSheets_returnsSetOfFileIds()
throws JsonProcessingException {
DatasourceConfiguration dsConfig = new DatasourceConfiguration();
List<Property> propList = new ArrayList<Property>();
OAuth2 oAuth2 = new OAuth2();
Expand All @@ -47,7 +48,92 @@ public void testGetUserAuthorizedSheetIds_specificSheets_returnsSetOfFileIds() t
propList.add(prop2);

dsConfig.setProperties(propList);
Set<String> result = SheetsUtil.getUserAuthorizedSheetIds(dsConfig);
assertEquals(result.size(), 1);
Set<String> result = SheetsUtil.validateAndGetUserAuthorizedSheetIds(dsConfig, null);
assertEquals(1, result.size());
}

@Test
public void testValidateAndGetUserAuthorizedSheetIds_invalidSpecificSheets_throwsException() {
DatasourceConfiguration dsConfig = new DatasourceConfiguration();
List<Property> propList = new ArrayList<>();
OAuth2 oAuth2 = new OAuth2();

oAuth2.setScopeString("https://www.googleapis.com/auth/drive.file");
dsConfig.setAuthentication(oAuth2);

Property prop1 = new Property("emailAddress", "test_email");
propList.add(prop1);

List<String> ids = new ArrayList<>();
ids.add("id1");

Property prop2 = new Property("userAuthorizedSheetIds", ids);
propList.add(prop2);

dsConfig.setProperties(propList);

// Create formData map with only the spreadsheetUrl
Map<String, Object> formData = new HashMap<>();
Map<String, Object> spreadsheetUrlData = new HashMap<>();
spreadsheetUrlData.put("data", "https://docs.google.com/spreadsheets/d/id2");
formData.put("sheetUrl", spreadsheetUrlData);

MethodConfig methodConfig = new MethodConfig(formData);

AppsmithPluginException exception = assertThrows(AppsmithPluginException.class, () -> {
SheetsUtil.validateAndGetUserAuthorizedSheetIds(dsConfig, methodConfig);
});

String expectedErrorMessage = ErrorMessages.MISSING_SPREADSHEET_URL_SELECTED_SHEETS_ERROR_MSG;
assertEquals(expectedErrorMessage, exception.getMessage());
}

@Test
public void testValidateAndGetUserAuthorizedSheetIds_validSpecificSheets_returnsAuthorisedSheetIds() {
DatasourceConfiguration dsConfig = new DatasourceConfiguration();
List<Property> propList = new ArrayList<>();
OAuth2 oAuth2 = new OAuth2();

oAuth2.setScopeString("https://www.googleapis.com/auth/drive.file");
dsConfig.setAuthentication(oAuth2);

Property prop1 = new Property("emailAddress", "test_email");
propList.add(prop1);

List<String> ids = new ArrayList<>();
ids.add("id1");

Property prop2 = new Property("userAuthorizedSheetIds", ids);
propList.add(prop2);

dsConfig.setProperties(propList);

// Create formData map with the spreadsheetUrl
Map<String, Object> formData = new HashMap<>();
Map<String, Object> spreadsheetUrlData = new HashMap<>();
spreadsheetUrlData.put("data", "https://docs.google.com/spreadsheets/d/id1");
formData.put("sheetUrl", spreadsheetUrlData);

MethodConfig methodConfig = new MethodConfig(formData);

Set<String> result = SheetsUtil.validateAndGetUserAuthorizedSheetIds(dsConfig, methodConfig);

assertEquals(1, result.size());
assertTrue(result.contains("id1"));
}

@Test
public void testValidateAndGetUserAuthorizedSheetIds_allSheets_returnsNull() {
DatasourceConfiguration dsConfig = new DatasourceConfiguration();
OAuth2 oAuth2 = new OAuth2();

oAuth2.setScopeString("https://www.googleapis.com/auth/drive,https://www.googleapis.com/auth/spreadsheets");
dsConfig.setAuthentication(oAuth2);

// Not adding any properties to dsConfig

Set<String> result = SheetsUtil.validateAndGetUserAuthorizedSheetIds(dsConfig, null);

assertNull(result);
}
}