-
Notifications
You must be signed in to change notification settings - Fork 0
/
server.gs
199 lines (170 loc) · 6.82 KB
/
server.gs
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
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
/*
* Maine Campus Crush
*
* A Bejewled clone for public higher education in Maine.
* Client based on http://www.emanueleferonato.com/2011/10/07/complete-bejeweled-prototype-made-wiht-jquery/
* Server based on https://mashe.hawksey.info/2014/07/google-sheets-as-a-database-insert-with-apps-script-using-postget-methods-with-ajax-example/
*
* February 1, 2015 - Stephen Houser
*
* Copyright (C) 2015 Stephen Houser
* This work is licensed inder a Creative Commons Attribution-Noncommercial-Share
* Alike 3.0 United States License (CC BY-NC-SA 3.0 US)
* http://creativecommons.org/licenses/by-nc-sa/3.0/us/
* ----------------------------------------------------------------------------
* "THE BEER-WARE LICENSE" (Revision 42):
* As long as you retain this notice you can do whatever you want with this stuff.
* If we meet some day, and you think this stuff is worth it, you can buy me a beer
* in return.
* ----------------------------------------------------------------------------
*/
/*
* Code.gs -- Google Script API for Score tracking
* Handles posting scores from Maine Campus Crush game to google spreadsheet.
* Return high scores for each team
* JSONP based to allow cross domain functionality.
* ** This script is "bound" to the containing Google Spreadsheet! **
* https://developers.google.com/apps-script/guides/bound
*/
// Name of the sheets to modify and get data from
var scoreSheetName = "All Scores";
var leaderboardSheetName = "Leaderboard";
// LEADERBOARD Columns
// Columns are: 0-Date, 1-Score, 2-Team, 3-Player, 4-Campus, 5-Mascot, 6-Notes
var colDate = 0,
colScore = 1,
colTeam = 2,
colPlayer = 3,
colCampus = 4,
colMascot = 5,
colNotes = 6;
// Google property service
var scriptProperties = PropertiesService.getScriptProperties();
function setup() {
var doc = SpreadsheetApp.getActiveSpreadsheet();
scriptProperties.setProperty("key", doc.getId());
}
function doGet(request) {
return handleResponse(request);
}
function doPost(request) {
return handleResponse(request);
}
function JSONPify(callbackName, data) {
return callbackName + "(" + JSON.stringify(data) + ")";
}
function isInt(number) {
return (typeof number==="number" && (number%1)===0);
}
function handleResponse(request) {
// Set callback function for JSONP results
var callbackFunctionName = "callback";
if (request.parameters.callback) {
callbackFunctionName = request.parameters.callback;
}
// The LockService[1] prevents concurrent access overwritting data.
// [1] http://googleappsdeveloper.blogspot.co.uk/2011/10/concurrency-and-google-apps-script.html
// we want a public lock, one that locks for all invocations
var lock = LockService.getPublicLock();
lock.waitLock(10000); // wait 10 seconds before conceding defeat.
try {
// Set where we write the data
var doc = SpreadsheetApp.openById(scriptProperties.getProperty("key"));
// ===== RECORD SCORE =====
// If a score is provided, then add to the score log
var score = parseInt(request.parameter.score, 10);
if (isInt(score)) {
var scoreSheet = doc.getSheetByName(scoreSheetName);
// Optional team number
var team = parseInt(request.parameter.team, 10);
if (!isInt(team)) {
team = 0;
}
// Optional player name (initials)
var player = request.parameter.player;
if (!player) {
player = "";
}
// Header is in row 1
var headRow = request.parameter.header_row || 1;
var headers = scoreSheet.getRange(1, 1, 1, scoreSheet.getLastColumn()).getValues()[0];
// The row we will post the submitted score
var nextRow = scoreSheet.getLastRow() + 1; // get next row
// Populate the new row data from the request
var row = [];
for (i in headers) { // loop through the header columns
if (headers[i] == "date") { // special case if you include a 'Timestamp' column
row.push(new Date());
} else if (request.parameter[headers[i]]) {
// else use header name to get data
row.push(request.parameter[headers[i]]);
} else {
row.push('');
}
}
// Set the new row values.
// more efficient to set values as [][] array than individually
//scoreSheet.getRange(nextRow, 1, 1, row.length).setValues([row]);
// Insert as topmost row...
// Insert before row 2 so style comes from row 2 and not header
// which would happen if you insertRowAfter(1)
scoreSheet.insertRowBefore(2);
scoreSheet.getRange(2, 1, 1, row.length).setValues([row]);
}
// ===== LEADERBOARD =====
var leaderboardSheet = doc.getSheetByName(leaderboardSheetName);
var leaderboardRange = leaderboardSheet.getRange(2, 1, leaderboardSheet.getLastRow(), leaderboardSheet.getLastColumn());
var leaderboardValues = leaderboardRange.getValues();
// ===== UPDATE LEADERBOARD =====
// If score was provided, update the leaderboard... if qualifies!
if (isInt(score)) {
// Loop through all teams finding a match. Undeclared folks get team=0 above
for (var row in leaderboardValues) {
var highTeam = leaderboardValues[row][colTeam]
if (highTeam == team) { // found my team
if (score > leaderboardValues[row][colScore]) { // new high score!
// update in-memory data
leaderboardValues[row][colDate] = new Date();
leaderboardValues[row][colScore] = score;
leaderboardValues[row][colPlayer] = player;
leaderboardRange.setValues(leaderboardValues);
break;
}
}
}
}
// ===== RETURN LEADERBOARD =====
var leaderboard = {};
for (var row in leaderboardValues) {
if (isInt(leaderboardValues[row][colTeam])) {
leaderboard[leaderboardValues[row][colTeam]] = {
"date" : leaderboardValues[row][colDate],
"score" : leaderboardValues[row][colScore],
"player": leaderboardValues[row][colPlayer],
"campus": leaderboardValues[row][colCampus],
"mascot": leaderboardValues[row][colMascot]
};
}
}
var results = JSONPify(callbackFunctionName, {
"result" : "success",
"parameters" : request.parameters,
"scores" : nextRow,
"leaderboard": leaderboard
});
return ContentService
.createTextOutput(results)
.setMimeType(ContentService.MimeType.JAVASCRIPT);
} catch(error) {
var results = JSONPify(callbackFunctionName, {
"result": "error",
"error" : error
});
return ContentService
.createTextOutput(results)
.setMimeType(ContentService.MimeType.JAVASCRIPT);
} finally {
//release lock
lock.releaseLock();
}
}