-
Notifications
You must be signed in to change notification settings - Fork 15
Expand file tree
/
Copy pathDriveLabelsAutomation.js
More file actions
250 lines (221 loc) · 7.85 KB
/
Copy pathDriveLabelsAutomation.js
File metadata and controls
250 lines (221 loc) · 7.85 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
/**
* Tutorial: Complete Google Drive Labels Automation in Apps Script
*
* Copy-paste this entire code into a new Google Apps Script project (script.google.com).
* Prerequisites:
* 1. Enable Drive API v3 and Drive Labels API v2 (Editor > Services > + > Search/Add each).
* 2. Re-authorize permissions (Run > Review permissions).
* 3. Replace fileId in fullLabelAutomation() with your actual file ID.
* 4. Ensure "Invoice" label exists and is published in Google Workspace Admin > Drive > Labels.
*
*
* This script:
* - Fetches available labels.
* - Mocks suggestion as "Invoice" (replace with Gemini for dynamic).
* - Fetches fields for the label.
* - Applies label + populates fields with mock values (from your invoice example).
* - Logs everything; check file in Drive > Details > Labels for results.
*/
// 1. Fetch Currently Available Labels and Their IDs
function fetchAvailableLabels() {
try {
const response = DriveLabels.Labels.list({ view: "LABEL_VIEW_FULL" });
const labels = response.labels || [];
if (labels.length === 0) {
Logger.log("No labels found. Check Workspace admin for published labels.");
return {};
}
const labelMap = {};
labels.forEach(label => {
if (label.properties?.title) {
labelMap[label.properties.title] = label.id;
}
});
Logger.log(`Fetched ${labels.length} labels: ${JSON.stringify(labelMap)}`);
return labelMap;
} catch (error) {
Logger.log(`Error fetching labels: ${error.message}`);
return {};
}
}
// 2. Fetch Label Fields and Their IDs (list-based to avoid 404)
function fetchLabelFields(labelId) {
try {
if (!labelId) {
throw new Error("labelId is required. Run fetchAvailableLabels() first and copy an ID.");
}
const response = DriveLabels.Labels.list({ view: "LABEL_VIEW_FULL" });
const labels = response.labels || [];
if (labels.length === 0) {
Logger.log("No labels found. Check Workspace admin for published labels.");
return {};
}
const targetLabel = labels.find(label => label.id === labelId);
if (!targetLabel) {
Logger.log(`Label ID "${labelId}" not found in available labels. Run fetchAvailableLabels() to verify.`);
return {};
}
const fields = targetLabel.fields || [];
if (fields.length === 0) {
Logger.log(`No fields found for label ${labelId}.`);
return {};
}
const fieldMap = {};
fields.forEach(field => {
const displayName = field.properties?.displayName;
if (displayName) {
let type = 'text'; // Default
if (field.integerOptions) type = 'integer';
else if (field.dateOptions) type = 'date';
else if (field.selectionOptions) type = 'selection';
fieldMap[displayName] = {
id: field.id,
type: type
};
}
});
Logger.log(`Fetched ${fields.length} fields for label ${labelId}: ${JSON.stringify(fieldMap)}`);
return fieldMap;
} catch (error) {
Logger.log(`Error fetching fields for label ${labelId}: ${error.message}`);
return {};
}
}
// 3. Apply Label to File
function applyLabelToFile(fileId, labelId) {
try {
if (!fileId || !labelId) {
throw new Error("fileId and labelId are required.");
}
const request = {
kind: "drive#modifyLabelsRequest",
labelModifications: [
{
kind: "drive#labelModification",
labelId: labelId,
removeLabel: false
}
]
};
const response = Drive.Files.modifyLabels(request, fileId);
Logger.log(`Label ${labelId} applied to file ${fileId}: ${JSON.stringify(response.modifiedLabels)}`);
return response.modifiedLabels || [];
} catch (error) {
Logger.log(`Error applying label ${labelId} to file ${fileId}: ${error.message}`);
return [];
}
}
// 4. Apply Label and Update Fields
function applyLabelAndUpdateFields(fileId, labelId, fields) {
try {
if (!fileId || !labelId || !fields || fields.length === 0) {
throw new Error("fileId, labelId, and non-empty fields array are required.");
}
const fieldModifications = fields.map(field => {
let fieldMod = {
kind: "drive#labelFieldModification",
fieldId: field.id
};
const value = field.value;
if (!value) {
Logger.log(`Skipping field ${field.id}: No value provided.`);
return null;
}
switch (field.type) {
case 'selection':
fieldMod.setSelectionValues = [value];
break;
case 'integer':
const intVal = parseInt(value);
if (!isNaN(intVal)) {
fieldMod.setIntegerValues = [intVal.toString()];
} else {
Logger.log(`Invalid integer for field ${field.id}: ${value}`);
return null;
}
break;
case 'date':
const date = new Date(value);
if (!isNaN(date.getTime())) {
const isoDate = date.toISOString().split('T')[0];
fieldMod.setDateValues = [isoDate];
} else {
Logger.log(`Invalid date for field ${field.id}: ${value}`);
return null;
}
break;
case 'text':
default:
fieldMod.setTextValues = [value];
break;
}
return fieldMod;
}).filter(mod => mod !== null);
if (fieldModifications.length === 0) {
Logger.log('No valid field modifications; applying label only.');
return applyLabelToFile(fileId, labelId);
}
const request = {
kind: "drive#modifyLabelsRequest",
labelModifications: [
{
kind: "drive#labelModification",
labelId: labelId,
fieldModifications: fieldModifications,
removeLabel: false
}
]
};
const response = Drive.Files.modifyLabels(request, fileId);
Logger.log(`Label ${labelId} and fields applied to file ${fileId}: ${JSON.stringify(response.modifiedLabels)}`);
return response.modifiedLabels || [];
} catch (error) {
Logger.log(`Error applying label and fields to file ${fileId}: ${error.message}`);
return [];
}
}
// Full Label Automation: Chains all steps (mock suggestion/values for demo)
function fullLabelAutomation(fileId) {
try {
Logger.log(`Starting automation for file: ${fileId}`);
// Step 1: Fetch labels
const labelMap = fetchAvailableLabels();
if (Object.keys(labelMap).length === 0) {
Logger.log("No labels available. Exiting.");
return;
}
// Step 2: Mock suggestion (replace with Gemini for dynamic AI)
const suggestedLabel = "Invoice"; // Hardcoded for demo; integrate Gemini here
const labelId = labelMap[suggestedLabel];
if (!labelId) {
Logger.log(`Suggested label "${suggestedLabel}" not found. Available: ${Object.keys(labelMap).join(", ")}. Exiting.`);
return;
}
Logger.log(`Suggested and found label: ${suggestedLabel} (ID: ${labelId})`);
// Step 3: Fetch fields
const fieldMap = fetchLabelFields(labelId);
if (Object.keys(fieldMap).length === 0) {
Logger.log("No fields for label. Applying label only.");
applyLabelToFile(fileId, labelId);
return;
}
// Step 4: Build fields array with mock values (from your invoice doc; extract dynamically in prod)
const fields = Object.keys(fieldMap).map(key => ({
id: fieldMap[key].id,
type: fieldMap[key].type,
value: key === "Invoice Number" ? "100556" :
key === "Invoice Date" ? "November 28, 2025" :
key === "Vendor Name" ? "Spark Electrical Services" : "Default Value"
}));
// Apply label + fields
applyLabelAndUpdateFields(fileId, labelId, fields);
Logger.log("Automation complete! Check file labels in Drive.");
} catch (error) {
Logger.log(`Automation failed: ${error.message}`);
}
}
function runDemo() {
// Replace this with your actual File ID
const myFileId = "your_file_id";
fullLabelAutomation(myFileId);
}