Skip to content

Commit f3fcf62

Browse files
committed
Google Drive Watch πŸ•΅πŸ»β€β™‚οΈ
1 parent 7cb7563 commit f3fcf62

File tree

3 files changed

+134
-0
lines changed

3 files changed

+134
-0
lines changed
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# Google Drive File Watch 🐒
2+
3+
[Monitor Deleted Files in Google Drive](https://www.labnol.org/google-drive-monitor-201026)
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
{
2+
"timeZone": "Asia/Kolkata",
3+
"dependencies": {
4+
"enabledAdvancedServices": [
5+
{
6+
"userSymbol": "Drive",
7+
"serviceId": "drive",
8+
"version": "v2"
9+
}
10+
]
11+
},
12+
"exceptionLogging": "STACKDRIVER",
13+
"oauthScopes": [
14+
"https://www.googleapis.com/auth/drive.metadata.readonly",
15+
"https://www.googleapis.com/auth/script.send_mail"
16+
],
17+
"runtimeVersion": "V8"
18+
}
Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
/**
2+
* Watch Google Drive Files
3+
* Author: amit@labnol.org
4+
* Web: https://digitalinspiration.com/
5+
* MIT License
6+
* */
7+
8+
// Enter the email address for email notification
9+
const EMAIL = "amit@labnol.org";
10+
11+
// How frequently should the watcher run? Put 2 for running every 2 days.
12+
const RUNNING_FREQUENCY = 1;
13+
14+
// At what hour of the day should the script run?
15+
const RUN_AT_HOUR = 10;
16+
17+
const enableDriveWatch = () => {
18+
const triggerName = "watchGoogleDrive";
19+
const [trigger = null] = ScriptApp.getProjectTriggers().filter((t) => t.getHandlerFunction() === triggerName);
20+
if (trigger === null) {
21+
ScriptApp.newTrigger(triggerName).timeBased().everyDays(1).atHour(RUN_AT_HOUR).create();
22+
}
23+
};
24+
25+
const disableDriveWatch = () => {
26+
ScriptApp.getProjectTriggers().map((trigger) => {
27+
ScriptApp.deleteTrigger(trigger);
28+
});
29+
};
30+
31+
const checkChangedFiles_ = (items) => {
32+
const cacheStore = CacheService.getScriptCache();
33+
const processed = (cacheStore.get("cache") || "").split(",");
34+
cacheStore.put("cache", items.map(({ id }) => id).join(","), 21600);
35+
return items
36+
.map(({ file }) => file)
37+
.filter(({ id, alternateLink, title }) => id && alternateLink && title)
38+
.filter(({ ownedByMe }) => ownedByMe)
39+
.filter(({ id }) => processed.indexOf(id) === -1)
40+
.filter(({ labels: { trashed = null } = {} }) => trashed === true)
41+
.map((file) => {
42+
const {
43+
iconLink = "",
44+
alternateLink = "",
45+
title = "",
46+
lastModifyingUser = {},
47+
createdDate = "",
48+
fileSize = "",
49+
} = file;
50+
51+
const { emailAddress = "", displayName = "", picture: { url = "" } = {} } = lastModifyingUser;
52+
const fileDate = createdDate ? Utilities.formatDate(new Date(createdDate), "IST", "MMMMM dd, YYYY") : "";
53+
54+
return [
55+
iconLink ? `<img src="${iconLink}" height=16 />` : "",
56+
`<a href="${alternateLink}">${title}</a>`,
57+
fileSize ? `(${Math.round(fileSize / 1000)} Kb)` : "",
58+
fileDate ? `Created: ${fileDate}` : "",
59+
`${displayName || emailAddress}`,
60+
url ? `<img src="${url}" height=16 />` : "",
61+
];
62+
});
63+
};
64+
65+
const sendEmail_ = (rows = []) => {
66+
const { length } = rows;
67+
if (length === 0) return;
68+
69+
const html = [
70+
`<table border="0" cellpadding="8" cellspacing="4" style="font-size:12px">`,
71+
rows
72+
.map((row) => row.map((td) => `<td>${td}</td>`).join(""))
73+
.map((tr) => `<tr>${tr}</tr>`)
74+
.join(""),
75+
`</table>`,
76+
`<p style="background:#ffffe0; padding:12px;font-size:12px;display:inline-block">`,
77+
`<a href="https://www.labnol.org/google-drive-monitor-201026">Drive Watch</a> is developed by`,
78+
` <a href="https://digitalinspiration.com/">Digital Inspiration</a></p>`,
79+
];
80+
MailApp.sendEmail({
81+
to: EMAIL,
82+
name: "Drive Watch",
83+
subject: `[Drive Watch] ${rows.length} files were deleted in your Google Drive`,
84+
htmlBody: html.join(""),
85+
});
86+
};
87+
88+
const watchGoogleDrive = () => {
89+
const propertyStore = PropertiesService.getScriptProperties();
90+
91+
const pageToken =
92+
propertyStore.getProperty("token") || Drive.Changes.getStartPageToken({ supportsAllDrives: true }).startPageToken;
93+
94+
const fields =
95+
"newStartPageToken,items(file(id,title,labels(trashed),iconLink,mimeType,createdDate,ownedByMe,lastModifyingUser(emailAddress,displayName,picture(url)),alternateLink, fileSize))";
96+
97+
const { newStartPageToken, items = [] } = Drive.Changes.list({
98+
fields,
99+
pageToken,
100+
includeItemsFromAllDrives: true,
101+
pageSize: 100,
102+
supportsAllDrives: true,
103+
});
104+
105+
if (newStartPageToken) {
106+
propertyStore.setProperty("token", newStartPageToken);
107+
}
108+
109+
if (items.length) {
110+
const deletedItems = checkChangedFiles_(items);
111+
sendEmail_(deletedItems);
112+
}
113+
};

0 commit comments

Comments
Β (0)