Skip to content

Commit a65c321

Browse files
Add change for File Identifier, macro for Oauth 2 and access token fields and other bugs.
Add change for File Identifier, macro for Oauth 2 and access token fields.
1 parent c58f79f commit a65c321

18 files changed

Lines changed: 576 additions & 78 deletions

docs/GoogleDrive-batchsink.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,10 @@ Make sure that:
4343
OAuth2 client credentials can be generated on Google Cloud
4444
[Credentials Page](https://console.cloud.google.com/apis/credentials)
4545

46+
**OAuth Method:** The method used to get OAuth access tokens. The oauth access token can be directly provided,
47+
or a client id, client secret, and refresh token can be provided.
48+
49+
**Access Token:** Short lived access token for connect.
4650
**Client ID:** OAuth2 client id used to identify the application.
4751

4852
**Client Secret:** OAuth2 client secret used to access the authorization server.

docs/GoogleDrive-batchsource.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,16 @@ https://drive.google.com/drive/folders/1dyUEebJaFnWa3Z4n0BFMVAXQ7mfUH11g?resourc
1717
```
1818
Then the Directory Identifier would be `1dyUEebJaFnWa3Z4n0BFMVAXQ7mfUH11g`.
1919

20+
**File Identifier:** Identifier of the file.
21+
22+
This comes after `file/d/ or document/d/ or spreadsheets/d/` in the URL. For example, if the URL is
23+
```
24+
https://docs.google.com/file/d/17W3vOhBwe0i24OdVNsbz8rAMClzUitKeAbumTqWFrkows
25+
```
26+
Then the File Identifier would be `17W3vOhBwe0i24OdVNsbz8rAMClzUitKeAbumTqWFrkows`.
27+
Either Directory Identifier or File Identifier should have a value. Filters will not work
28+
while providing File Identifier.
29+
2030
**File Metadata Properties:** Properties that represent metadata of files.
2131
They will be a part of output structured record. Descriptions for properties can be view at
2232
[Drive API file reference](https://developers.google.com/drive/api/v3/reference/files).
@@ -58,6 +68,11 @@ Make sure that:
5868
OAuth2 client credentials can be generated on Google Cloud
5969
[Credentials Page](https://console.cloud.google.com/apis/credentials)
6070

71+
**OAuth Method:** The method used to get OAuth access tokens. The oauth access token can be directly provided,
72+
or a client id, client secret, and refresh token can be provided.
73+
74+
**Access Token:** Short lived access token for connect.
75+
6176
**Client ID:** OAuth2 client id used to identify the application.
6277

6378
**Client Secret:** OAuth2 client secret used to access the authorization server.

docs/GoogleSheets-batchsink.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,11 @@ Make sure that:
4646
OAuth2 client credentials can be generated on Google Cloud
4747
[Credentials Page](https://console.cloud.google.com/apis/credentials)
4848

49+
**OAuth Method:** The method used to get OAuth access tokens. The oauth access token can be directly provided,
50+
or a client id, client secret, and refresh token can be provided.
51+
52+
**Access Token:** Short lived access token for connect.
53+
4954
**Client ID:** OAuth2 client id used to identify the application.
5055

5156
**Client Secret:** OAuth2 client secret used to access the authorization server.

docs/GoogleSheets-batchsource.md

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,16 @@ https://drive.google.com/drive/folders/1dyUEebJaFnWa3Z4n0BFMVAXQ7mfUH11g?resourc
1717
```
1818
Then the Directory Identifier would be `1dyUEebJaFnWa3Z4n0BFMVAXQ7mfUH11g`.
1919

20+
**File Identifier:** Identifier of the spreadsheet file.
21+
22+
This comes after `spreadsheets/d/` in the URL. For example, if the URL is
23+
```
24+
https://docs.google.com/spreadsheets/d/17W3vOhBwe0i24OdVNsbz8rAMClzUitKeAbumTqWFrkows
25+
```
26+
Then the File Identifier would be `17W3vOhBwe0i24OdVNsbz8rAMClzUitKeAbumTqWFrkows`.
27+
Either Directory Identifier or File Identifier should have a value. Filters will not work
28+
while providing File Identifier.
29+
2030
### Filtering
2131

2232
**Filter:** Filter that can be applied to the files in the selected directory.
@@ -55,6 +65,11 @@ Make sure that:
5565
OAuth2 client credentials can be generated on Google Cloud
5666
[Credentials Page](https://console.cloud.google.com/apis/credentials)
5767

68+
**OAuth Method:** The method used to get OAuth access tokens. The oauth access token can be directly provided,
69+
or a client id, client secret, and refresh token can be provided.
70+
71+
**Access Token:** Short lived access token for connect.
72+
5873
**Client ID:** OAuth2 client id used to identify the application.
5974

6075
**Client Secret:** OAuth2 client secret used to access the authorization server.
@@ -124,10 +139,10 @@ _Treat first row as column names_ - the plugin uses first row for schema definin
124139
**Column Names Row Number:** Number of the row to be treated as a header.
125140
Only shown when the 'Column Names Selection' field is set to 'Custom row as column names' header.
126141

127-
**Number of Columns to Read:** Last column plugin will read as data. It will be ignored if the Column
128-
Names Row contains less number of columns.
142+
**Number of Columns to Read:** Last column plugin will read as data. It will be ignored if the Column
143+
Names Row contains less number of columns. Set it to 0 to read all the columns in the sheet.
129144

130-
**Number of Rows to Read:** Last row plugin will read as data.
145+
**Number of Rows to Read:** Last row plugin will read as data. Set it to 0 to read all the rows in the sheet.
131146

132147
**Read Buffer Size:** Number of rows the source reads with a single API request. Default value is 100.
133148

src/main/java/io/cdap/plugin/google/common/GoogleAuthBaseConfig.java

Lines changed: 102 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -47,8 +47,14 @@ public abstract class GoogleAuthBaseConfig extends PluginConfig {
4747
public static final String CLIENT_SECRET_LABEL = "Client secret";
4848
public static final String REFRESH_TOKEN = "refreshToken";
4949
public static final String REFRESH_TOKEN_LABEL = "Refresh token";
50+
51+
public static final String ACCESS_TOKEN = "accessToken";
52+
public static final String ACCESS_TOKEN_LABEL = "Access token";
53+
54+
public static final String OAUTH_METHOD = "oauthMethod";
5055
public static final String ACCOUNT_FILE_PATH = "accountFilePath";
5156
public static final String DIRECTORY_IDENTIFIER = "directoryIdentifier";
57+
public static final String FILE_IDENTIFIER = "fileIdentifier";
5258
public static final String NAME_SERVICE_ACCOUNT_TYPE = "serviceAccountType";
5359
public static final String NAME_SERVICE_ACCOUNT_JSON = "serviceAccountJSON";
5460
public static final String SERVICE_ACCOUNT_FILE_PATH = "filePath";
@@ -76,21 +82,38 @@ public abstract class GoogleAuthBaseConfig extends PluginConfig {
7682
@Macro
7783
protected String serviceAccountType;
7884

85+
@Macro
7986
@Nullable
87+
@Name(OAUTH_METHOD)
88+
@Description("The method used to get OAuth access tokens. "
89+
+ "The oauth access token can be directly provided, "
90+
+ "or a client id, client secret, and refresh token can be provided.")
91+
private String oauthMethod;
92+
93+
@Nullable
94+
@Macro
8095
@Name(CLIENT_ID)
8196
@Description("OAuth2 client id.")
8297
private String clientId;
8398

8499
@Nullable
100+
@Macro
85101
@Name(CLIENT_SECRET)
86102
@Description("OAuth2 client secret.")
87103
private String clientSecret;
88104

89105
@Nullable
106+
@Macro
90107
@Name(REFRESH_TOKEN)
91108
@Description("OAuth2 refresh token.")
92109
private String refreshToken;
93110

111+
@Nullable
112+
@Macro
113+
@Name(ACCESS_TOKEN)
114+
@Description("Short lived access token for connect.")
115+
private String accessToken;
116+
94117
@Nullable
95118
@Macro
96119
@Name(ACCOUNT_FILE_PATH)
@@ -108,12 +131,22 @@ public abstract class GoogleAuthBaseConfig extends PluginConfig {
108131
@Macro
109132
protected String serviceAccountJson;
110133

134+
@Nullable
135+
@Macro
111136
@Name(DIRECTORY_IDENTIFIER)
112137
@Description("Identifier of the folder. This comes after “folders/” in the URL. For example, if the URL was " +
113138
"“https://drive.google.com/drive/folders/1dyUEebJaFnWa3Z4n0BFMVAXQ7mfUH11g?resourcekey=0-XVijrJSp3E3gkdJp20MpCQ”, "
114139
+ "then the Directory Identifier would be “1dyUEebJaFnWa3Z4n0BFMVAXQ7mfUH11g”.")
115140
private String directoryIdentifier;
116141

142+
@Nullable
143+
@Macro
144+
@Name(FILE_IDENTIFIER)
145+
@Description("Identifier of the file. This comes after “file/d/ or spreadsheets/d/ or document/d/” in the URL. " +
146+
"For example, if the URL was “https://drive.google.com/file/d/16npTpL3ozkAzB5kLQ-oQD3IlTZhnnh2w1/view”, "
147+
+ "then the File Identifier would be “16npTpL3ozkAzB5kLQ-oQD3IlTZhnnh2w1”.")
148+
private String fileIdentifier;
149+
117150
/**
118151
* Returns the ValidationResult.
119152
*
@@ -122,7 +155,7 @@ public abstract class GoogleAuthBaseConfig extends PluginConfig {
122155
*/
123156
public ValidationResult validate(FailureCollector collector) {
124157
IdUtils.validateReferenceName(referenceName, collector);
125-
158+
checkIfDirectoryOrFileIdentifierExists(collector);
126159
ValidationResult validationResult = new ValidationResult();
127160
if (validateAuthType(collector)) {
128161
AuthType authType = getAuthType();
@@ -143,13 +176,10 @@ public ValidationResult validate(FailureCollector collector) {
143176
try {
144177
GoogleDriveClient client = new GoogleDriveClient(this);
145178

146-
// validate auth
147-
validateCredentials(collector, client);
148-
149-
// validate directory
150-
validateDirectoryIdentifier(collector, client);
151-
152-
validationResult.setDirectoryAccessible(true);
179+
// check directory or file access
180+
if (isDirectoryOrFileAccessible(collector, client)) {
181+
validationResult.setDirectoryOrFileAccessible(true);
182+
}
153183
} catch (Exception e) {
154184
collector.addFailure(
155185
String.format("Exception during authentication/directory properties check: %s.", e.getMessage()),
@@ -177,9 +207,13 @@ private boolean validateAuthType(FailureCollector collector) {
177207
}
178208

179209
private boolean validateOAuth2Properties(FailureCollector collector) {
180-
return checkPropertyIsSet(collector, clientId, CLIENT_ID, CLIENT_ID_LABEL)
181-
& checkPropertyIsSet(collector, clientSecret, CLIENT_SECRET, CLIENT_SECRET_LABEL)
182-
& checkPropertyIsSet(collector, refreshToken, REFRESH_TOKEN, REFRESH_TOKEN_LABEL);
210+
if (OAuthMethod.REFRESH_TOKEN.equals(getOAuthMethod())) {
211+
return checkPropertyIsSet(collector, clientId, CLIENT_ID, CLIENT_ID_LABEL)
212+
& checkPropertyIsSet(collector, clientSecret, CLIENT_SECRET, CLIENT_SECRET_LABEL)
213+
& checkPropertyIsSet(collector, refreshToken, REFRESH_TOKEN, REFRESH_TOKEN_LABEL);
214+
} else {
215+
return checkPropertyIsSet(collector, accessToken, ACCESS_TOKEN, ACCESS_TOKEN_LABEL);
216+
}
183217
}
184218

185219
private boolean validateServiceAccount(FailureCollector collector) {
@@ -206,27 +240,41 @@ private boolean validateServiceAccount(FailureCollector collector) {
206240
return collector.getValidationFailures().size() == 0;
207241
}
208242

209-
private void validateCredentials(FailureCollector collector, GoogleDriveClient driveClient) throws IOException {
210-
try {
211-
driveClient.checkRootFolder();
212-
} catch (GoogleJsonResponseException e) {
213-
collector.addFailure(e.getDetails().getMessage(), "Provide valid credentials.")
214-
.withConfigProperty(NAME_SERVICE_ACCOUNT_TYPE)
215-
.withStacktrace(e.getStackTrace());
216-
}
217-
}
218-
219-
private void validateDirectoryIdentifier(FailureCollector collector, GoogleDriveClient driveClient)
243+
private boolean isDirectoryOrFileAccessible(FailureCollector collector, GoogleDriveClient driveClient)
220244
throws IOException {
221-
if (!containsMacro(DIRECTORY_IDENTIFIER)) {
245+
246+
if (directoryIdentifier != null && !containsMacro(DIRECTORY_IDENTIFIER)) {
222247
try {
223248
driveClient.isFolderAccessible(directoryIdentifier);
249+
return true;
224250
} catch (GoogleJsonResponseException e) {
225251
collector.addFailure(e.getDetails().getMessage(), "Provide an existing folder identifier.")
226252
.withConfigProperty(DIRECTORY_IDENTIFIER)
227253
.withStacktrace(e.getStackTrace());
228254
}
229255
}
256+
257+
if (fileIdentifier != null && !containsMacro(FILE_IDENTIFIER)) {
258+
try {
259+
driveClient.isFileAccessible(fileIdentifier);
260+
return true;
261+
} catch (GoogleJsonResponseException e) {
262+
collector.addFailure(e.getDetails().getMessage(), "Provide an existing file identifier.")
263+
.withConfigProperty(FILE_IDENTIFIER)
264+
.withStacktrace(e.getStackTrace());
265+
}
266+
}
267+
return false;
268+
}
269+
270+
protected void checkIfDirectoryOrFileIdentifierExists(FailureCollector collector) {
271+
if (directoryIdentifier == null && !containsMacro(DIRECTORY_IDENTIFIER) &&
272+
fileIdentifier == null && !containsMacro(FILE_IDENTIFIER)) {
273+
collector.addFailure("Both Directory Identifier and File Identifier can not be null.",
274+
"Provide either Directory Identifier or File Identifier.")
275+
.withConfigProperty(DIRECTORY_IDENTIFIER)
276+
.withConfigProperty(FILE_IDENTIFIER);
277+
}
230278
}
231279

232280
protected boolean checkPropertyIsSet(FailureCollector collector, String propertyValue, String propertyName,
@@ -250,6 +298,10 @@ public String getDirectoryIdentifier() {
250298
return directoryIdentifier;
251299
}
252300

301+
public String getFileIdentifier() {
302+
return fileIdentifier;
303+
}
304+
253305
public AuthType getAuthType() {
254306
return AuthType.fromValue(authType);
255307
}
@@ -277,6 +329,13 @@ public void setAccountFilePath(String accountFilePath) {
277329
public void setDirectoryIdentifier(String directoryIdentifier) {
278330
this.directoryIdentifier = directoryIdentifier;
279331
}
332+
public void setFileIdentifier(String fileIdentifier) {
333+
this.fileIdentifier = fileIdentifier;
334+
}
335+
336+
public void setOauthMethod(String oauthMethod) {
337+
this.oauthMethod = oauthMethod;
338+
}
280339

281340
public void setClientId(String clientId) {
282341
this.clientId = clientId;
@@ -290,6 +349,10 @@ public void setRefreshToken(String refreshToken) {
290349
this.refreshToken = refreshToken;
291350
}
292351

352+
public void setAccessToken(String accessToken) {
353+
this.accessToken = accessToken;
354+
}
355+
293356
@Nullable
294357
public String getClientId() {
295358
return clientId;
@@ -305,6 +368,11 @@ public String getRefreshToken() {
305368
return refreshToken;
306369
}
307370

371+
@Nullable
372+
public String getAccessToken() {
373+
return accessToken;
374+
}
375+
308376
@Nullable
309377
public String getServiceAccountFilePath() {
310378
if (containsMacro(ACCOUNT_FILE_PATH) || Strings.isNullOrEmpty(accountFilePath)
@@ -344,4 +412,15 @@ public Boolean isServiceAccountFilePath() {
344412
String serviceAccountType = getServiceAccountType();
345413
return Strings.isNullOrEmpty(serviceAccountType) ? null : serviceAccountType.equals(SERVICE_ACCOUNT_FILE_PATH);
346414
}
415+
416+
public OAuthMethod getOAuthMethod() {
417+
if (oauthMethod == null) {
418+
return OAuthMethod.REFRESH_TOKEN;
419+
}
420+
try {
421+
return OAuthMethod.valueOf(oauthMethod.toUpperCase());
422+
} catch (IllegalArgumentException e) {
423+
throw new IllegalArgumentException("Invalid oauth method " + oauthMethod);
424+
}
425+
}
347426
}

src/main/java/io/cdap/plugin/google/common/GoogleDriveClient.java

Lines changed: 16 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,6 @@
4343
*/
4444
public class GoogleDriveClient<C extends GoogleAuthBaseConfig> {
4545
private static final JsonFactory JSON_FACTORY = JacksonFactory.getDefaultInstance();
46-
private static final String ROOT_FOLDER_ID = "root";
4746
protected final Drive service;
4847
protected final C config;
4948
protected NetHttpTransport httpTransport;
@@ -88,13 +87,18 @@ protected Drive getDriveClient() throws IOException {
8887
}
8988

9089
protected Credential getOAuth2Credential() {
91-
GoogleCredential credential = new GoogleCredential.Builder()
92-
.setTransport(httpTransport)
93-
.setJsonFactory(JSON_FACTORY)
94-
.setClientSecrets(config.getClientId(),
95-
config.getClientSecret())
96-
.build();
97-
credential.createScoped(getRequiredScopes()).setRefreshToken(config.getRefreshToken());
90+
GoogleCredential credential;
91+
GoogleCredential.Builder builder = new GoogleCredential.Builder()
92+
.setTransport(httpTransport)
93+
.setJsonFactory(JSON_FACTORY);
94+
if (OAuthMethod.ACCESS_TOKEN.equals(config.getOAuthMethod())) {
95+
credential = builder.build();
96+
credential.createScoped(getRequiredScopes()).setAccessToken(config.getAccessToken());
97+
} else {
98+
credential = builder.setClientSecrets(config.getClientId(),
99+
config.getClientSecret()).build();
100+
credential.createScoped(getRequiredScopes()).setRefreshToken(config.getRefreshToken());
101+
}
98102
return credential;
99103
}
100104

@@ -121,11 +125,11 @@ protected List<String> getRequiredScopes() {
121125
return Collections.singletonList(DriveScopes.DRIVE_READONLY);
122126
}
123127

124-
public void checkRootFolder() throws IOException {
125-
service.files().get(ROOT_FOLDER_ID).setSupportsAllDrives(true).execute();
126-
}
127-
128128
public void isFolderAccessible(String folderId) throws IOException {
129129
service.files().get(folderId).setSupportsAllDrives(true).execute();
130130
}
131+
132+
public void isFileAccessible(String fileId) throws IOException {
133+
service.files().get(fileId).setSupportsAllDrives(true).execute();
134+
}
131135
}

src/main/java/io/cdap/plugin/google/common/GoogleDriveFilteringClient.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,10 @@ public List<File> getFilesSummary(List<ExportedType> exportedTypes, int filesNum
7171
String nextToken = "";
7272
int retrievedFiles = 0;
7373
int actualFilesNumber = filesNumber;
74+
if (config.getFileIdentifier() != null) {
75+
files.add(service.files().get(config.getFileIdentifier()).setSupportsAllDrives(true).execute());
76+
return files;
77+
}
7478
Drive.Files.List request = service.files().list()
7579
.setSupportsAllDrives(true)
7680
.setIncludeItemsFromAllDrives(true)

0 commit comments

Comments
 (0)