@guayaba/workflow-piece-google-drive 0.7.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.babelrc +3 -0
- package/.eslintrc.json +18 -0
- package/README.md +5 -0
- package/assets/logo.png +0 -0
- package/package.json +28 -0
- package/src/i18n/ca.json +125 -0
- package/src/i18n/de.json +136 -0
- package/src/i18n/es.json +136 -0
- package/src/i18n/fr.json +136 -0
- package/src/i18n/hi.json +125 -0
- package/src/i18n/id.json +125 -0
- package/src/i18n/ja.json +136 -0
- package/src/i18n/nl.json +136 -0
- package/src/i18n/pt.json +136 -0
- package/src/i18n/ru.json +127 -0
- package/src/i18n/translation.json +137 -0
- package/src/i18n/vi.json +127 -0
- package/src/i18n/zh.json +136 -0
- package/src/index.ts +74 -0
- package/src/lib/action/add-permission.action.ts +78 -0
- package/src/lib/action/create-new-folder.ts +38 -0
- package/src/lib/action/create-new-text-file.ts +89 -0
- package/src/lib/action/delete-file.ts +31 -0
- package/src/lib/action/delete-permission.action.ts +80 -0
- package/src/lib/action/duplicate-file.action.ts +78 -0
- package/src/lib/action/get-file-by-id.ts +34 -0
- package/src/lib/action/list-files.action.ts +209 -0
- package/src/lib/action/move-file.ts +44 -0
- package/src/lib/action/read-file.ts +24 -0
- package/src/lib/action/save-file-as-pdf.action.ts +72 -0
- package/src/lib/action/search-folder-or-file.action.ts +108 -0
- package/src/lib/action/send-to-trash.ts +34 -0
- package/src/lib/action/set-public-access.ts +64 -0
- package/src/lib/action/upload-file.ts +72 -0
- package/src/lib/auth.ts +80 -0
- package/src/lib/common/get-file-content.ts +109 -0
- package/src/lib/common/index.ts +179 -0
- package/src/lib/triggers/new-file.ts +115 -0
- package/src/lib/triggers/new-folder.ts +74 -0
- package/tsconfig.json +16 -0
- package/tsconfig.lib.json +15 -0
package/src/lib/auth.ts
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { AppConnectionValueForAuthProperty, PieceAuth, Property } from '@guayaba/workflows-framework';
|
|
2
|
+
import { AppConnectionType } from '@guayaba/workflows-shared';
|
|
3
|
+
import { google } from 'googleapis';
|
|
4
|
+
import { OAuth2Client } from 'googleapis-common';
|
|
5
|
+
|
|
6
|
+
export const googleDriveScopes = ['https://www.googleapis.com/auth/drive'];
|
|
7
|
+
|
|
8
|
+
export const googleDriveAuth = [PieceAuth.OAuth2({
|
|
9
|
+
description: '',
|
|
10
|
+
authUrl: 'https://accounts.google.com/o/oauth2/auth',
|
|
11
|
+
tokenUrl: 'https://oauth2.googleapis.com/token',
|
|
12
|
+
required: true,
|
|
13
|
+
scope: googleDriveScopes,
|
|
14
|
+
}), PieceAuth.CustomAuth({
|
|
15
|
+
displayName: 'Service Account (Advanced)',
|
|
16
|
+
description: 'Authenticate via service account from https://console.cloud.google.com/ > IAM & Admin > Service Accounts > Create Service Account > Keys > Add key. <br> <br> You can optionally use domain-wide delegation (https://support.google.com/a/answer/162106?hl=en#zippy=%2Cset-up-domain-wide-delegation-for-a-client) to access files without adding the service account to each one. <br> <br> **Note:** Without a user email, the service account only has access to files/folders you explicitly share with it.',
|
|
17
|
+
required: true,
|
|
18
|
+
props: {
|
|
19
|
+
serviceAccount: Property.LongText({
|
|
20
|
+
displayName: 'Service Account JSON Key',
|
|
21
|
+
required: true,
|
|
22
|
+
}),
|
|
23
|
+
userEmail: Property.ShortText({
|
|
24
|
+
displayName: 'User Email',
|
|
25
|
+
required: false,
|
|
26
|
+
description: 'Email address of the user to impersonate for domain-wide delegation.',
|
|
27
|
+
}),
|
|
28
|
+
},
|
|
29
|
+
validate: async ({ auth }) => {
|
|
30
|
+
try {
|
|
31
|
+
await getAccessToken({
|
|
32
|
+
type: AppConnectionType.CUSTOM_AUTH,
|
|
33
|
+
props: { ...auth },
|
|
34
|
+
});
|
|
35
|
+
} catch (e) {
|
|
36
|
+
return {
|
|
37
|
+
valid: false,
|
|
38
|
+
error: (e as Error).message,
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
return {
|
|
42
|
+
valid: true,
|
|
43
|
+
};
|
|
44
|
+
},
|
|
45
|
+
})];
|
|
46
|
+
|
|
47
|
+
export type GoogleDriveAuthValue = AppConnectionValueForAuthProperty<typeof googleDriveAuth>;
|
|
48
|
+
|
|
49
|
+
export async function createGoogleClient(auth: GoogleDriveAuthValue): Promise<OAuth2Client> {
|
|
50
|
+
if (auth.type === AppConnectionType.CUSTOM_AUTH) {
|
|
51
|
+
let serviceAccount;
|
|
52
|
+
try {
|
|
53
|
+
serviceAccount = JSON.parse(auth.props.serviceAccount);
|
|
54
|
+
} catch {
|
|
55
|
+
throw new Error('Invalid Service Account JSON Key. Please provide a valid JSON string.');
|
|
56
|
+
}
|
|
57
|
+
return new google.auth.JWT({
|
|
58
|
+
email: serviceAccount.client_email,
|
|
59
|
+
key: serviceAccount.private_key,
|
|
60
|
+
scopes: googleDriveScopes,
|
|
61
|
+
subject: auth.props.userEmail,
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
const authClient = new OAuth2Client();
|
|
65
|
+
authClient.setCredentials(auth);
|
|
66
|
+
return authClient;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export const getAccessToken = async (auth: GoogleDriveAuthValue): Promise<string> => {
|
|
70
|
+
if (auth.type === AppConnectionType.CUSTOM_AUTH) {
|
|
71
|
+
const googleClient = await createGoogleClient(auth);
|
|
72
|
+
const response = await googleClient.getAccessToken();
|
|
73
|
+
if (response.token) {
|
|
74
|
+
return response.token;
|
|
75
|
+
} else {
|
|
76
|
+
throw new Error('Could not retrieve access token from service account json');
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
return auth.access_token;
|
|
80
|
+
};
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import {
|
|
2
|
+
FilesService,
|
|
3
|
+
} from '@guayaba/workflows-framework';
|
|
4
|
+
import { extension } from 'mime-types';
|
|
5
|
+
import { GoogleDriveAuthValue, getAccessToken } from '../auth';
|
|
6
|
+
|
|
7
|
+
async function getMimeType(
|
|
8
|
+
auth: GoogleDriveAuthValue,
|
|
9
|
+
fileId: string
|
|
10
|
+
): Promise<string> {
|
|
11
|
+
const accessToken = await getAccessToken(auth);
|
|
12
|
+
const mimeType = (
|
|
13
|
+
await fetch(
|
|
14
|
+
`https://www.googleapis.com/drive/v3/files/${fileId}?fields=mimeType&supportsAllDrives=true`,
|
|
15
|
+
{
|
|
16
|
+
headers: {
|
|
17
|
+
Authorization: `Bearer ${accessToken}`,
|
|
18
|
+
},
|
|
19
|
+
}
|
|
20
|
+
).then((res) => res.json())
|
|
21
|
+
)['mimeType'] as string;
|
|
22
|
+
return mimeType;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const googledlCall = async (
|
|
26
|
+
url: string,
|
|
27
|
+
auth: GoogleDriveAuthValue,
|
|
28
|
+
fileId: string,
|
|
29
|
+
files: FilesService,
|
|
30
|
+
fileName: string | undefined
|
|
31
|
+
) => {
|
|
32
|
+
const mimeType = await getMimeType(auth, fileId);
|
|
33
|
+
const accessToken = await getAccessToken(auth);
|
|
34
|
+
|
|
35
|
+
const download = await fetch(url, {
|
|
36
|
+
headers: {
|
|
37
|
+
Authorization: `Bearer ${accessToken}`,
|
|
38
|
+
},
|
|
39
|
+
})
|
|
40
|
+
.then((response) =>
|
|
41
|
+
response.ok ? response.blob() : Promise.reject(response)
|
|
42
|
+
)
|
|
43
|
+
.catch((error) =>
|
|
44
|
+
Promise.reject(
|
|
45
|
+
new Error(
|
|
46
|
+
`Error when download file:\n\tDownload file response: ${
|
|
47
|
+
(error as Error).message ?? error
|
|
48
|
+
}`
|
|
49
|
+
)
|
|
50
|
+
)
|
|
51
|
+
);
|
|
52
|
+
|
|
53
|
+
const extensionResult = extension(mimeType);
|
|
54
|
+
const fileExtension = extensionResult ? '.' + extensionResult : '';
|
|
55
|
+
const srcFileName = fileName ?? fileId + fileExtension;
|
|
56
|
+
|
|
57
|
+
return files.write({
|
|
58
|
+
fileName: srcFileName,
|
|
59
|
+
data: Buffer.from(await download.arrayBuffer()),
|
|
60
|
+
});
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
export async function downloadFileFromDrive(
|
|
64
|
+
auth: GoogleDriveAuthValue,
|
|
65
|
+
files: FilesService,
|
|
66
|
+
fileId: string,
|
|
67
|
+
fileName: string | undefined
|
|
68
|
+
): Promise<string> {
|
|
69
|
+
let mimeType = await getMimeType(auth, fileId);
|
|
70
|
+
|
|
71
|
+
// the google drive API doesn't allowed downloading google documents but we can export them to office formats
|
|
72
|
+
if (
|
|
73
|
+
[
|
|
74
|
+
'application/vnd.google-apps.document',
|
|
75
|
+
'application/vnd.google-apps.spreadsheet',
|
|
76
|
+
'application/vnd.google-apps.presentation',
|
|
77
|
+
].includes(mimeType)
|
|
78
|
+
) {
|
|
79
|
+
switch (mimeType) {
|
|
80
|
+
case 'application/vnd.google-apps.document':
|
|
81
|
+
mimeType =
|
|
82
|
+
'application/vnd.openxmlformats-officedocument.wordprocessingml.document';
|
|
83
|
+
break;
|
|
84
|
+
case 'application/vnd.google-apps.spreadsheet':
|
|
85
|
+
mimeType =
|
|
86
|
+
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet';
|
|
87
|
+
break;
|
|
88
|
+
case 'application/vnd.google-apps.presentation':
|
|
89
|
+
mimeType =
|
|
90
|
+
'application/vnd.openxmlformats-officedocument.presentationml.presentation';
|
|
91
|
+
break;
|
|
92
|
+
}
|
|
93
|
+
return await googledlCall(
|
|
94
|
+
`https://www.googleapis.com/drive/v3/files/${fileId}/export?mimeType=${mimeType}&supportsAllDrives=true`,
|
|
95
|
+
auth,
|
|
96
|
+
fileId,
|
|
97
|
+
files,
|
|
98
|
+
fileName
|
|
99
|
+
);
|
|
100
|
+
} else {
|
|
101
|
+
return await googledlCall(
|
|
102
|
+
`https://www.googleapis.com/drive/v3/files/${fileId}?alt=media&supportsAllDrives=true`,
|
|
103
|
+
auth,
|
|
104
|
+
fileId,
|
|
105
|
+
files,
|
|
106
|
+
fileName
|
|
107
|
+
);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
import {
|
|
2
|
+
httpClient,
|
|
3
|
+
HttpMethod,
|
|
4
|
+
AuthenticationType,
|
|
5
|
+
HttpRequest,
|
|
6
|
+
} from '@guayaba/workflows-common';
|
|
7
|
+
import { Property } from '@guayaba/workflows-framework';
|
|
8
|
+
import dayjs from 'dayjs';
|
|
9
|
+
import { google } from 'googleapis';
|
|
10
|
+
import { googleDriveAuth, GoogleDriveAuthValue, getAccessToken, createGoogleClient } from '../auth';
|
|
11
|
+
|
|
12
|
+
const FOLDER_DROPDOWN_PAGE_SIZE = 1000;
|
|
13
|
+
|
|
14
|
+
const escapeDriveQueryLiteral = (value: string): string =>
|
|
15
|
+
value.replace(/\\/g, '\\\\').replace(/'/g, "\\'");
|
|
16
|
+
|
|
17
|
+
export const common = {
|
|
18
|
+
properties: {
|
|
19
|
+
parentFolder: Property.Dropdown({
|
|
20
|
+
displayName: 'Parent Folder',
|
|
21
|
+
description:
|
|
22
|
+
"The Drive folder to target. Leave empty to use the root of My Drive. Type in the box to search your Drive by folder name. If the folder still isn't listed, switch this field to 'Dynamic value' (the toggle next to the field) and paste the folder ID — you can copy it from the folder's URL in Drive, after /folders/ (e.g. https://drive.google.com/drive/folders/<FOLDER_ID>).",
|
|
23
|
+
required: false,
|
|
24
|
+
auth: googleDriveAuth,
|
|
25
|
+
refreshers: ['include_team_drives'],
|
|
26
|
+
refreshOnSearch: true,
|
|
27
|
+
options: async ({ auth, include_team_drives }, ctx) => {
|
|
28
|
+
if (!auth) {
|
|
29
|
+
return {
|
|
30
|
+
disabled: true,
|
|
31
|
+
options: [],
|
|
32
|
+
placeholder: 'Please authenticate first',
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
const authValue = auth as GoogleDriveAuthValue;
|
|
36
|
+
const accessToken = await getAccessToken(authValue);
|
|
37
|
+
const searchValue = ctx?.searchValue?.trim() ?? '';
|
|
38
|
+
const qParts = [
|
|
39
|
+
"mimeType='application/vnd.google-apps.folder'",
|
|
40
|
+
'trashed = false',
|
|
41
|
+
];
|
|
42
|
+
if (searchValue.length > 0) {
|
|
43
|
+
qParts.push(`name contains '${escapeDriveQueryLiteral(searchValue)}'`);
|
|
44
|
+
}
|
|
45
|
+
const request: HttpRequest = {
|
|
46
|
+
method: HttpMethod.GET,
|
|
47
|
+
url: `https://www.googleapis.com/drive/v3/files`,
|
|
48
|
+
queryParams: {
|
|
49
|
+
q: qParts.join(' and '),
|
|
50
|
+
includeItemsFromAllDrives: include_team_drives ? 'true' : 'false',
|
|
51
|
+
supportsAllDrives: 'true',
|
|
52
|
+
pageSize: String(FOLDER_DROPDOWN_PAGE_SIZE),
|
|
53
|
+
fields: 'nextPageToken, files(id, name)',
|
|
54
|
+
},
|
|
55
|
+
authentication: {
|
|
56
|
+
type: AuthenticationType.BEARER_TOKEN,
|
|
57
|
+
token: accessToken,
|
|
58
|
+
},
|
|
59
|
+
};
|
|
60
|
+
let folders: { id: string; name: string }[] = [];
|
|
61
|
+
let truncated = false;
|
|
62
|
+
try {
|
|
63
|
+
const response = await httpClient.sendRequest<{
|
|
64
|
+
files: { id: string; name: string }[];
|
|
65
|
+
nextPageToken?: string;
|
|
66
|
+
}>(request);
|
|
67
|
+
folders = response.body.files ?? [];
|
|
68
|
+
truncated = Boolean(response.body.nextPageToken);
|
|
69
|
+
} catch (e) {
|
|
70
|
+
throw new Error(`Failed to get folders\nError:${e}`);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
return {
|
|
74
|
+
disabled: false,
|
|
75
|
+
placeholder: truncated
|
|
76
|
+
? `Showing first ${folders.length} matches — type to narrow the list, or switch to Dynamic value to paste an ID.`
|
|
77
|
+
: undefined,
|
|
78
|
+
options: folders.map((folder: { id: string; name: string }) => {
|
|
79
|
+
return {
|
|
80
|
+
label: folder.name,
|
|
81
|
+
value: folder.id,
|
|
82
|
+
};
|
|
83
|
+
}),
|
|
84
|
+
};
|
|
85
|
+
},
|
|
86
|
+
}),
|
|
87
|
+
include_team_drives: Property.Checkbox({
|
|
88
|
+
displayName: 'Include Team Drives',
|
|
89
|
+
description:
|
|
90
|
+
'Determines if folders from Team Drives should be included in the results.',
|
|
91
|
+
defaultValue: false,
|
|
92
|
+
required: false,
|
|
93
|
+
}),
|
|
94
|
+
},
|
|
95
|
+
|
|
96
|
+
async getFiles(
|
|
97
|
+
auth: GoogleDriveAuthValue,
|
|
98
|
+
search?: {
|
|
99
|
+
parent?: string;
|
|
100
|
+
createdTime?: string | number | Date;
|
|
101
|
+
createdTimeOp?: string;
|
|
102
|
+
includeTeamDrive?: boolean;
|
|
103
|
+
},
|
|
104
|
+
order?: string
|
|
105
|
+
) {
|
|
106
|
+
const authClient = await createGoogleClient(auth);
|
|
107
|
+
|
|
108
|
+
const drive = google.drive({ version: 'v3', auth: authClient });
|
|
109
|
+
|
|
110
|
+
const q: string[] = [];
|
|
111
|
+
if (search?.parent) q.push(`'${search.parent}' in parents`);
|
|
112
|
+
if (search?.createdTime)
|
|
113
|
+
q.push(
|
|
114
|
+
`createdTime ${search.createdTimeOp ?? '>'} '${dayjs(
|
|
115
|
+
search.createdTime
|
|
116
|
+
).format()}'`
|
|
117
|
+
);
|
|
118
|
+
q.push(`trashed = false`);
|
|
119
|
+
const allFiles: any[] = [];
|
|
120
|
+
let pageToken: string | undefined = undefined;
|
|
121
|
+
do {
|
|
122
|
+
const listParams: Record<string, any> = {
|
|
123
|
+
q: q.concat("mimeType!='application/vnd.google-apps.folder'").join(' and '),
|
|
124
|
+
fields: 'nextPageToken, files(id, name, mimeType, webViewLink, kind, createdTime)',
|
|
125
|
+
orderBy: order ?? 'createdTime desc',
|
|
126
|
+
supportsAllDrives: true,
|
|
127
|
+
includeItemsFromAllDrives: search?.includeTeamDrive,
|
|
128
|
+
};
|
|
129
|
+
if (pageToken) listParams.pageToken = pageToken;
|
|
130
|
+
const response = await drive.files.list(listParams);
|
|
131
|
+
allFiles.push(...(response.data.files ?? []));
|
|
132
|
+
pageToken = response.data.nextPageToken ?? undefined;
|
|
133
|
+
} while (pageToken);
|
|
134
|
+
|
|
135
|
+
return allFiles;
|
|
136
|
+
},
|
|
137
|
+
|
|
138
|
+
async getFolders(
|
|
139
|
+
auth: GoogleDriveAuthValue,
|
|
140
|
+
search?: {
|
|
141
|
+
parent?: string;
|
|
142
|
+
createdTime?: string | number | Date;
|
|
143
|
+
createdTimeOp?: string;
|
|
144
|
+
includeTeamDrive?: boolean;
|
|
145
|
+
},
|
|
146
|
+
order?: string
|
|
147
|
+
) {
|
|
148
|
+
const authClient = await createGoogleClient(auth);
|
|
149
|
+
|
|
150
|
+
const drive = google.drive({ version: 'v3', auth: authClient });
|
|
151
|
+
|
|
152
|
+
const q: string[] = [`mimeType='application/vnd.google-apps.folder'`];
|
|
153
|
+
if (search?.parent) q.push(`'${search.parent}' in parents`);
|
|
154
|
+
if (search?.createdTime)
|
|
155
|
+
q.push(
|
|
156
|
+
`createdTime ${search.createdTimeOp ?? '>'} '${dayjs(
|
|
157
|
+
search.createdTime
|
|
158
|
+
).format()}'`
|
|
159
|
+
);
|
|
160
|
+
q.push(`trashed = false`);
|
|
161
|
+
const allFolders: any[] = [];
|
|
162
|
+
let pageToken: string | undefined = undefined;
|
|
163
|
+
do {
|
|
164
|
+
const listParams: Record<string, any> = {
|
|
165
|
+
q: q.join(' and '),
|
|
166
|
+
fields: 'nextPageToken, files(id, name, createdTime)',
|
|
167
|
+
orderBy: order ?? 'createdTime desc',
|
|
168
|
+
supportsAllDrives: true,
|
|
169
|
+
includeItemsFromAllDrives: search?.includeTeamDrive,
|
|
170
|
+
};
|
|
171
|
+
if (pageToken) listParams.pageToken = pageToken;
|
|
172
|
+
const response = await drive.files.list(listParams);
|
|
173
|
+
allFolders.push(...(response.data.files ?? []));
|
|
174
|
+
pageToken = response.data.nextPageToken ?? undefined;
|
|
175
|
+
} while (pageToken);
|
|
176
|
+
|
|
177
|
+
return allFolders;
|
|
178
|
+
},
|
|
179
|
+
};
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import {
|
|
2
|
+
AppConnectionValueForAuthProperty,
|
|
3
|
+
PiecePropValueSchema,
|
|
4
|
+
Property,
|
|
5
|
+
createTrigger,
|
|
6
|
+
} from '@guayaba/workflows-framework';
|
|
7
|
+
import { TriggerStrategy } from '@guayaba/workflows-framework';
|
|
8
|
+
import {
|
|
9
|
+
DedupeStrategy,
|
|
10
|
+
Polling,
|
|
11
|
+
pollingHelper,
|
|
12
|
+
} from '@guayaba/workflows-common';
|
|
13
|
+
|
|
14
|
+
import dayjs from 'dayjs';
|
|
15
|
+
import { googleDriveAuth } from '../auth';
|
|
16
|
+
import { common } from '../common';
|
|
17
|
+
import { downloadFileFromDrive } from '../common/get-file-content';
|
|
18
|
+
|
|
19
|
+
const polling: Polling<
|
|
20
|
+
AppConnectionValueForAuthProperty<typeof googleDriveAuth>,
|
|
21
|
+
{ parentFolder?: any; include_team_drives?: boolean }
|
|
22
|
+
> = {
|
|
23
|
+
strategy: DedupeStrategy.TIMEBASED,
|
|
24
|
+
items: async ({ auth, propsValue, lastFetchEpochMS }) => {
|
|
25
|
+
const currentValues =
|
|
26
|
+
(await common.getFiles(auth, {
|
|
27
|
+
parent: propsValue.parentFolder,
|
|
28
|
+
createdTime: lastFetchEpochMS,
|
|
29
|
+
includeTeamDrive: propsValue.include_team_drives,
|
|
30
|
+
})) ?? [];
|
|
31
|
+
const items = currentValues.map((item: any) => ({
|
|
32
|
+
epochMilliSeconds: dayjs(item.createdTime).valueOf(),
|
|
33
|
+
data: item,
|
|
34
|
+
}));
|
|
35
|
+
return items;
|
|
36
|
+
},
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
export const newFile = createTrigger({
|
|
40
|
+
auth: googleDriveAuth,
|
|
41
|
+
name: 'new_file',
|
|
42
|
+
displayName: 'New File',
|
|
43
|
+
description: 'Trigger when a new file is uploaded.',
|
|
44
|
+
props: {
|
|
45
|
+
parentFolder: common.properties.parentFolder,
|
|
46
|
+
include_team_drives: common.properties.include_team_drives,
|
|
47
|
+
include_file_content: Property.Checkbox({
|
|
48
|
+
displayName: 'Include File Content',
|
|
49
|
+
description: 'Include the file content in the output. This will increase the time taken to fetch the files and might cause issues with large files.',
|
|
50
|
+
required: false,
|
|
51
|
+
defaultValue: false
|
|
52
|
+
}),
|
|
53
|
+
},
|
|
54
|
+
type: TriggerStrategy.POLLING,
|
|
55
|
+
onEnable: async (context) => {
|
|
56
|
+
await pollingHelper.onEnable(polling, {
|
|
57
|
+
auth: context.auth,
|
|
58
|
+
store: context.store,
|
|
59
|
+
propsValue: context.propsValue,
|
|
60
|
+
});
|
|
61
|
+
},
|
|
62
|
+
onDisable: async (context) => {
|
|
63
|
+
await pollingHelper.onDisable(polling, {
|
|
64
|
+
auth: context.auth,
|
|
65
|
+
store: context.store,
|
|
66
|
+
propsValue: context.propsValue,
|
|
67
|
+
});
|
|
68
|
+
},
|
|
69
|
+
run: async (context) => {
|
|
70
|
+
const newFiles = await pollingHelper.poll(polling, {
|
|
71
|
+
auth: context.auth,
|
|
72
|
+
store: context.store,
|
|
73
|
+
propsValue: context.propsValue,
|
|
74
|
+
files: context.files,
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
return await handleFileContent(newFiles, context)
|
|
78
|
+
},
|
|
79
|
+
test: async (context) => {
|
|
80
|
+
const newFiles = await pollingHelper.test(polling, {
|
|
81
|
+
auth: context.auth,
|
|
82
|
+
store: context.store,
|
|
83
|
+
propsValue: context.propsValue,
|
|
84
|
+
files: context.files,
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
return await handleFileContent(newFiles, context)
|
|
88
|
+
},
|
|
89
|
+
|
|
90
|
+
sampleData: {
|
|
91
|
+
kind: 'drive#file',
|
|
92
|
+
mimeType: 'image/png',
|
|
93
|
+
id: '1dpv4-sKJfKRwI9qx1vWqQhEGEn3EpbI5',
|
|
94
|
+
name: 'google-drive.png',
|
|
95
|
+
link: 'https://cdn.activepieces.com/pieces/google-drive.png'
|
|
96
|
+
},
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
async function handleFileContent(newFiles: unknown[], context: any) {
|
|
100
|
+
const newFilesObj = JSON.parse(JSON.stringify(newFiles))
|
|
101
|
+
|
|
102
|
+
if (context.propsValue.include_file_content) {
|
|
103
|
+
const fileContentPromises: Promise<string>[] = []
|
|
104
|
+
for (const file of newFilesObj) {
|
|
105
|
+
fileContentPromises.push(downloadFileFromDrive(context.auth, context.files, file["id"], file["name"]));
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
const filesContent = await Promise.all(fileContentPromises)
|
|
109
|
+
|
|
110
|
+
for (let i = 0; i < newFilesObj.length; i++) {
|
|
111
|
+
newFilesObj[i].content = filesContent[i]
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
return newFilesObj
|
|
115
|
+
}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import {
|
|
2
|
+
AppConnectionValueForAuthProperty,
|
|
3
|
+
PiecePropValueSchema,
|
|
4
|
+
createTrigger,
|
|
5
|
+
} from '@guayaba/workflows-framework';
|
|
6
|
+
import { TriggerStrategy } from '@guayaba/workflows-framework';
|
|
7
|
+
import {
|
|
8
|
+
DedupeStrategy,
|
|
9
|
+
Polling,
|
|
10
|
+
pollingHelper,
|
|
11
|
+
} from '@guayaba/workflows-common';
|
|
12
|
+
|
|
13
|
+
import dayjs from 'dayjs';
|
|
14
|
+
import { googleDriveAuth } from '../auth';
|
|
15
|
+
import { common } from '../common';
|
|
16
|
+
|
|
17
|
+
const polling: Polling<
|
|
18
|
+
AppConnectionValueForAuthProperty<typeof googleDriveAuth>,
|
|
19
|
+
{ parentFolder?: any,include_team_drives?:boolean }
|
|
20
|
+
> = {
|
|
21
|
+
strategy: DedupeStrategy.TIMEBASED,
|
|
22
|
+
items: async ({ auth, propsValue, lastFetchEpochMS }) => {
|
|
23
|
+
const currentValues =
|
|
24
|
+
(await common.getFolders(auth, {
|
|
25
|
+
parent: propsValue.parentFolder,
|
|
26
|
+
createdTime: lastFetchEpochMS,
|
|
27
|
+
includeTeamDrive:propsValue.include_team_drives
|
|
28
|
+
})) ?? [];
|
|
29
|
+
const items = currentValues.map((item: any) => ({
|
|
30
|
+
epochMilliSeconds: dayjs(item.createdTime).valueOf(),
|
|
31
|
+
data: item,
|
|
32
|
+
}));
|
|
33
|
+
return items;
|
|
34
|
+
},
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
export const newFolder = createTrigger({
|
|
38
|
+
auth: googleDriveAuth,
|
|
39
|
+
name: 'new_folder',
|
|
40
|
+
displayName: 'New Folder',
|
|
41
|
+
description: 'Trigger when a new folder is created or uploaded.',
|
|
42
|
+
props: {
|
|
43
|
+
parentFolder: common.properties.parentFolder,
|
|
44
|
+
include_team_drives: common.properties.include_team_drives,
|
|
45
|
+
},
|
|
46
|
+
type: TriggerStrategy.POLLING,
|
|
47
|
+
onEnable: async (context) => {
|
|
48
|
+
await pollingHelper.onEnable(polling, {
|
|
49
|
+
auth: context.auth,
|
|
50
|
+
store: context.store,
|
|
51
|
+
propsValue: context.propsValue,
|
|
52
|
+
});
|
|
53
|
+
},
|
|
54
|
+
onDisable: async (context) => {
|
|
55
|
+
await pollingHelper.onDisable(polling, {
|
|
56
|
+
auth: context.auth,
|
|
57
|
+
store: context.store,
|
|
58
|
+
propsValue: context.propsValue,
|
|
59
|
+
});
|
|
60
|
+
},
|
|
61
|
+
run: async (context) => {
|
|
62
|
+
return await pollingHelper.poll(polling, context);
|
|
63
|
+
},
|
|
64
|
+
test: async (context) => {
|
|
65
|
+
return await pollingHelper.test(polling, context);
|
|
66
|
+
},
|
|
67
|
+
|
|
68
|
+
sampleData: {
|
|
69
|
+
kind: 'drive#file',
|
|
70
|
+
mimeType: 'application/vnd.google-apps.folder',
|
|
71
|
+
id: '1aMEtTqIYn5651wdK7WLxaK_SDim4mvXW',
|
|
72
|
+
name: 'New Folder WOOOO',
|
|
73
|
+
},
|
|
74
|
+
});
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
{
|
|
2
|
+
"extends": "../../../../tsconfig.base.json",
|
|
3
|
+
"files": [],
|
|
4
|
+
"include": [],
|
|
5
|
+
"references": [
|
|
6
|
+
{
|
|
7
|
+
"path": "./tsconfig.lib.json"
|
|
8
|
+
}
|
|
9
|
+
],
|
|
10
|
+
"compilerOptions": {
|
|
11
|
+
"forceConsistentCasingInFileNames": true,
|
|
12
|
+
"strict": true,
|
|
13
|
+
"noImplicitReturns": true,
|
|
14
|
+
"noFallthroughCasesInSwitch": true
|
|
15
|
+
}
|
|
16
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
{
|
|
2
|
+
"extends": "./tsconfig.json",
|
|
3
|
+
"compilerOptions": {
|
|
4
|
+
"module": "commonjs",
|
|
5
|
+
"rootDir": ".",
|
|
6
|
+
"baseUrl": ".",
|
|
7
|
+
"paths": {},
|
|
8
|
+
"outDir": "./dist",
|
|
9
|
+
"declaration": true,
|
|
10
|
+
"declarationMap": true,
|
|
11
|
+
"types": ["node"]
|
|
12
|
+
},
|
|
13
|
+
"exclude": ["jest.config.ts", "src/**/*.spec.ts", "src/**/*.test.ts"],
|
|
14
|
+
"include": ["src/**/*.ts"]
|
|
15
|
+
}
|