Repository navigation
Expand file tree
/
Copy pathgoogle-sheets-apps-script.js
More file actions
120 lines (103 loc) · 3.36 KB
/
Copy pathgoogle-sheets-apps-script.js
File metadata and controls
120 lines (103 loc) · 3.36 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
/**
* Google Apps Script receiver for the Hidden Cost Game Google Sheets mirror.
*
* Setup:
* 1. Create a Google Sheet.
* 2. Open Extensions -> Apps Script.
* 3. Paste this file into Code.gs.
* 4. In Project Settings -> Script properties, add WEBHOOK_SECRET with the
* same value as GOOGLE_SHEETS_WEBHOOK_SECRET in your app deployment.
* 5. Deploy as a web app that can receive POST requests.
*/
const SHEET_NAME = "Submissions";
const HEADERS = [
"receivedAt",
"serverSubmissionId",
"submittedAt",
"sessionId",
"schemaVersion",
"exportVersion",
"assignedDisplayedProfile",
"assignedHiddenProfile",
"finalFinancialScore",
"finalHealthScore",
"fullTreatmentChoices",
"partialTreatmentChoices",
"skippedTreatmentChoices",
"responsibilityShift",
"constraintRecognitionShift",
"protestLegitimacyShift",
"ruleCorrectionSupportShift",
"redistributionSupportShift",
"revisionCondition",
"attemptedPreRevealRevision",
"usedRevisionOpportunity",
"revealTimingCondition",
"costVisibilityCondition",
"explanationFrameCondition",
"replayCompleted",
"replayAssignmentCondition",
"memoryDistortionMagnitude",
"rememberedPrimaryAttributionMatchesOriginal",
];
function doPost(e) {
try {
const data = parseJsonBody_(e);
const expectedSecret = PropertiesService.getScriptProperties().getProperty("WEBHOOK_SECRET");
if (!expectedSecret) {
return jsonResponse_({ ok: false, error: "WEBHOOK_SECRET script property is not configured" });
}
if (!data || data.secret !== expectedSecret) {
return jsonResponse_({ ok: false, error: "unauthorized" });
}
const sheet = getOrCreateSheet_();
ensureHeaders_(sheet);
const row = HEADERS.map((header) => normalizeCellValue_(header === "receivedAt" ? data[header] || new Date().toISOString() : data[header]));
sheet.appendRow(row);
return jsonResponse_({ ok: true });
} catch (error) {
return jsonResponse_({ ok: false, error: error && error.message ? error.message : "unknown error" });
}
}
function parseJsonBody_(e) {
const contents = e && e.postData && typeof e.postData.contents === "string" ? e.postData.contents : "";
if (!contents) {
throw new Error("empty request body");
}
try {
const parsed = JSON.parse(contents);
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
throw new Error("JSON body must be an object");
}
return parsed;
} catch (error) {
throw new Error("invalid JSON body");
}
}
function getOrCreateSheet_() {
const spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
if (!spreadsheet) {
throw new Error("no active spreadsheet found");
}
return spreadsheet.getSheetByName(SHEET_NAME) || spreadsheet.insertSheet(SHEET_NAME);
}
function ensureHeaders_(sheet) {
const firstRowValues = sheet.getRange(1, 1, 1, HEADERS.length).getValues()[0];
const isHeaderRowEmpty = firstRowValues.every((value) => value === "");
if (isHeaderRowEmpty) {
sheet.getRange(1, 1, 1, HEADERS.length).setValues([HEADERS]);
sheet.setFrozenRows(1);
}
}
function normalizeCellValue_(value) {
if (value === undefined || value === null) {
return "";
}
if (typeof value === "object") {
return JSON.stringify(value);
}
return value;
}
function jsonResponse_(body) {
return ContentService.createTextOutput(JSON.stringify(body)).setMimeType(ContentService.MimeType.JSON);
}