-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathrepl.js
executable file
·168 lines (146 loc) · 5.23 KB
/
repl.js
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
#!/usr/bin/env node --experimental-repl-await
require('dotenv').config();
const fs = require('fs').promises;
const process = require('process');
const repl = require('repl');
const path = require('path');
const homedir = require('os').homedir();
const { type } = require('os');
const { authenticate } = require('@google-cloud/local-auth');
const { google } = require('googleapis');
const _ = require('lodash');
// If modifying these scopes, delete token.json.
const SCOPES = ['https://www.googleapis.com/auth/gmail.readonly', 'https://mail.google.com/'];
// The file token.json stores the user's access and refresh tokens, and is
// created automatically when the authorization flow completes for the first
// time.
const TOKEN_PATH = path.join(process.cwd(), 'token.json');
const CREDENTIALS_PATH = path.join(process.cwd(), 'credentials.json');
/**
* Reads previously authorized credentials from the save file.
*
* @return {Promise<OAuth2Client|null>}
*/
async function loadSavedCredentialsIfExist() {
try {
const content = await fs.readFile(TOKEN_PATH);
const credentials = JSON.parse(content);
return google.auth.fromJSON(credentials);
} catch (err) {
return null;
}
}
/**
* Serializes credentials to a file compatible with GoogleAUth.fromJSON.
*
* @param {OAuth2Client} client
* @return {Promise<void>}
*/
async function saveCredentials(client) {
const content = await fs.readFile(CREDENTIALS_PATH);
const keys = JSON.parse(content);
const key = keys.installed || keys.web;
const payload = JSON.stringify({
type: 'authorized_user',
client_id: key.client_id,
client_secret: key.client_secret,
refresh_token: client.credentials.refresh_token,
});
await fs.writeFile(TOKEN_PATH, payload);
}
/**
* Load or request or authorization to call APIs.
*
*/
async function authorize() {
let client = await loadSavedCredentialsIfExist();
if (client) {
return client;
}
client = await authenticate({
scopes: SCOPES,
keyfilePath: CREDENTIALS_PATH,
});
if (client.credentials) {
await saveCredentials(client);
}
return client;
}
async function getProfile(gmail) {
// https://developers.google.com/gmail/api/reference/rest/v1/users/getProfile
const resp = await gmail.users.getProfile({ userId: 'me'})
return resp.data
}
async function listMessages(gmail, q, params = {}) {
// https://developers.google.com/gmail/api/reference/rest/v1/users.messages/list
let pageToken = ''
const messages = []
while (typeof pageToken !== 'undefined') {
const { data } = await gmail.users.messages.list({ userId: 'me', maxResults: 500, pageToken, q, ...params })
pageToken = data.nextPageToken
if (typeof data.messages !== 'undefined' && data.messages.length > 0) {
messages.push(...data.messages)
}
}
return messages
}
async function getMessage(gmail, id, params = {}) {
// https://developers.google.com/gmail/api/reference/rest/v1/users.messages/get
const resp = await gmail.users.messages.get({ userId: 'me', id, ...params })
return resp.data
}
async function listThreads(gmail, q, params = {}) {
// https://developers.google.com/gmail/api/reference/rest/v1/users.threads/list
let pageToken = ''
const threads = []
while (typeof pageToken !== 'undefined') {
const { data } = await gmail.users.threads.list({ userId: 'me', maxResults: 500, pageToken, q, ...params })
pageToken = data.nextPageToken
if (typeof data.threads !== 'undefined' && data.threads.length > 0) {
threads.push(...data.threads)
}
}
return threads
}
async function getThread(gmail, id, params = {}) {
// https://developers.google.com/gmail/api/reference/rest/v1/users.threads/get
const resp = await gmail.users.threads.get({ userId: 'me', id, ...params })
return resp.data
}
async function batchDeleteMessages(gmail, q) {
// https://developers.google.com/gmail/api/reference/rest/v1/users.messages/batchDelete
let pageToken = ''
while (typeof pageToken !== 'undefined') {
// Get messages
const { data } = await gmail.users.messages.list({ userId: 'me', q, maxResults: 500, pageToken })
pageToken = data.nextPageToken
if (typeof data.messages !== 'undefined' && data.messages.length > 0) {
// Batch delete all of them
await gmail.users.messages.batchDelete({ userId: 'me', ids: data.messages.map(msg => msg.id) })
}
}
}
// Context initializer
const initializeContext = async (context, gmail) => {
context.gmail = gmail;
context.profile = _.partial(getProfile, gmail);
context.messages = _.partial(listMessages, gmail);
context.message = _.partial(getMessage, gmail);
context.threads = _.partial(listThreads, gmail);
context.thread = _.partial(getThread, gmail);
context.unread = _.partial(listThreads, gmail, 'is:unread');
context.bulkDeleteThreads = _.partial(batchDeleteMessages, gmail);
};
(async () => {
const auth = await authorize();
const gmail = google.gmail({version: 'v1', auth});
const profile = await getProfile(gmail);
// Start a repl
const r = repl.start(`📧 ${ profile.emailAddress } ❯ `);
// Initialize
await initializeContext(r.context, gmail);
// Listen for the reset event
r.on('reset', initializeContext);
// Initialize a history log file
r.setupHistory(path.join(homedir, '.node_repl_history'), () => {});
})();