1
0
Fork 0
mirror of https://github.com/Luzifer/gmail-manage.git synced 2024-12-23 04:21:21 +00:00

Advance development

- Use ES6 and Babel to transpile to AppsScript
- Add filter management
- Move config to config
This commit is contained in:
Knut Ahlers 2018-10-21 01:02:53 +02:00
parent 05c5feac6a
commit 3e3cf696cd
Signed by: luzifer
GPG key ID: DC2729FDD34BE99E
9 changed files with 3024 additions and 25 deletions

4
.claspignore Normal file
View file

@ -0,0 +1,4 @@
node_modules/**
package.json
package-lock.json
src/**

3
.gitignore vendored Normal file
View file

@ -0,0 +1,3 @@
config.js
app.js
node_modules

25
Code.js
View file

@ -1,25 +0,0 @@
// Apps Scripts may only run for ~5m so we limit the execution
var MAX_DELETE_PER_LOOP = 1000
function cleanup() {
trashByQuery("label:crontab older_than:6m")
trashByQuery("label:newsletter older_than:6m")
trashByQuery("label:social-media older_than:2y")
trashByQuery("older_than:10y")
}
function trashByQuery(query) {
var threads = []
var removedThreads = 0
do {
threads = GmailApp.search(query)
for (var i = 0; i < threads.length; i++) {
var thread = threads[i]
thread.moveToTrash()
removedThreads++
}
} while (threads.length > 0 && removedThreads < MAX_DELETE_PER_LOOP)
Logger.log('Removed %s threads for query "%s"', removedThreads, query)
}

View file

@ -1,6 +1,11 @@
{ {
"timeZone": "Europe/Paris", "timeZone": "Europe/Paris",
"dependencies": { "dependencies": {
"enabledAdvancedServices": [{
"userSymbol": "Gmail",
"serviceId": "gmail",
"version": "v1"
}]
}, },
"exceptionLogging": "STACKDRIVER" "exceptionLogging": "STACKDRIVER"
} }

2834
package-lock.json generated Normal file

File diff suppressed because it is too large Load diff

16
package.json Normal file
View file

@ -0,0 +1,16 @@
{
"babel": {
"presets": [
"google-apps-script"
],
"comments": false
},
"scripts": {
"build": "babel src/*.js --out-file app.js"
},
"devDependencies": {
"@babel/cli": "^7.1.2",
"@babel/core": "^7.1.2",
"babel-preset-google-apps-script": "0.0.3"
}
}

16
src/const.js Normal file
View file

@ -0,0 +1,16 @@
// Apps Scripts may only run for ~5m so we limit the execution
var MAX_DELETE_PER_LOOP = 1000
// Label constants (these are label NAMES to be used with getOrCreateLabel)
var labelImportant = "IMPORTANT"
var labelInbox = "INBOX"
var labelSpam = "SPAM"
var labelStarred = "STARRED"
var labelTrash = "TRASH"
var labelUnread = "UNREAD"
var labelCatForums = "CATEGORY_FORUMS"
var labelCatPersonal = "CATEGORY_PERSONAL"
var labelCatPromotions = "CATEGORY_PROMOTIONS"
var labelCatSocial = "CATEGORY_SOCIAL"
var labelCatUpdates = "CATEGORY_UPDATES"

48
src/index.js Normal file
View file

@ -0,0 +1,48 @@
// executeMailCleanup takes the queries defined in config and deletes
// mails matched by those filters
function executeMailCleanup() {
for (let i = 0; i < config.cleanup_queries.length; i++) {
let query = config.cleanup_queries[i]
trashByQuery(query)
}
}
// applyFilterDefinition takes the filter definitions from the config
// matches them to the filters already defined in the Gmail account
// and afterwards applies reqired changes
function applyFilterDefinition() {
let presentFilters = getHashedFilters()
let definedFilters = {}
for (let i = 0; i < config.filters.length; i++) {
let filter = config.filters[i]
if (filter.action.add_labels) {
filter.action.addLabelIds = filter.action.add_labels.map((name) => {
return getOrCreateLabel(name).id
})
delete filter.action.add_labels
}
if (filter.action.remove_labels) {
filter.action.removeLabelIds = filter.action.remove_labels.map((name) => {
return getOrCreateLabel(name).id
})
delete filter.action.remove_labels
}
definedFilters[hashFilter(filter)] = filter
}
for (let hash in presentFilters) {
if (hash in definedFilters) continue
Gmail.Users.Settings.Filters.remove("me", presentFilters[hash].id)
Logger.log(["Removed filter", presentFilters[hash]])
}
for (let hash in definedFilters) {
if (hash in presentFilters) continue
Gmail.Users.Settings.Filters.create(definedFilters[hash], "me")
Logger.log(["Created filter", definedFilters[hash]])
}
}

98
src/lib.js Normal file
View file

@ -0,0 +1,98 @@
// getHashedFilters returns a dictionary of all present filters with
// sha256 hashes as keys
function getHashedFilters() {
let resp = Gmail.Users.Settings.Filters.list("me")
let hashedFilters = {}
for (let i = 0; i < resp.filter.length; i++) {
let filter = resp.filter[i]
hashedFilters[hashFilter(filter)] = filter
}
return hashedFilters
}
// getOrCreateLabel fetches a label by name or creates a new one if it does not exist
function getOrCreateLabel(name) {
let labels = parseCacheResponse(CacheService.getScriptCache().get("labels"))
if (labels === null) {
labels = Gmail.Users.Labels.list("me").labels
CacheService.getScriptCache().put("labels", JSON.stringify(labels), 60)
}
for (let i = 0; i < labels.length; i++) {
let label = labels[i]
if (label.name == name) {
return label
}
}
// Invalidate cache, needs to be reloaded next time
CacheService.getScriptCache().remove("labels")
return Gmail.Users.Labels.create({
labelListVisibility: "labelShow",
messageListVisibility: "show",
name: name,
}, "me")
}
// hashFilter returns a hash to the filter dictionary given for comparison
function hashFilter(filter) {
let obj = {}
if (filter.criteria.query) obj["crit.query"] = filter.criteria.query
if (filter.action.addLabelIds) obj["act.add"] = filter.action.addLabelIds.join("|")
if (filter.action.removeLabelIds) obj["act.del"] = filter.action.removeLabelIds.join("|")
return sha256sum(JSON.stringify(obj))
}
// parseCacheResponse unmarshals the JSON string from the cache if any
function parseCacheResponse(resp) {
if (resp === null) return null
return JSON.parse(resp)
}
// resolveLabelIDToName determines the name of a label to a given ID
function resolveLabelIDToName(id) {
let labels = parseCacheResponse(CacheService.getScriptCache().get("labels"))
if (labels === null) {
labels = Gmail.Users.Labels.list("me").labels
CacheService.getScriptCache().put("labels", JSON.stringify(labels), 60)
}
for (let i = 0; i < labels.length; i++) {
let label = labels[i]
if (label.id == id) {
return label.name
}
}
return null
}
// sha256sum calculates a hex digest from the input string
function sha256sum(input) {
return Utilities.computeDigest(Utilities.DigestAlgorithm.SHA_256, input)
.map((chr) => {
return (chr + 256).toString(16).slice(-2)
}).join('')
}
// trashByQuery moves messages matching a query to trash
function trashByQuery(query) {
let threads = []
let removedThreads = 0
do {
threads = GmailApp.search(query)
for (let i = 0; i < threads.length; i++) {
let thread = threads[i]
thread.moveToTrash()
removedThreads++
}
} while (threads.length > 0 && removedThreads < MAX_DELETE_PER_LOOP)
Logger.log('Removed %s threads for query "%s"', removedThreads, query)
}