-
-
Save AlexKorovyansky/fad23755d9244b986988 to your computer and use it in GitHub Desktop.
GAS Stuff for transformation Google Form response to Mailchimp subscriber
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
String.prototype.startsWith=function(str){return this.indexOf(str) == 0;} | |
String.prototype.trim=function(){return this.replace(/^\s\s*/, '').replace(/\s\s*$/, '');}; | |
var tag = "devfest14_registration"; | |
var spreadSheet = SpreadsheetApp.getActiveSpreadsheet(); | |
var metaSheetResponses = makeMetaSheet(spreadSheet.getSheetByName("Responses"), 2, 0); | |
var metaRowFlatRange = metaSheetResponses.getMetaRowFlatRange(1); | |
var emailPositionInDataRange = metaRowFlatRange.positionOf("EMAIL^"); | |
var invitationCodePositionInRange = metaRowFlatRange.positionOf("MERGE_INVCODE^"); | |
var invitationCodeStatusPositionInRange = metaRowFlatRange.positionOf("MERGE_INVSTAT"); | |
var responseStatusPositionInRange = metaRowFlatRange.positionOf(":STATUS"); | |
function onOpen() { | |
var menu = [ | |
{name: "Enable", functionName: "enableAutoProcessing"}, | |
{name: "Disable", functionName: "disableAutoProcessing"}, | |
{name: "Force", functionName: "autoProcessLastResponse"} | |
]; | |
SpreadsheetApp.getActive().addMenu("Auto Processing", menu); | |
var menu = [ | |
{name: "Delete All Triggers", functionName: "deleteAllTriggers"}, | |
{name: "Clear Logs", functionName: "clearLogs"} | |
]; | |
SpreadsheetApp.getActive().addMenu("Debug", menu); | |
} | |
function enableAutoProcessing() { | |
ScriptApp.newTrigger("autoProcessLastResponse") | |
.forSpreadsheet(spreadSheet) | |
.onFormSubmit() | |
.create(); | |
} | |
function disableAutoProcessing() { | |
var allTriggers = ScriptApp.getScriptTriggers(); | |
for(var i = 0; i < allTriggers.length; ++i) { | |
if (allTriggers[i].getHandlerFunction().equals("autoProcessLastResponse")) { | |
ScriptApp.deleteTrigger(allTriggers[i]); | |
} | |
} | |
} | |
function deleteAllTriggers() { | |
var allTriggers = ScriptApp.getScriptTriggers(); | |
for(var i = 0; i < allTriggers.length; ++i) { | |
ScriptApp.deleteTrigger(allTriggers[i]); | |
} | |
} | |
function autoProcessLastResponse() { | |
var timestamp = new Date().getTime(); | |
debug(tag, "[" + timestamp + "]: Starting of autoProcessLastResponse..."); | |
try { | |
validate(); | |
processResponse(-1); | |
} catch(e) { | |
metaSheetResponses.getDataRowFlatRange(-1).getRange().setBackground("#777777"); | |
metaSheetResponses.getDataRowFlatRange(-1).getCell(responseStatusPositionInRange).setValue(JSON.stringify(e)); | |
debug(tag, "EXCEPTION" + JSON.stringify(e)); | |
// TODO: send exception stacktrace to admin | |
} | |
debug(tag, "[" + timestamp + "]: Finished of autoProcessJustAddedResponse."); | |
} | |
function validate() { | |
debug(tag, "mcFieldsRange = " + metaRowFlatRange.toPrettyString()); | |
debug(tag, "emailPositionInRowsRange = " + emailPositionInDataRange); | |
debug(tag, "invitationCodePositionInRange = " + invitationCodePositionInRange); | |
debug(tag, "invitationCodeStatusPositionInRange = " + invitationCodeStatusPositionInRange); | |
debug(tag, "responseStatusPositionInRange = " + responseStatusPositionInRange); | |
// TODO: add exception if something == -1 | |
} | |
function processResponse(dataRowPosition) { | |
var newResponseRowFlatRange = metaSheetResponses.getDataRowFlatRange(dataRowPosition); | |
debug(tag, "newResponseRowFlatRange = " + newResponseRowFlatRange.toPrettyString()); | |
var newResponseEmailAsString = String(newResponseRowFlatRange.getValue(emailPositionInDataRange)); | |
debug(tag, "newResponseEmailAsString = " + newResponseEmailAsString); | |
var newResponseInvitationCodeAsString = String(newResponseRowFlatRange.getValue(invitationCodePositionInRange)); | |
debug(tag, "newResponseInvitationCodeAsString = " + newResponseInvitationCodeAsString); | |
// Trim spaces in response | |
for (var i = 0; i < metaRowFlatRange.length(); ++i) { | |
var metaRowItemAsString = String(metaRowFlatRange.getValue(i)); | |
if (metaRowItemAsString.indexOf('^') > -1) { | |
newResponseRowFlatRange.getCell(i).setValue(String(newResponseRowFlatRange.getValue(i)).trim()); | |
} | |
} | |
// Process Invitation Code | |
var newResponseInvitationCodeStatus = getStatusForInvitationCode(newResponseInvitationCodeAsString); | |
debug(tag, "newResponseInvitationCodeStatus = " + newResponseInvitationCodeStatus); | |
var newResponseInvitationCodeStatusCell = newResponseRowFlatRange.getCell(invitationCodeStatusPositionInRange); | |
if (newResponseInvitationCodeStatus == InvitationCodeStatus.NOT_PROVIDED) { | |
newResponseInvitationCodeStatusCell.setValue(""); | |
} else if (newResponseInvitationCodeStatus == InvitationCodeStatus.CORRECT) { | |
newResponseInvitationCodeStatusCell.setValue("correct"); | |
} else { | |
newResponseInvitationCodeStatusCell.setValue("wrong"); | |
} | |
// Send request to MailChimp API | |
var payload = { | |
"apikey": "apikey-us3", | |
"id": "95d64c3075", | |
"email": { | |
"email": newResponseEmailAsString | |
}, | |
"merge_vars": { | |
}, | |
"double_optin": false, | |
"send_welcome": true | |
} | |
for (var i = 0; i < metaRowFlatRange.length(); ++i) { | |
var metaRowItemAsString = String(metaRowFlatRange.getValue(i)); | |
if (metaRowItemAsString.startsWith("MERGE_")) { | |
var key = metaRowItemAsString.replace("MERGE_", "").replace("^", ""); | |
payload.merge_vars[key] = String(newResponseRowFlatRange.getValue(i)); | |
} | |
} | |
debug(tag, "request = " + JSON.stringify(payload)); | |
var options = { | |
"method" : "post", | |
"muteHttpExceptions": true, | |
"payload" : JSON.stringify(payload) | |
}; | |
var rawResponse = UrlFetchApp.fetch("https://us3.api.mailchimp.com/2.0/lists/subscribe.json", options); | |
debug(tag, "response = " + rawResponse.getResponseCode() + ": " + rawResponse.getContentText()); | |
if (rawResponse.getResponseCode() == 200 || rawResponse.getResponseCode() == 500) { | |
var response = JSON.parse(rawResponse.getContentText()); | |
if (rawResponse.getResponseCode() == 200) { | |
// success | |
newResponseRowFlatRange.getCell(responseStatusPositionInRange).setValue("SUCCESS"); | |
newResponseRowFlatRange.getRange().setBackground("#E0FFF5"); | |
if (newResponseInvitationCodeStatus == InvitationCodeStatus.CORRECT) { | |
redeemInvitationCode(newResponseInvitationCodeAsString); | |
} | |
debug(tag, "SUCCESS"); | |
} else if (rawResponse.getResponseCode() == 500) { | |
// mailchimp reject | |
newResponseRowFlatRange.getCell(responseStatusPositionInRange).setValue(response.error); | |
newResponseRowFlatRange.getRange().setBackground("#FFD6CC"); | |
debug(tag, "MailChimp Reject"); | |
} | |
} else { | |
// http error | |
newResponseRowFlatRange.getCell(responseStatusPositionInRange).setValue("HTTP ERROR " + rawResponse.getResponseCode()); | |
newResponseRowFlatRange.getRange().setBackground("#FAA5A5"); | |
debug(tag, "HTTP Error"); | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
String.prototype.trim=function(){return this.replace(/^\s\s*/, '').replace(/\s\s*$/, '');}; | |
var InvitationCodeStatus = { | |
CORRECT: 200, | |
NOT_PROVIDED: 204, | |
NOT_FOUND: 403, | |
GONE: 410, | |
}; | |
var spreadSheet = SpreadsheetApp.getActiveSpreadsheet(); | |
var metaSheetInvites = makeMetaSheet(spreadSheet.getSheetByName("Invites"), 1, 0); | |
var invitationCodePositionInDataRange = 0; | |
var inviteBalancePositionInDataRange = 1; | |
function getStatusForInvitationCode(invitationCode) { | |
if (!invitationCode) { | |
return InvitationCodeStatus.NOT_PROVIDED; | |
} | |
var invitationCodeAsString = String(invitationCode).trim(); | |
if (invitationCodeAsString.length == 0) { | |
return InvitationCodeStatus.NOT_PROVIDED; | |
} | |
var matchedInvitesFlatRows = metaSheetInvites.filterDataRows(function(flatDataRow) { | |
var flatDataRowInvitationCodeAsString = String(flatDataRow.getValue(invitationCodePositionInDataRange)); | |
return invitationCodeAsString.equals(flatDataRowInvitationCodeAsString); | |
}); | |
if (matchedInvitesFlatRows.length == 0) { | |
return InvitationCodeStatus.NOT_FOUND; | |
} else { | |
for (var i = 0; i < matchedInvitesFlatRows.length; ++i) { | |
var matchedInvitationCodeCellFlatRow = matchedInvitesFlatRows[i].getCell(inviteBalancePositionInDataRange); | |
var matchedInvitationCodeBalance = matchedInvitationCodeCellFlatRow.getValue(); | |
if (matchedInvitationCodeBalance > 0) { | |
return InvitationCodeStatus.CORRECT; | |
} | |
} | |
return InvitationCodeStatus.GONE; | |
} | |
} | |
function redeemInvitationCode(invitationCode) { | |
if (!invitationCode) { | |
return; | |
} | |
var invitationCodeAsString = String(invitationCode).trim(); | |
var matchedInvitesFlatRows = metaSheetInvites.filterDataRows(function(flatDataRow) { | |
var flatDataRowInvitationCodeAsString = String(flatDataRow.getValue(invitationCodePositionInDataRange)); | |
return invitationCodeAsString.equals(flatDataRowInvitationCodeAsString); | |
}); | |
if (matchedInvitesFlatRows.length > 0) { | |
for (var i = 0; i < matchedInvitesFlatRows.length; ++i) { | |
var matchedInvitationCodeBalanceCell = matchedInvitesFlatRows[i].getCell(inviteBalancePositionInDataRange); | |
var matchedInvitationCodeBalance = matchedInvitationCodeBalanceCell.getValue(); | |
if (matchedInvitationCodeBalance > 0) { | |
matchedInvitationCodeBalanceCell.setValue(matchedInvitationCodeBalance - 1); | |
} | |
} | |
} | |
} | |
function fooGetStatusForInvitationCode() { | |
debug("foo", getStatusForInvitationCode("c")); | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
var spreadSheet = SpreadsheetApp.getActiveSpreadsheet(); | |
var metaSheetLogs = makeMetaSheet(spreadSheet.getSheetByName("Logs"), 1, 0); | |
function debug(tag, message) { | |
log(tag, message, "debug"); | |
} | |
function info(tag, message) { | |
log(tag, message, "info"); | |
} | |
function warning(tag, message) { | |
log(tag, message, "warning"); | |
} | |
function error(tag, message) { | |
log(tag, message, "error"); | |
} | |
function log(tag, message, level){ | |
metaSheetLogs.getSheet().appendRow([new Date(), level, tag, String(message)]); | |
} | |
function clearLogs() { | |
if (metaSheetLogs.hasData()) { | |
metaSheetLogs.getDataRange(0, 0, metaSheetLogs.getDataRowsNumber(), metaSheetLogs.getDataColumnsNumber()).clear(); | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
function makeMetaSheet(sheet, metaRowsNum, metaColumnsNum) { | |
var metaSheet = { | |
sheet: sheet, | |
metaRowsNum: metaRowsNum, | |
metaColumnsNum: metaColumnsNum, | |
metaRowsRanges: [], | |
metaColumnsRanges: [], | |
getSheet: function() { | |
return this.sheet; | |
}, | |
getMetaRowsNumber: function() { | |
return this.metaNumRows; | |
}, | |
getMetaColumnsNumber: function() { | |
return this.metaNumColumns; | |
}, | |
getDataRowsNumber: function() { | |
return this.sheet.getLastRow() - this.metaRowsNum; | |
}, | |
getDataColumnsNumber: function() { | |
return this.sheet.getLastColumn() - this.metaColumnsNum; | |
}, | |
hasData: function() { | |
return this.getDataRowsNumber() > 0 && this.getDataColumnsNumber() > 0; | |
}, | |
getMetaRowFlatRange: function(index) { | |
return makeFlatRange(this.sheet.getRange(index + 1, this.metaColumnsNum + 1, 1, this.sheet.getLastColumn() - this.metaColumnsNum)); | |
}, | |
getMetaColumnFlatRange: function(index) { | |
return makeFlatRange(this.sheet.getRange(this.metaRowsNum + 1, index + 1, this.sheet.getLastRow() - this.metaRowsNum, 1)); | |
}, | |
getDataRange: function(rowOffset, columnOffset, numRows, numColumns) { | |
var startRow = this.translateRowPositionDataToAbsolute(rowOffset); | |
var startColumn = this.translateColumnPositionDataToAbsolute(columnOffset); | |
return this.sheet.getRange(startRow, startColumn, numRows, numColumns); | |
}, | |
getDataRowFlatRange: function(position) { | |
return makeFlatRange(this.getDataRange(position, 0, 1, this.getDataColumnsNumber())); | |
}, | |
getDataColumnFlatRange: function(position) { | |
return makeFlatRange(this.getDataRange(0, position, this.getDataRowsNumber(), 1)); | |
}, | |
filterDataRows: function(filter) { | |
var ranges = []; | |
for (i = 0; i < this.getDataRowsNumber(); ++i) { | |
var flatDataRow = this.getDataRowFlatRange(i); | |
if (filter(flatDataRow)) { | |
ranges.push(flatDataRow); | |
} | |
} | |
return ranges; | |
}, | |
translateRowPositionDataToAbsolute: function(position) { | |
return position >= 0 ? (this.metaRowsNum + position + 1) : (this.sheet.getLastRow() + position + 1); | |
}, | |
translateColumnPositionDataToAbsolute: function(position) { | |
return position >= 0 ? (this.metaColumnsNum + position + 1) : (this.sheet.getLastColumn() + position + 1); | |
}, | |
// TODO: | |
toPrettyString: function() { | |
} | |
} | |
return metaSheet; | |
} | |
function makeFlatRange(range) { | |
var isRow = false; | |
if (range.getWidth() == 1 && range.getHeight() >= 1) { | |
isRow = false; | |
} else if (range.getHeight() == 1 && range.getWidth() >= 1) { | |
isRow = true; | |
} else { | |
throw "Impossible to flattern data range, width:" + range.getWidth() + ", height:" + range.getHeight(); | |
} | |
return { | |
getRange: function() { | |
return range; | |
}, | |
getValue: function(position) { | |
if (isRow) { | |
return range.getValues()[0][position] | |
} else { | |
return range.getValues()[position][0]; | |
} | |
}, | |
getCell: function(position) { | |
if (isRow) { | |
return range.offset(0, position, 1, 1); | |
} else { | |
return range.offset(position, 0, 1, 1); | |
} | |
}, | |
positionOf: function(data) { | |
for (var i = 0; i < this.length(); ++i) { | |
var item = this.getValue(i); | |
if (item.equals(data)) { | |
return i; | |
} | |
} | |
return -1; | |
}, | |
toPrettyString: function() { | |
var result = []; | |
for (var i = 0; i < this.length(); ++i) { | |
if (i > 0) { | |
result.push(", "); | |
} | |
result.push(this.getValue(i)); | |
} | |
return result.join(""); | |
}, | |
length: function() { | |
if (isRow) { | |
return range.getWidth(); | |
} else { | |
return range.getHeight(); | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment